Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

puppeteer

Package Overview
Dependencies
Maintainers
3
Versions
916
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

puppeteer - npm Package Compare versions

Comparing version 0.13.0 to 1.0.0-next.1514510476874

lib/Downloader.js

2

.eslintrc.js

@@ -74,3 +74,3 @@ module.exports = {

"valid-typeof": 2,
"no-unused-vars": [2, { "args": "none", "vars": "local" }],
"no-unused-vars": [2, { "args": "none", "vars": "local", "varsIgnorePattern": "([fx]?describe|[fx]?it|beforeAll|beforeEach|afterAll|afterEach)" }],
"no-implicit-globals": [2],

@@ -77,0 +77,0 @@

@@ -66,3 +66,3 @@ # How to Contribute

- `style` - puppeteer code style: spaces/alignment/wrapping etc
- `chore` - build-related work, e.g. doclint changes / travis / appveyour
- `chore` - build-related work, e.g. doclint changes / travis / appveyor
1. *namespace* is put in parenthesis after label and is optional

@@ -115,3 +115,4 @@ 2. *title* is a brief summary of changes

Puppeteer tests are located in [test/test.js](https://github.com/GoogleChrome/puppeteer/blob/master/test/test.js)
and are written using [Jasmine](https://jasmine.github.io/) testing framework. Despite being named 'unit', these are integration tests, making sure public API methods and events work as expected.
and are written with a [TestRunner](https://github.com/GoogleChrome/puppeteer/tree/master/utils/testrunner) framework.
Despite being named 'unit', these are integration tests, making sure public API methods and events work as expected.

@@ -118,0 +119,0 @@ - To run all tests:

@@ -331,2 +331,26 @@ /**

{
'name': 'iPhone X',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 375,
'height': 812,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone X landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 812,
'height': 375,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Kindle Fire HDX',

@@ -333,0 +357,0 @@ 'userAgent': 'Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true',

@@ -27,3 +27,3 @@ /**

page.on('request', request => {
if (request.resourceType === 'image')
if (request.resourceType() === 'image')
request.abort();

@@ -30,0 +30,0 @@ else

@@ -14,3 +14,3 @@ # Running the examples

By default, Puppeteer disables extensions when launching Chrome. You can load a specific
extension using:
extension using:

@@ -35,2 +35,3 @@ ```js

- [pupperender](https://github.com/LasaleFamine/pupperender) - Express middleware that checks the User-Agent header of incoming requests, and if it matches one of a configurable set of bots, render the page using Puppeteer. Useful for PWA rendering.
- [headless-chrome-crawler](https://github.com/yujiosaka/headless-chrome-crawler) - Crawler that provides simple APIs to manipulate Headless Chrome and allows you to crawl dynamic websites.

@@ -37,0 +38,0 @@ ## Testing

@@ -17,2 +17,7 @@ /**

/**
* @fileoverview Search developers.google.com/web for articles tagged
* "Headless Chrome" and scrape results from the results page.
*/
'use strict';

@@ -26,21 +31,29 @@

const page = await browser.newPage();
await page.goto('https://google.com', {waitUntil: 'networkidle2'});
await page.waitFor('input[name=q]');
// Type our query into the search bar
await page.type('input[name=q]', 'puppeteer');
await page.goto('https://developers.google.com/web/');
await page.click('input[type="submit"]');
// Type into search box.
await page.type('#searchbox input', 'Headless Chrome');
// Wait for the results to show up
await page.waitForSelector('h3 a');
// Wait for suggest overlay to appear and click "show all results".
const allResultsSelector = '.devsite-suggest-all-results';
await page.waitForSelector(allResultsSelector);
await page.click(allResultsSelector);
// Extract the results from the page
const links = await page.evaluate(() => {
const anchors = Array.from(document.querySelectorAll('h3 a'));
return anchors.map(anchor => anchor.textContent);
});
// Wait for the results page to load and display the results.
const resultsSelector = '.gsc-results .gsc-thumbnail-inside a.gs-title';
await page.waitForSelector(resultsSelector);
// Extract the results from the page.
const links = await page.evaluate(resultsSelector => {
const anchors = Array.from(document.querySelectorAll(resultsSelector));
return anchors.map(anchor => {
const title = anchor.textContent.split('|')[0].trim();
return `${title} - ${anchor.href}`;
});
}, resultsSelector);
console.log(links.join('\n'));
await browser.close();
})();

@@ -17,10 +17,13 @@ /**

// If node does not support async await, use the compiled version.
let folder = 'lib';
let asyncawait = true;
try {
new Function('async function test(){await 1}');
} catch (error) {
folder = 'node6';
asyncawait = false;
}
module.exports = require(`./${folder}/Puppeteer`);
// If node does not support async await, use the compiled version.
if (asyncawait)
module.exports = require('./lib/Puppeteer');
else
module.exports = require('./node6/lib/Puppeteer');

@@ -17,2 +17,4 @@ /**

buildNode6IfNecessary();
if (process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD) {

@@ -27,8 +29,10 @@ console.log('**INFO** Skipping Chromium download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" environment variable was found.');

const Downloader = require('./utils/ChromiumDownloader');
const platform = Downloader.currentPlatform();
const revision = require('./package').puppeteer.chromium_revision;
const Downloader = require('./lib/Downloader');
const downloader = Downloader.createDefault();
const platform = downloader.currentPlatform();
const revision = Downloader.defaultRevision();
const ProgressBar = require('progress');
const revisionInfo = Downloader.revisionInfo(platform, revision);
const revisionInfo = downloader.revisionInfo(platform, revision);
// Do nothing if the revision is already downloaded.

@@ -50,5 +54,7 @@ if (revisionInfo.downloaded)

const allRevisions = Downloader.downloadedRevisions();
const DOWNLOAD_HOST = process.env.PUPPETEER_DOWNLOAD_HOST || process.env.npm_config_puppeteer_download_host;
Downloader.downloadRevision(platform, revision, DOWNLOAD_HOST, onProgress)
const allRevisions = downloader.downloadedRevisions();
const downloadHost = process.env.PUPPETEER_DOWNLOAD_HOST || process.env.npm_config_puppeteer_download_host;
if (downloadHost)
downloader.setDownloadHost(downloadHost);
downloader.downloadRevision(platform, revision, onProgress)
.then(onSuccess)

@@ -63,3 +69,3 @@ .catch(onError);

// Remove previous chromium revisions.
const cleanupOldVersions = allRevisions.map(({platform, revision}) => Downloader.removeRevision(platform, revision));
const cleanupOldVersions = allRevisions.map(({platform, revision}) => downloader.removeRevision(platform, revision));
return Promise.all(cleanupOldVersions);

@@ -95,1 +101,22 @@ }

function buildNode6IfNecessary() {
const fs = require('fs');
const path = require('path');
// if this package is installed from NPM, then it already has up-to-date node6
// folder.
if (!fs.existsSync(path.join('utils', 'node6-transform')))
return;
let asyncawait = true;
try {
new Function('async function test(){await 1}');
} catch (error) {
asyncawait = false;
}
// if async/await is supported, then node6 is not needed.
if (asyncawait)
return;
// Re-build node6/ folder.
console.log('Building Puppeteer for Node 6');
require(path.join(__dirname, 'utils', 'node6-transform'));
}

@@ -25,8 +25,10 @@ /**

* @param {!Object=} options
* @param {?Puppeteer.ChildProcess} process
* @param {(function():Promise)=} closeCallback
*/
constructor(connection, options = {}, closeCallback) {
constructor(connection, options = {}, process, closeCallback) {
super();
this._ignoreHTTPSErrors = !!options.ignoreHTTPSErrors;
this._appMode = !!options.appMode;
this._process = process;
this._screenshotTaskQueue = new TaskQueue();

@@ -46,8 +48,16 @@ this._connection = connection;

/**
* @return {?Puppeteer.ChildProcess}
*/
process() {
return this._process;
}
/**
* @param {!Puppeteer.Connection} connection
* @param {boolean} ignoreHTTPSErrors
* @param {!Object=} options
* @param {?Puppeteer.ChildProcess} process
* @param {function()=} closeCallback
*/
static async create(connection, ignoreHTTPSErrors, closeCallback) {
const browser = new Browser(connection, ignoreHTTPSErrors, closeCallback);
static async create(connection, options, process, closeCallback) {
const browser = new Browser(connection, options, process, closeCallback);
await connection.send('Target.setDiscoverTargets', {discover: true});

@@ -54,0 +64,0 @@ return browser;

@@ -45,3 +45,3 @@ /**

this._lastId = 0;
/** @type {!Map<number, {resolve: function, reject: function, method: string}>}*/
/** @type {!Map<number, {resolve: function, reject: function, error: !Error, method: string}>}*/
this._callbacks = new Map();

@@ -75,3 +75,3 @@ this._delay = delay;

return new Promise((resolve, reject) => {
this._callbacks.set(id, {resolve, reject, method});
this._callbacks.set(id, {resolve, reject, error: new Error(), method});
});

@@ -99,3 +99,3 @@ }

if (object.error)
callback.reject(new Error(`Protocol error (${callback.method}): ${object.error.message} ${object.error.data}`));
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): ${object.error.message} ${object.error.data}`));
else

@@ -127,3 +127,3 @@ callback.resolve(object.result);

for (const callback of this._callbacks.values())
callback.reject(new Error(`Protocol error (${callback.method}): Target closed.`));
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
this._callbacks.clear();

@@ -161,3 +161,3 @@ for (const session of this._sessions.values())

this._lastId = 0;
/** @type {!Map<number, {resolve: function, reject: function, method: string}>}*/
/** @type {!Map<number, {resolve: function, reject: function, error: !Error, method: string}>}*/
this._callbacks = new Map();

@@ -193,6 +193,6 @@ this._connection = connection;

this._callbacks.delete(id);
callback.reject(e);
callback.reject(rewriteError(callback.error, e && e.message));
});
return new Promise((resolve, reject) => {
this._callbacks.set(id, {resolve, reject, method});
this._callbacks.set(id, {resolve, reject, error: new Error(), method});
});

@@ -211,3 +211,3 @@ }

if (object.error)
callback.reject(new Error(`Protocol error (${callback.method}): ${object.error.message} ${object.error.data}`));
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): ${object.error.message} ${object.error.data}`));
else

@@ -228,3 +228,3 @@ callback.resolve(object.result);

for (const callback of this._callbacks.values())
callback.reject(new Error(`Protocol error (${callback.method}): Target closed.`));
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
this._callbacks.clear();

@@ -235,2 +235,12 @@ this._connection = null;

/**
* @param {!Error} error
* @param {string} message
* @return {!Error}
*/
function rewriteError(error, message) {
error.message = message;
return error;
}
module.exports = {Connection, Session};

@@ -28,3 +28,3 @@ /**

this._client = client;
this.type = type;
this._type = type;
this._message = message;

@@ -38,2 +38,9 @@ this._handled = false;

*/
type() {
return this._type;
}
/**
* @return {string}
*/
message() {

@@ -40,0 +47,0 @@ return this._message;

@@ -195,2 +195,21 @@ /**

}
/**
* @param {string} expression
* @return {!Promise<?ElementHandle>}
*/
async xpath(expression) {
const handle = await this.executionContext().evaluateHandle(
(element, expression) => {
const document = element.ownerDocument || element;
return document.evaluate(expression, element, null, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
},
this, expression
);
const element = handle.asElement();
if (element)
return element;
await handle.dispose();
return null;
}
}

@@ -197,0 +216,0 @@

@@ -22,8 +22,12 @@ /**

* @param {!Puppeteer.Session} client
* @param {string} contextId
* @param {!Object} contextPayload
* @param {function(*):!JSHandle} objectHandleFactory
*/
constructor(client, contextId, objectHandleFactory) {
constructor(client, contextPayload, objectHandleFactory) {
this._client = client;
this._contextId = contextId;
this._contextId = contextPayload.id;
const auxData = contextPayload.auxData || {isDefault: true};
this._frameId = auxData.frameId || null;
this._isDefault = !!auxData.isDefault;
this._objectHandleFactory = objectHandleFactory;

@@ -33,3 +37,3 @@ }

/**
* @param {function(*)|string} pageFunction
* @param {Function|string} pageFunction
* @param {...*} args

@@ -46,3 +50,3 @@ * @return {!Promise<(!Object|undefined)>}

/**
* @param {function(*)|string} pageFunction
* @param {Function|string} pageFunction
* @param {...*} args

@@ -49,0 +53,0 @@ * @return {!Promise<!JSHandle>}

@@ -44,2 +44,4 @@ /**

this._client.on('Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context));
this._client.on('Runtime.executionContextDestroyed', event => this._onExecutionContextDestroyed(event.executionContextId));
this._client.on('Runtime.executionContextsCleared', event => this._onExecutionContextsCleared());
this._client.on('Page.lifecycleEvent', event => this._onLifecycleEvent(event));

@@ -148,16 +150,34 @@

_onExecutionContextCreated(contextPayload) {
const context = new ExecutionContext(this._client, contextPayload.id, this.createJSHandle.bind(this, contextPayload.id));
const context = new ExecutionContext(this._client, contextPayload, this.createJSHandle.bind(this, contextPayload.id));
this._contextIdToContext.set(contextPayload.id, context);
const frameId = contextPayload.auxData && contextPayload.auxData.isDefault ? contextPayload.auxData.frameId : null;
const frame = this._frames.get(frameId);
if (!frame)
const frame = context._frameId ? this._frames.get(context._frameId) : null;
if (frame && context._isDefault)
frame._setDefaultContext(context);
}
/**
* @param {!ExecutionContext} context
*/
_removeContext(context) {
const frame = context._frameId ? this._frames.get(context._frameId) : null;
if (frame && context._isDefault)
frame._setDefaultContext(null);
}
/**
* @param {string} executionContextId
*/
_onExecutionContextDestroyed(executionContextId) {
const context = this._contextIdToContext.get(executionContextId);
if (!context)
return;
frame._context = context;
for (const waitTask of frame._waitTasks)
waitTask.rerun();
this._contextIdToContext.delete(executionContextId);
this._removeContext(context);
}
_onExecutionContextDestroyed(contextPayload) {
this._contextIdToContext.delete(contextPayload.id);
_onExecutionContextsCleared() {
for (const context of this._contextIdToContext.values())
this._removeContext(context);
this._contextIdToContext.clear();
}

@@ -213,3 +233,10 @@

this._id = frameId;
this._context = null;
/** @type {?Promise<!ElementHandle>} */
this._documentPromise = null;
/** @type {?Promise<!ExecutionContext>} */
this._contextPromise = null;
this._contextResolveCallback = null;
this._setDefaultContext(null);
/** @type {!Set<!WaitTask>} */

@@ -228,6 +255,23 @@ this._waitTasks = new Set();

/**
* @return {!ExecutionContext}
* @param {?ExecutionContext} context
*/
_setDefaultContext(context) {
if (context) {
this._contextResolveCallback.call(null, context);
this._contextResolveCallback = null;
for (const waitTask of this._waitTasks)
waitTask.rerun();
} else {
this._documentPromise = null;
this._contextPromise = new Promise(fulfill => {
this._contextResolveCallback = fulfill;
});
}
}
/**
* @return {!Promise<!ExecutionContext>}
*/
executionContext() {
return this._context;
return this._contextPromise;
}

@@ -241,3 +285,4 @@

async evaluate(pageFunction, ...args) {
return this._context.evaluate(pageFunction, ...args);
const context = await this._contextPromise;
return context.evaluate(pageFunction, ...args);
}

@@ -250,11 +295,31 @@

async $(selector) {
const handle = await this._context.evaluateHandle(selector => document.querySelector(selector), selector);
const element = handle.asElement();
if (element)
return element;
await handle.dispose();
return null;
const document = await this._document();
const value = await document.$(selector);
return value;
}
/**
* @return {!Promise<!ElementHandle>}
*/
async _document() {
if (this._documentPromise)
return this._documentPromise;
this._documentPromise = this._contextPromise.then(async context => {
const document = await context.evaluateHandle('document');
return document.asElement();
});
return this._documentPromise;
}
/**
* @param {string} expression
* @return {!Promise<?ElementHandle>}
*/
async xpath(expression) {
const document = await this._document();
const value = await document.xpath(expression);
return value;
}
/**
* @param {string} selector

@@ -281,3 +346,4 @@ * @param {Function|string} pageFunction

async $$eval(selector, pageFunction, ...args) {
const arrayHandle = await this._context.evaluateHandle(selector => Array.from(document.querySelectorAll(selector)), selector);
const context = await this._contextPromise;
const arrayHandle = await context.evaluateHandle(selector => Array.from(document.querySelectorAll(selector)), selector);
const result = await this.evaluate(pageFunction, arrayHandle, ...args);

@@ -293,15 +359,33 @@ await arrayHandle.dispose();

async $$(selector) {
const arrayHandle = await this._context.evaluateHandle(selector => document.querySelectorAll(selector), selector);
const properties = await arrayHandle.getProperties();
await arrayHandle.dispose();
const result = [];
for (const property of properties.values()) {
const elementHandle = property.asElement();
if (elementHandle)
result.push(elementHandle);
}
return result;
const document = await this._document();
const value = await document.$$(selector);
return value;
}
/**
* @return {!Promise<String>}
*/
async content() {
return await this.evaluate(() => {
let retVal = '';
if (document.doctype)
retVal = new XMLSerializer().serializeToString(document.doctype);
if (document.documentElement)
retVal += document.documentElement.outerHTML;
return retVal;
});
}
/**
* @param {string} html
*/
async setContent(html) {
await this.evaluate(html => {
document.open();
document.write(html);
document.close();
}, html);
}
/**
* @return {string}

@@ -349,3 +433,4 @@ */

try {
return await this._context.evaluateHandle(addScriptUrl, url);
const context = await this._contextPromise;
return (await context.evaluateHandle(addScriptUrl, url)).asElement();
} catch (error) {

@@ -359,9 +444,11 @@ throw new Error(`Loading script from ${url} failed`);

contents += '//# sourceURL=' + options.path.replace(/\n/g, '');
const context = await this._contextPromise;
return (await context.evaluateHandle(addScriptContent, contents)).asElement();
}
return this._context.evaluateHandle(addScriptContent, contents);
if (typeof options.content === 'string') {
const context = await this._contextPromise;
return (await context.evaluateHandle(addScriptContent, options.content)).asElement();
}
if (typeof options.content === 'string')
return this._context.evaluateHandle(addScriptContent, options.content);
throw new Error('Provide an object with a `url`, `path` or `content` property');

@@ -405,3 +492,4 @@

try {
return await this._context.evaluateHandle(addStyleUrl, url);
const context = await this._contextPromise;
return (await context.evaluateHandle(addStyleUrl, url)).asElement();
} catch (error) {

@@ -415,9 +503,11 @@ throw new Error(`Loading style from ${url} failed`);

contents += '/*# sourceURL=' + options.path.replace(/\n/g, '') + '*/';
const context = await this._contextPromise;
return (await context.evaluateHandle(addStyleContent, contents)).asElement();
}
return await this._context.evaluateHandle(addStyleContent, contents);
if (typeof options.content === 'string') {
const context = await this._contextPromise;
return (await context.evaluateHandle(addStyleContent, options.content)).asElement();
}
if (typeof options.content === 'string')
return await this._context.evaluateHandle(addStyleContent, options.content);
throw new Error('Provide an object with a `url`, `path` or `content` property');

@@ -424,0 +514,0 @@

@@ -20,3 +20,3 @@ /**

const childProcess = require('child_process');
const Downloader = require('../utils/ChromiumDownloader');
const Downloader = require('./Downloader');
const {Connection} = require('./Connection');

@@ -27,4 +27,3 @@ const {Browser} = require('./Browser');

const {helper} = require('./helper');
// @ts-ignore
const ChromiumRevision = require('../package.json').puppeteer.chromium_revision;
const ChromiumRevision = Downloader.defaultRevision();

@@ -67,6 +66,9 @@ const mkdtempAsync = helper.promisify(fs.mkdtemp);

let temporaryUserDataDir = null;
const chromeArguments = [].concat(DEFAULT_ARGS);
const chromeArguments = [];
if (!options.ignoreDefaultArgs)
chromeArguments.push(...DEFAULT_ARGS);
if (options.appMode)
options.headless = false;
else
else if (!options.ignoreDefaultArgs)
chromeArguments.push(...AUTOMATION_ARGS);

@@ -94,3 +96,4 @@

if (typeof chromeExecutable !== 'string') {
const revisionInfo = Downloader.revisionInfo(Downloader.currentPlatform(), ChromiumRevision);
const downloader = Downloader.createDefault();
const revisionInfo = downloader.revisionInfo(downloader.currentPlatform(), ChromiumRevision);
console.assert(revisionInfo.downloaded, `Chromium revision is not downloaded. Run "npm install"`);

@@ -133,2 +136,6 @@ chromeExecutable = revisionInfo.executablePath;

listeners.push(helper.addEventListener(process, 'SIGINT', forceKillChrome));
if (options.handleSIGTERM !== false)
listeners.push(helper.addEventListener(process, 'SIGTERM', killChrome));
if (options.handleSIGHUP !== false)
listeners.push(helper.addEventListener(process, 'SIGHUP', killChrome));
/** @type {?Connection} */

@@ -140,5 +147,5 @@ let connection = null;

connection = await Connection.create(browserWSEndpoint, connectionDelay);
return Browser.create(connection, options, killChrome);
return Browser.create(connection, options, chromeProcess, killChrome);
} catch (e) {
killChrome();
forceKillChrome();
throw e;

@@ -178,6 +185,14 @@ }

/**
* @return {!Array<string>}
*/
static defaultArgs() {
return DEFAULT_ARGS.concat(AUTOMATION_ARGS);
}
/**
* @return {string}
*/
static executablePath() {
const revisionInfo = Downloader.revisionInfo(Downloader.currentPlatform(), ChromiumRevision);
const downloader = Downloader.createDefault();
const revisionInfo = downloader.revisionInfo(downloader.currentPlatform(), ChromiumRevision);
return revisionInfo.executablePath;

@@ -192,3 +207,3 @@ }

const connection = await Connection.create(options.browserWSEndpoint);
return Browser.create(connection, options, () => connection.send('Browser.close'));
return Browser.create(connection, options, null, () => connection.send('Browser.close'));
}

@@ -195,0 +210,0 @@ }

@@ -46,3 +46,4 @@ /**

this._eventListeners = [
helper.addEventListener(this._frameManager, FrameManager.Events.LifecycleEvent, this._checkLifecycleComplete.bind(this))
helper.addEventListener(this._frameManager, FrameManager.Events.LifecycleEvent, this._checkLifecycleComplete.bind(this)),
helper.addEventListener(this._frameManager, FrameManager.Events.FrameDetached, this._checkLifecycleComplete.bind(this))
];

@@ -63,7 +64,7 @@

/**
* @return {?Promise<?Error>}
* @return {!Promise<?Error>}
*/
_createTimeoutPromise() {
if (!this._timeout)
return null;
return new Promise(() => {});
const errorMessage = 'Navigation Timeout Exceeded: ' + this._timeout + 'ms exceeded';

@@ -70,0 +71,0 @@ return new Promise(fulfill => this._maximumTimer = setTimeout(fulfill, this._timeout))

@@ -150,6 +150,6 @@ /**

if (event.redirectStatusCode) {
if (event.redirectUrl) {
const request = this._interceptionIdToRequest.get(event.interceptionId);
console.assert(request, 'INTERNAL ERROR: failed to find request for interception redirect.');
this._handleRequestRedirect(request, event.redirectStatusCode, event.redirectHeaders);
this._handleRequestRedirect(request, event.responseStatusCode, event.responseHeaders);
this._handleRequestStart(request._requestId, event.interceptionId, event.redirectUrl, event.resourceType, event.request);

@@ -222,3 +222,5 @@ return;

const request = this._requestIdToRequest.get(event.requestId);
this._handleRequestRedirect(request, event.redirectResponse.status, event.redirectResponse.headers);
// If we connect late to the target, we could have missed the requestWillBeSent event.
if (request)
this._handleRequestRedirect(request, event.redirectResponse.status, event.redirectResponse.headers);
}

@@ -297,12 +299,47 @@ this._handleRequestStart(event.requestId, null, event.request.url, event.type, event.request);

this.url = url;
this.resourceType = resourceType.toLowerCase();
this.method = payload.method;
this.postData = payload.postData;
this.headers = {};
this._url = url;
this._resourceType = resourceType.toLowerCase();
this._method = payload.method;
this._postData = payload.postData;
this._headers = {};
for (const key of Object.keys(payload.headers))
this.headers[key.toLowerCase()] = payload.headers[key];
this._headers[key.toLowerCase()] = payload.headers[key];
}
/**
* @return {string}
*/
url() {
return this._url;
}
/**
* @return {string}
*/
resourceType() {
return this._resourceType;
}
/**
* @return {string}
*/
method() {
return this._method;
}
/**
* @return {string}
*/
postData() {
return this._postData;
}
/**
* @return {!Object}
*/
headers() {
return this._headers;
}
/**
* @return {?Response}

@@ -350,3 +387,3 @@ */

// Mocking responses for dataURL requests is not currently supported.
if (this.url.startsWith('data:'))
if (this._url.startsWith('data:'))
return;

@@ -443,11 +480,38 @@ console.assert(this._allowInterception, 'Request Interception is not enabled!');

this.status = status;
this.ok = status >= 200 && status <= 299;
this.url = request.url;
this.headers = {};
this._status = status;
this._url = request.url();
this._headers = {};
for (const key of Object.keys(headers))
this.headers[key.toLowerCase()] = headers[key];
this._headers[key.toLowerCase()] = headers[key];
}
/**
* @return {string}
*/
url() {
return this._url;
}
/**
* @return {boolean}
*/
ok() {
return this._status >= 200 && this._status <= 299;
}
/**
* @return {number}
*/
status() {
return this._status;
}
/**
* @return {!Object}
*/
headers() {
return this._headers;
}
/**
* @return {!Promise<!Buffer>}

@@ -454,0 +518,0 @@ */

@@ -190,3 +190,4 @@ /**

async evaluateHandle(pageFunction, ...args) {
return this.mainFrame().executionContext().evaluateHandle(pageFunction, ...args);
const context = await this.mainFrame().executionContext();
return context.evaluateHandle(pageFunction, ...args);
}

@@ -199,3 +200,4 @@

async queryObjects(prototypeHandle) {
return this.mainFrame().executionContext().queryObjects(prototypeHandle);
const context = await this.mainFrame().executionContext();
return context.queryObjects(prototypeHandle);
}

@@ -232,2 +234,10 @@

/**
* @param {string} expression
* @return {!Promise<?Puppeteer.ElementHandle>}
*/
async xpath(expression) {
return this.mainFrame().xpath(expression);
}
/**
* @param {!Array<string>} urls

@@ -259,7 +269,16 @@ * @return {!Promise<!Array<Network.Cookie>>}

async setCookie(...cookies) {
const pageURL = this.url();
const startsWithHTTP = pageURL.startsWith('http');
const items = cookies.map(cookie => {
const item = Object.assign({}, cookie);
const pageURL = this.url();
if (!item.url && pageURL.startsWith('http'))
item.url = this.url();
if (!item.url && startsWithHTTP)
item.url = pageURL;
console.assert(
item.url !== 'about:blank',
`Blank page can not have cookie "${item.name}"`
);
console.assert(
!String.prototype.startsWith.call(item.url || '', 'data:'),
`Data URL page can not have cookie "${item.name}"`
);
return item;

@@ -433,10 +452,3 @@ });

async content() {
return await this.evaluate(() => {
let retVal = '';
if (document.doctype)
retVal = new XMLSerializer().serializeToString(document.doctype);
if (document.documentElement)
retVal += document.documentElement.outerHTML;
return retVal;
});
return await this._frameManager.mainFrame().content();
}

@@ -448,7 +460,3 @@

async setContent(html) {
await this.evaluate(html => {
document.open();
document.write(html);
document.close();
}, html);
await this._frameManager.mainFrame().setContent(html);
}

@@ -466,3 +474,3 @@

const eventListeners = [
helper.addEventListener(this._networkManager, NetworkManager.Events.Request, request => requests.set(request.url, request))
helper.addEventListener(this._networkManager, NetworkManager.Events.Request, request => requests.set(request.url(), request))
];

@@ -523,3 +531,3 @@

const responses = new Map();
const listener = helper.addEventListener(this._networkManager, NetworkManager.Events.Response, response => responses.set(response.url, response));
const listener = helper.addEventListener(this._networkManager, NetworkManager.Events.Response, response => responses.set(response.url(), response));
const error = await watcher.navigationPromise();

@@ -634,3 +642,8 @@ helper.removeEventListeners([listener]);

let screenshotType = null;
if (options.path) {
// options.type takes precedence over inferring the type from options.path
// because it may be a 0-length file with no extension created beforehand (i.e. as a temp file).
if (options.type) {
console.assert(options.type === 'png' || options.type === 'jpeg', 'Unknown options.type value: ' + options.type);
screenshotType = options.type;
} else if (options.path) {
const mimeType = mime.lookup(options.path);

@@ -643,7 +656,3 @@ if (mimeType === 'image/png')

}
if (options.type) {
console.assert(!screenshotType || options.type === screenshotType, `Passed screenshot type '${options.type}' does not match the type inferred from the file path: '${screenshotType}'`);
console.assert(options.type === 'png' || options.type === 'jpeg', 'Unknown options.type value: ' + options.type);
screenshotType = options.type;
}
if (!screenshotType)

@@ -715,2 +724,4 @@ screenshotType = 'png';

const displayHeaderFooter = !!options.displayHeaderFooter;
const headerTemplate = options.headerTemplate || '';
const footerTemplate = options.footerTemplate || '';
const printBackground = !!options.printBackground;

@@ -741,2 +752,4 @@ const landscape = !!options.landscape;

displayHeaderFooter: displayHeaderFooter,
headerTemplate: headerTemplate,
footerTemplate: footerTemplate,
printBackground: printBackground,

@@ -992,6 +1005,27 @@ scale: scale,

constructor(type, text, args) {
this.type = type;
this.text = text;
this.args = args;
this._type = type;
this._text = text;
this._args = args;
}
/**
* @return {string}
*/
type() {
return this._type;
}
/**
* @return {string}
*/
text() {
return this._text;
}
/**
* @return {!Array<string>}
*/
args() {
return this._args;
}
}

@@ -998,0 +1032,0 @@

@@ -42,2 +42,9 @@ /**

}
/**
* @return {!Array<string>}
*/
static defaultArgs() {
return Launcher.defaultArgs();
}
}

@@ -44,0 +51,0 @@

@@ -40,3 +40,3 @@ /**

const categoriesArray = [
const defaultCategories = [
'-*', 'devtools.timeline', 'v8.execute', 'disabled-by-default-devtools.timeline',

@@ -47,2 +47,3 @@ 'disabled-by-default-devtools.timeline.frame', 'toplevel',

];
const categoriesArray = options.categories || defaultCategories;

@@ -49,0 +50,0 @@ if (options.screenshots)

{
"name": "puppeteer",
"version": "0.13.0",
"version": "1.0.0-next.1514510476874",
"description": "A high-level API to control headless Chrome over the DevTools Protocol",

@@ -11,5 +11,5 @@ "main": "index.js",

"scripts": {
"unit": "jasmine test/test.js",
"debug-unit": "cross-env DEBUG_TEST=true node --inspect-brk ./node_modules/jasmine/bin/jasmine.js test/test.js",
"test-doclint": "jasmine utils/doclint/check_public_api/test/test.js && jasmine utils/doclint/preprocessor/test.js",
"unit": "node test/test.js",
"debug-unit": "node --inspect-brk test/test.js",
"test-doclint": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js",
"test": "npm run lint --silent && npm run coverage && npm run test-doclint && npm run test-node6-transformer",

@@ -20,6 +20,8 @@ "install": "node install.js",

"coverage": "cross-env COVERAGE=true npm run unit",
"test-node6-transformer": "jasmine utils/node6-transform/test/test.js",
"test-node6-transformer": "node utils/node6-transform/test/test.js",
"build": "node utils/node6-transform/index.js",
"unit-node6": "jasmine node6-test/test.js",
"tsc": "tsc -p ."
"unit-node6": "node node6/test/test.js",
"tsc": "tsc -p .",
"prepublishOnly": "npm run build",
"apply-next-version": "node utils/apply_next_version.js"
},

@@ -39,3 +41,3 @@ "author": "The Chromium Authors",

"puppeteer": {
"chromium_revision": "515411"
"chromium_revision": "524617"
},

@@ -53,3 +55,2 @@ "devDependencies": {

"esprima": "^4.0.0",
"jasmine": "^2.6.0",
"markdown-toc": "^1.1.0",

@@ -56,0 +57,0 @@ "minimist": "^1.2.0",

@@ -7,3 +7,3 @@ # Puppeteer [![Linux Build Status](https://img.shields.io/travis/GoogleChrome/puppeteer/master.svg)](https://travis-ci.org/GoogleChrome/puppeteer) [![Windows Build Status](https://img.shields.io/appveyor/ci/aslushnikov/puppeteer/master.svg?logo=appveyor)](https://ci.appveyor.com/project/aslushnikov/puppeteer/branch/master) [![NPM puppeteer package](https://img.shields.io/npm/v/puppeteer.svg)](https://npmjs.org/package/puppeteer)

> Puppeteer is a Node library which provides a high-level API to control [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) Chrome over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). It can also be configured to use full (non-headless) Chrome.
> Puppeteer is a Node library which provides a high-level API to control [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). It can also be configured to use full (non-headless) Chrome or Chromium.

@@ -116,3 +116,3 @@ ###### What can I do?

By default, Puppeteer downloads and uses a specific version of Chromium so its API
is guaranteed to work out of the box. To use Puppeteer with a different version of Chrome,
is guaranteed to work out of the box. To use Puppeteer with a different version of Chrome or Chromium,
pass in the executable's path when creating a `Browser` instance:

@@ -126,2 +126,5 @@

See [`this article`](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description
of the differences between Chromium and Chrome. [`This article`](https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.
**3. Creates a fresh user profile**

@@ -139,3 +142,3 @@

displaying. Instead of launching in headless mode, launch a full version of
Chrome using `headless: false`:
the browser using `headless: false`:

@@ -201,5 +204,5 @@ ```js

Puppeteer works only with Chrome. However, many teams only run unit tests with a single browser (e.g. PhantomJS). In non-testing use cases, Puppeteer provides a powerful but simple API because it's only targeting one browser that enables you to rapidly develop automation scripts.
Puppeteer works only with Chromium or Chrome. However, many teams only run unit tests with a single browser (e.g. PhantomJS). In non-testing use cases, Puppeteer provides a powerful but simple API because it's only targeting one browser that enables you to rapidly develop automation scripts.
Puppeteer uses the latest versions of Chromium.
Puppeteer bundles the latest versions of Chromium.

@@ -206,0 +209,0 @@ #### Q: Who maintains Puppeteer?

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc