puppeteer-core
Advanced tools
Comparing version
<!-- gen:toc --> | ||
- [How to Contribute](#how-to-contribute) | ||
* [Contributor License Agreement](#contributor-license-agreement) | ||
* [Getting setup](#getting-setup) | ||
* [Getting Code](#getting-code) | ||
* [Code reviews](#code-reviews) | ||
@@ -11,3 +11,3 @@ * [Code Style](#code-style) | ||
* [Adding New Dependencies](#adding-new-dependencies) | ||
* [Writing Tests](#writing-tests) | ||
* [Running & Writing Tests](#running--writing-tests) | ||
* [Public API Coverage](#public-api-coverage) | ||
@@ -37,3 +37,3 @@ * [Debugging Puppeteer](#debugging-puppeteer) | ||
## Getting setup | ||
## Getting Code | ||
@@ -53,2 +53,8 @@ 1. Clone this repository | ||
3. Run Puppeteer tests locally. For more information about tests, read [Running & Writing Tests](#running--writing-tests). | ||
```bash | ||
npm run unit | ||
``` | ||
## Code reviews | ||
@@ -140,3 +146,3 @@ | ||
## Writing Tests | ||
## Running & Writing Tests | ||
@@ -164,2 +170,9 @@ - Every feature should be accompanied by a test. | ||
- To run tests in "verbose" mode or to stop testrunner on first failure: | ||
```bash | ||
npm run unit -- --verbose | ||
npm run unit -- --break-on-failure | ||
``` | ||
- To run a specific test, substitute the `it` with `fit` (mnemonic rule: '*focus it*'): | ||
@@ -166,0 +179,0 @@ |
@@ -28,2 +28,3 @@ /** | ||
ExecutionContext: require('./ExecutionContext').ExecutionContext, | ||
FileChooser: require('./Page').FileChooser, | ||
Frame: require('./FrameManager').Frame, | ||
@@ -30,0 +31,0 @@ JSHandle: require('./JSHandle').JSHandle, |
@@ -116,3 +116,3 @@ /** | ||
} catch (err) { | ||
if (err instanceof TypeError && err.message === 'Converting circular structure to JSON') | ||
if (err instanceof TypeError && err.message.startsWith('Converting circular structure to JSON')) | ||
err.message += ' Are you passing a nested JSHandle?'; | ||
@@ -119,0 +119,0 @@ throw err; |
@@ -18,3 +18,3 @@ /** | ||
const EventEmitter = require('events'); | ||
const {helper, assert} = require('./helper'); | ||
const {helper, assert, debugError} = require('./helper'); | ||
const {Events} = require('./Events'); | ||
@@ -280,3 +280,3 @@ const {ExecutionContext, EVALUATION_SCRIPT_URL} = require('./ExecutionContext'); | ||
worldName: name, | ||
}))); | ||
}).catch(debugError))); // frames might be removed before we send this | ||
} | ||
@@ -283,0 +283,0 @@ |
@@ -217,7 +217,10 @@ /** | ||
const timeoutPromise = new Promise((resolve, x) => reject = x); | ||
const timeoutTimer = setTimeout(() => reject(timeoutError), timeout); | ||
let timeoutTimer = null; | ||
if (timeout) | ||
timeoutTimer = setTimeout(() => reject(timeoutError), timeout); | ||
try { | ||
return await Promise.race([promise, timeoutPromise]); | ||
} finally { | ||
clearTimeout(timeoutTimer); | ||
if (timeoutTimer) | ||
clearTimeout(timeoutTimer); | ||
} | ||
@@ -224,0 +227,0 @@ } |
@@ -45,2 +45,3 @@ /** | ||
'--disable-client-side-phishing-detection', | ||
'--disable-component-extensions-with-background-pages', | ||
'--disable-default-apps', | ||
@@ -126,3 +127,9 @@ '--disable-dev-shm-usage', | ||
/** @type {!Array<"ignore"|"pipe">} */ | ||
const stdio = usePipe ? ['ignore', 'ignore', 'ignore', 'pipe', 'pipe'] : ['pipe', 'pipe', 'pipe']; | ||
let stdio = ['pipe', 'pipe', 'pipe']; | ||
if (usePipe) { | ||
if (dumpio) | ||
stdio = ['ignore', 'pipe', 'pipe', 'pipe', 'pipe']; | ||
else | ||
stdio = ['ignore', 'ignore', 'ignore', 'pipe', 'pipe']; | ||
} | ||
const chromeProcess = childProcess.spawn( | ||
@@ -297,3 +304,2 @@ chromeExecutable, | ||
_resolveExecutablePath() { | ||
const browserFetcher = new BrowserFetcher(this._projectRoot); | ||
// puppeteer-core doesn't take into account PUPPETEER_* env variables. | ||
@@ -306,2 +312,5 @@ if (!this._isPuppeteerCore) { | ||
} | ||
} | ||
const browserFetcher = new BrowserFetcher(this._projectRoot); | ||
if (!this._isPuppeteerCore) { | ||
const revision = process.env['PUPPETEER_CHROMIUM_REVISION']; | ||
@@ -308,0 +317,0 @@ if (revision) { |
102
lib/Page.js
@@ -18,2 +18,3 @@ /** | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const EventEmitter = require('events'); | ||
@@ -47,8 +48,3 @@ const mime = require('mime'); | ||
const page = new Page(client, target, ignoreHTTPSErrors, screenshotTaskQueue); | ||
await Promise.all([ | ||
page._frameManager.initialize(), | ||
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}), | ||
client.send('Performance.enable', {}), | ||
client.send('Log.enable', {}), | ||
]); | ||
await page._initialize(); | ||
if (defaultViewport) | ||
@@ -120,2 +116,4 @@ await page.setViewport(defaultViewport); | ||
networkManager.on(Events.NetworkManager.RequestFinished, event => this.emit(Events.Page.RequestFinished, event)); | ||
this._fileChooserInterceptionIsDisabled = false; | ||
this._fileChooserInterceptors = new Set(); | ||
@@ -131,2 +129,3 @@ client.on('Page.domContentEventFired', event => this.emit(Events.Page.DOMContentLoaded)); | ||
client.on('Log.entryAdded', event => this._onLogEntryAdded(event)); | ||
client.on('Page.fileChooserOpened', event => this._onFileChooser(event)); | ||
this._target._isClosedPromise.then(() => { | ||
@@ -138,3 +137,49 @@ this.emit(Events.Page.Close); | ||
async _initialize() { | ||
await Promise.all([ | ||
this._frameManager.initialize(), | ||
this._client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}), | ||
this._client.send('Performance.enable', {}), | ||
this._client.send('Log.enable', {}), | ||
this._client.send('Page.setInterceptFileChooserDialog', {enabled: true}).catch(e => { | ||
this._fileChooserInterceptionIsDisabled = true; | ||
}), | ||
]); | ||
} | ||
/** | ||
* @param {!Protocol.Page.fileChooserOpenedPayload} event | ||
*/ | ||
_onFileChooser(event) { | ||
if (!this._fileChooserInterceptors.size) { | ||
this._client.send('Page.handleFileChooser', { action: 'fallback' }).catch(debugError); | ||
return; | ||
} | ||
const interceptors = Array.from(this._fileChooserInterceptors); | ||
this._fileChooserInterceptors.clear(); | ||
const fileChooser = new FileChooser(this._client, event); | ||
for (const interceptor of interceptors) | ||
interceptor.call(null, fileChooser); | ||
} | ||
/** | ||
* @param {!{timeout?: number}=} options | ||
* @return !Promise<!FileChooser>} | ||
*/ | ||
async waitForFileChooser(options = {}) { | ||
if (this._fileChooserInterceptionIsDisabled) | ||
throw new Error('File chooser handling does not work with multiple connections to the same page'); | ||
const { | ||
timeout = this._timeoutSettings.timeout(), | ||
} = options; | ||
let callback; | ||
const promise = new Promise(x => callback = x); | ||
this._fileChooserInterceptors.add(callback); | ||
return helper.waitWithTimeout(promise, 'waiting for file chooser', timeout).catch(e => { | ||
this._fileChooserInterceptors.delete(callback); | ||
throw e; | ||
}); | ||
} | ||
/** | ||
* @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}} options | ||
@@ -1266,3 +1311,46 @@ */ | ||
class FileChooser { | ||
/** | ||
* @param {Puppeteer.CDPSession} client | ||
* @param {!Protocol.Page.fileChooserOpenedPayload} event | ||
*/ | ||
constructor(client, event) { | ||
this._client = client; | ||
this._multiple = event.mode !== 'selectSingle'; | ||
this._handled = false; | ||
} | ||
module.exports = {Page, ConsoleMessage}; | ||
/** | ||
* @return {boolean} | ||
*/ | ||
isMultiple() { | ||
return this._multiple; | ||
} | ||
/** | ||
* @param {!Array<string>} filePaths | ||
* @return {!Promise} | ||
*/ | ||
async accept(filePaths) { | ||
assert(!this._handled, 'Cannot accept FileChooser which is already handled!'); | ||
this._handled = true; | ||
const files = filePaths.map(filePath => path.resolve(filePath)); | ||
await this._client.send('Page.handleFileChooser', { | ||
action: 'accept', | ||
files, | ||
}); | ||
} | ||
/** | ||
* @return {!Promise} | ||
*/ | ||
async cancel() { | ||
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!'); | ||
this._handled = true; | ||
await this._client.send('Page.handleFileChooser', { | ||
action: 'cancel', | ||
}); | ||
} | ||
} | ||
module.exports = {Page, ConsoleMessage, FileChooser}; |
@@ -16,3 +16,3 @@ /** | ||
*/ | ||
const {helper} = require('./helper'); | ||
const {helper, debugError} = require('./helper'); | ||
@@ -35,3 +35,5 @@ /** | ||
this.onclose.call(null); | ||
}) | ||
}), | ||
helper.addEventListener(pipeRead, 'error', debugError), | ||
helper.addEventListener(pipeWrite, 'error', debugError), | ||
]; | ||
@@ -38,0 +40,0 @@ this.onmessage = null; |
@@ -280,3 +280,10 @@ /** | ||
'}': {'keyCode': 221, 'key': '}', 'code': 'BracketRight'}, | ||
'"': {'keyCode': 222, 'key': '"', 'code': 'Quote'} | ||
'"': {'keyCode': 222, 'key': '"', 'code': 'Quote'}, | ||
'SoftLeft': {'key': 'SoftLeft', 'code': 'SoftLeft', 'location': 4}, | ||
'SoftRight': {'key': 'SoftRight', 'code': 'SoftRight', 'location': 4}, | ||
'Camera': {'keyCode': 44, 'key': 'Camera', 'code': 'Camera', 'location': 4}, | ||
'Call': {'key': 'Call', 'code': 'Call', 'location': 4}, | ||
'EndCall': {'keyCode': 95, 'key': 'EndCall', 'code': 'EndCall', 'location': 4}, | ||
'VolumeDown': {'keyCode': 182, 'key': 'VolumeDown', 'code': 'VolumeDown', 'location': 4}, | ||
'VolumeUp': {'keyCode': 183, 'key': 'VolumeUp', 'code': 'VolumeUp', 'location': 4}, | ||
}; |
@@ -28,2 +28,3 @@ /** | ||
ExecutionContext: require('./ExecutionContext').ExecutionContext, | ||
FileChooser: require('./Page').FileChooser, | ||
Frame: require('./FrameManager').Frame, | ||
@@ -30,0 +31,0 @@ JSHandle: require('./JSHandle').JSHandle, |
@@ -194,3 +194,3 @@ /** | ||
} catch (err) { | ||
if (err instanceof TypeError && err.message === 'Converting circular structure to JSON') | ||
if (err instanceof TypeError && err.message.startsWith('Converting circular structure to JSON')) | ||
err.message += ' Are you passing a nested JSHandle?'; | ||
@@ -197,0 +197,0 @@ throw err; |
@@ -18,3 +18,3 @@ /** | ||
const EventEmitter = require('events'); | ||
const {helper, assert} = require('./helper'); | ||
const {helper, assert, debugError} = require('./helper'); | ||
const {Events} = require('./Events'); | ||
@@ -410,3 +410,3 @@ const {ExecutionContext, EVALUATION_SCRIPT_URL} = require('./ExecutionContext'); | ||
worldName: name, | ||
})))); | ||
}).catch(debugError)))); // frames might be removed before we send this | ||
});} | ||
@@ -413,0 +413,0 @@ |
@@ -269,7 +269,10 @@ /** | ||
const timeoutPromise = new Promise((resolve, x) => reject = x); | ||
const timeoutTimer = setTimeout(() => reject(timeoutError), timeout); | ||
let timeoutTimer = null; | ||
if (timeout) | ||
timeoutTimer = setTimeout(() => reject(timeoutError), timeout); | ||
try { | ||
return (yield Promise.race([promise, timeoutPromise])); | ||
} finally { | ||
clearTimeout(timeoutTimer); | ||
if (timeoutTimer) | ||
clearTimeout(timeoutTimer); | ||
} | ||
@@ -276,0 +279,0 @@ });} |
@@ -45,2 +45,3 @@ /** | ||
'--disable-client-side-phishing-detection', | ||
'--disable-component-extensions-with-background-pages', | ||
'--disable-default-apps', | ||
@@ -152,3 +153,9 @@ '--disable-dev-shm-usage', | ||
/** @type {!Array<"ignore"|"pipe">} */ | ||
const stdio = usePipe ? ['ignore', 'ignore', 'ignore', 'pipe', 'pipe'] : ['pipe', 'pipe', 'pipe']; | ||
let stdio = ['pipe', 'pipe', 'pipe']; | ||
if (usePipe) { | ||
if (dumpio) | ||
stdio = ['ignore', 'pipe', 'pipe', 'pipe', 'pipe']; | ||
else | ||
stdio = ['ignore', 'ignore', 'ignore', 'pipe', 'pipe']; | ||
} | ||
const chromeProcess = childProcess.spawn( | ||
@@ -349,3 +356,2 @@ chromeExecutable, | ||
_resolveExecutablePath() { | ||
const browserFetcher = new BrowserFetcher(this._projectRoot); | ||
// puppeteer-core doesn't take into account PUPPETEER_* env variables. | ||
@@ -358,2 +364,5 @@ if (!this._isPuppeteerCore) { | ||
} | ||
} | ||
const browserFetcher = new BrowserFetcher(this._projectRoot); | ||
if (!this._isPuppeteerCore) { | ||
const revision = process.env['PUPPETEER_CHROMIUM_REVISION']; | ||
@@ -360,0 +369,0 @@ if (revision) { |
@@ -16,3 +16,3 @@ /** | ||
*/ | ||
const {helper} = require('./helper'); | ||
const {helper, debugError} = require('./helper'); | ||
@@ -35,3 +35,5 @@ /** | ||
this.onclose.call(null); | ||
}) | ||
}), | ||
helper.addEventListener(pipeRead, 'error', debugError), | ||
helper.addEventListener(pipeWrite, 'error', debugError), | ||
]; | ||
@@ -38,0 +40,0 @@ this.onmessage = null; |
@@ -280,3 +280,10 @@ /** | ||
'}': {'keyCode': 221, 'key': '}', 'code': 'BracketRight'}, | ||
'"': {'keyCode': 222, 'key': '"', 'code': 'Quote'} | ||
'"': {'keyCode': 222, 'key': '"', 'code': 'Quote'}, | ||
'SoftLeft': {'key': 'SoftLeft', 'code': 'SoftLeft', 'location': 4}, | ||
'SoftRight': {'key': 'SoftRight', 'code': 'SoftRight', 'location': 4}, | ||
'Camera': {'keyCode': 44, 'key': 'Camera', 'code': 'Camera', 'location': 4}, | ||
'Call': {'key': 'Call', 'code': 'Call', 'location': 4}, | ||
'EndCall': {'keyCode': 95, 'key': 'EndCall', 'code': 'EndCall', 'location': 4}, | ||
'VolumeDown': {'keyCode': 182, 'key': 'VolumeDown', 'code': 'VolumeDown', 'location': 4}, | ||
'VolumeUp': {'keyCode': 183, 'key': 'VolumeUp', 'code': 'VolumeUp', 'location': 4}, | ||
}; |
{ | ||
"name": "puppeteer-core", | ||
"version": "1.18.1", | ||
"version": "1.19.0", | ||
"description": "A high-level API to control headless Chrome over the DevTools Protocol", | ||
@@ -11,3 +11,3 @@ "main": "index.js", | ||
"puppeteer": { | ||
"chromium_revision": "672088" | ||
"chromium_revision": "674921" | ||
}, | ||
@@ -14,0 +14,0 @@ "scripts": { |
@@ -9,3 +9,3 @@ # Puppeteer | ||
###### [API](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/GoogleChrome/puppeteer/blob/master/CONTRIBUTING.md) | [Troubleshooting](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md) | ||
###### [API](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/GoogleChrome/puppeteer/blob/master/CONTRIBUTING.md) | [Troubleshooting](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md) | ||
@@ -41,3 +41,3 @@ > Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). Puppeteer runs [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) by default, but can be configured to run full (non-headless) Chrome or Chromium. | ||
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, see [Environment variables](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#environment-variables). | ||
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, see [Environment variables](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#environment-variables). | ||
@@ -65,3 +65,3 @@ | ||
Puppeteer will be familiar to people using other browser testing frameworks. You create an instance | ||
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#). | ||
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#). | ||
@@ -91,3 +91,3 @@ **Example** - navigating to https://example.com and saving a screenshot as *example.png*: | ||
Puppeteer sets an initial page size to 800px x 600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#pagesetviewportviewport). | ||
Puppeteer sets an initial page size to 800px x 600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#pagesetviewportviewport). | ||
@@ -117,3 +117,3 @@ **Example** - create a PDF. | ||
See [`Page.pdf()`](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#pagepdfoptions) for more information about creating pdfs. | ||
See [`Page.pdf()`](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#pagepdfoptions) for more information about creating pdfs. | ||
@@ -153,3 +153,3 @@ **Example** - evaluate script in the context of the page | ||
See [`Page.evaluate()`](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`. | ||
See [`Page.evaluate()`](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`. | ||
@@ -163,3 +163,3 @@ <!-- [END getstarted] --> | ||
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the ['headless' option](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#puppeteerlaunchoptions) when launching a browser: | ||
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the ['headless' option](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#puppeteerlaunchoptions) when launching a browser: | ||
@@ -180,3 +180,3 @@ ```js | ||
See [`Puppeteer.launch()`](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#puppeteerlaunchoptions) for more information. | ||
See [`Puppeteer.launch()`](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#puppeteerlaunchoptions) for more information. | ||
@@ -193,3 +193,3 @@ 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/+/master/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users. | ||
- [API Documentation](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md) | ||
- [API Documentation](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md) | ||
- [Examples](https://github.com/GoogleChrome/puppeteer/tree/master/examples/) | ||
@@ -384,3 +384,3 @@ - [Community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer) | ||
* Puppeteer is bundled with Chromium--not Chrome--and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.) | ||
* Puppeteer is bundled with Chromium--not Chrome--and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.) | ||
* Since Puppeteer (in all configurations) controls a desktop version of Chromium/Chrome, features that are only supported by the mobile version of Chrome are not supported. This means that Puppeteer [does not support HTTP Live Streaming (HLS)](https://caniuse.com/#feat=http-live-streaming). | ||
@@ -387,0 +387,0 @@ |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
761622
1.36%22858
1.38%