chore: use Google's TS style guide's format config (#8542)

This commit is contained in:
jrandolf 2022-06-22 15:25:44 +02:00 committed by GitHub
parent 3744c2f584
commit 84712cbc28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
122 changed files with 2891 additions and 2962 deletions

View File

@ -143,7 +143,7 @@ module.exports = {
'no-unused-vars': 0, 'no-unused-vars': 0,
'@typescript-eslint/no-unused-vars': [ '@typescript-eslint/no-unused-vars': [
'error', 'error',
{ argsIgnorePattern: '^_' }, {argsIgnorePattern: '^_'},
], ],
'func-call-spacing': 0, 'func-call-spacing': 0,
'@typescript-eslint/func-call-spacing': 2, '@typescript-eslint/func-call-spacing': 2,

1
.prettierrc.cjs Normal file
View File

@ -0,0 +1 @@
module.exports = require('gts/.prettierrc.json');

View File

@ -76,7 +76,7 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto('https://example.com'); await page.goto('https://example.com');
await page.screenshot({ path: 'example.png' }); await page.screenshot({path: 'example.png'});
await browser.close(); await browser.close();
})(); })();
@ -103,7 +103,7 @@ const puppeteer = require('puppeteer');
await page.goto('https://news.ycombinator.com', { await page.goto('https://news.ycombinator.com', {
waitUntil: 'networkidle2', waitUntil: 'networkidle2',
}); });
await page.pdf({ path: 'hn.pdf', format: 'a4' }); await page.pdf({path: 'hn.pdf', format: 'a4'});
await browser.close(); await browser.close();
})(); })();
@ -163,7 +163,7 @@ See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/main/docs/ap
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/puppeteer/puppeteer/blob/main/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/puppeteer/puppeteer/blob/main/docs/api.md#puppeteerlaunchoptions) when launching a browser:
```js ```js
const browser = await puppeteer.launch({ headless: false }); // default is true const browser = await puppeteer.launch({headless: false}); // default is true
``` ```
**2. Runs a bundled version of Chromium** **2. Runs a bundled version of Chromium**
@ -173,7 +173,7 @@ is guaranteed to work out of the box. To use Puppeteer with a different version
pass in the executable's path when creating a `Browser` instance: pass in the executable's path when creating a `Browser` instance:
```js ```js
const browser = await puppeteer.launch({ executablePath: '/path/to/Chrome' }); const browser = await puppeteer.launch({executablePath: '/path/to/Chrome'});
``` ```
You can also use Puppeteer with Firefox Nightly (experimental support). See [`Puppeteer.launch()`](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#puppeteerlaunchoptions) for more information. You can also use Puppeteer with Firefox Nightly (experimental support). See [`Puppeteer.launch()`](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#puppeteerlaunchoptions) for more information.
@ -201,7 +201,7 @@ Puppeteer creates its own browser user profile which it **cleans up on every run
the browser using `headless: false`: the browser using `headless: false`:
```js ```js
const browser = await puppeteer.launch({ headless: false }); const browser = await puppeteer.launch({headless: false});
``` ```
2. Slow it down - the `slowMo` option slows down Puppeteer operations by the 2. Slow it down - the `slowMo` option slows down Puppeteer operations by the
@ -218,7 +218,7 @@ Puppeteer creates its own browser user profile which it **cleans up on every run
This is also handy when debugging code in `page.evaluate()`: This is also handy when debugging code in `page.evaluate()`:
```js ```js
page.on('console', (msg) => console.log('PAGE LOG:', msg.text())); page.on('console', msg => console.log('PAGE LOG:', msg.text()));
await page.evaluate(() => console.log(`url is ${location.href}`)); await page.evaluate(() => console.log(`url is ${location.href}`));
``` ```
@ -232,7 +232,7 @@ Puppeteer creates its own browser user profile which it **cleans up on every run
- Use `{devtools: true}` when launching Puppeteer: - Use `{devtools: true}` when launching Puppeteer:
```js ```js
const browser = await puppeteer.launch({ devtools: true }); const browser = await puppeteer.launch({devtools: true});
``` ```
- Change default test timeout: - Change default test timeout:

View File

@ -1,4 +1,4 @@
import { dirname } from 'path'; import {dirname} from 'path';
let puppeteerDirname: string; let puppeteerDirname: string;
@ -13,4 +13,4 @@ try {
puppeteerDirname = __dirname; puppeteerDirname = __dirname;
} }
export { puppeteerDirname }; export {puppeteerDirname};

View File

@ -1,6 +1,6 @@
import { createRequire } from 'module'; import {createRequire} from 'module';
import { dirname } from 'path'; import {dirname} from 'path';
import { fileURLToPath } from 'url'; import {fileURLToPath} from 'url';
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
@ -16,4 +16,4 @@ try {
puppeteerDirname = dirname(fileURLToPath(import.meta.url)); puppeteerDirname = dirname(fileURLToPath(import.meta.url));
} }
export { puppeteerDirname }; export {puppeteerDirname};

View File

@ -515,7 +515,7 @@ const puppeteer = require('puppeteer');
], ],
}); });
const backgroundPageTarget = await browser.waitForTarget( const backgroundPageTarget = await browser.waitForTarget(
(target) => target.type() === 'background_page' target => target.type() === 'background_page'
); );
const backgroundPage = await backgroundPageTarget.page(); const backgroundPage = await backgroundPageTarget.page();
// Test the background page as you would any other page. // Test the background page as you would any other page.
@ -858,7 +858,7 @@ const puppeteer = require('puppeteer');
browser.disconnect(); browser.disconnect();
// Use the endpoint to reestablish a connection // Use the endpoint to reestablish a connection
const browser2 = await puppeteer.connect({ browserWSEndpoint }); const browser2 = await puppeteer.connect({browserWSEndpoint});
// Close Chromium // Close Chromium
await browser2.close(); await browser2.close();
})(); })();
@ -1003,7 +1003,7 @@ An example of finding a target for a page opened via `window.open`:
```js ```js
await page.evaluate(() => window.open('https://www.example.com/')); await page.evaluate(() => window.open('https://www.example.com/'));
const newWindowTarget = await browser.waitForTarget( const newWindowTarget = await browser.waitForTarget(
(target) => target.url() === 'https://www.example.com/' target => target.url() === 'https://www.example.com/'
); );
``` ```
@ -1155,7 +1155,7 @@ An example of finding a target for a page opened via `window.open`:
```js ```js
await page.evaluate(() => window.open('https://www.example.com/')); await page.evaluate(() => window.open('https://www.example.com/'));
const newWindowTarget = await browserContext.waitForTarget( const newWindowTarget = await browserContext.waitForTarget(
(target) => target.url() === 'https://www.example.com/' target => target.url() === 'https://www.example.com/'
); );
``` ```
@ -1174,7 +1174,7 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto('https://example.com'); await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' }); await page.screenshot({path: 'screenshot.png'});
await browser.close(); await browser.close();
})(); })();
``` ```
@ -1215,11 +1215,11 @@ The arguments passed into `console.log` appear as arguments on the event handler
An example of handling `console` event: An example of handling `console` event:
```js ```js
page.on('console', (msg) => { page.on('console', msg => {
for (let i = 0; i < msg.args().length; ++i) for (let i = 0; i < msg.args().length; ++i)
console.log(`${i}: ${msg.args()[i]}`); console.log(`${i}: ${msg.args()[i]}`);
}); });
page.evaluate(() => console.log('hello', 5, { foo: 'bar' })); page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
``` ```
#### event: 'dialog' #### event: 'dialog'
@ -1286,14 +1286,14 @@ Emitted when the page opens a new tab or window.
```js ```js
const [popup] = await Promise.all([ const [popup] = await Promise.all([
new Promise((resolve) => page.once('popup', resolve)), new Promise(resolve => page.once('popup', resolve)),
page.click('a[target=_blank]'), page.click('a[target=_blank]'),
]); ]);
``` ```
```js ```js
const [popup] = await Promise.all([ const [popup] = await Promise.all([
new Promise((resolve) => page.once('popup', resolve)), new Promise(resolve => page.once('popup', resolve)),
page.evaluate(() => window.open('https://example.com')), page.evaluate(() => window.open('https://example.com')),
]); ]);
``` ```
@ -1369,12 +1369,12 @@ If `pageFunction` returns a [Promise], then `page.$$eval` would wait for the pro
Examples: Examples:
```js ```js
const divCount = await page.$$eval('div', (divs) => divs.length); const divCount = await page.$$eval('div', divs => divs.length);
``` ```
```js ```js
const options = await page.$$eval('div > span.options', (options) => const options = await page.$$eval('div > span.options', options =>
options.map((option) => option.textContent) options.map(option => option.textContent)
); );
``` ```
@ -1392,9 +1392,9 @@ If `pageFunction` returns a [Promise], then `page.$eval` would wait for the prom
Examples: Examples:
```js ```js
const searchValue = await page.$eval('#search', (el) => el.value); const searchValue = await page.$eval('#search', el => el.value);
const preloadHref = await page.$eval('link[rel=preload]', (el) => el.href); const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
const html = await page.$eval('.main-container', (e) => e.outerHTML); const html = await page.$eval('.main-container', e => e.outerHTML);
``` ```
Shortcut for [page.mainFrame().$eval(selector, pageFunction)](#frameevalselector-pagefunction-args). Shortcut for [page.mainFrame().$eval(selector, pageFunction)](#frameevalselector-pagefunction-args).
@ -1662,7 +1662,7 @@ const slow3G = puppeteer.networkConditions['Slow 3G'];
```js ```js
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'prefers-color-scheme', value: 'dark' }, {name: 'prefers-color-scheme', value: 'dark'},
]); ]);
await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches); await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches);
// → true // → true
@ -1670,7 +1670,7 @@ await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches);
// → false // → false
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'prefers-reduced-motion', value: 'reduce' }, {name: 'prefers-reduced-motion', value: 'reduce'},
]); ]);
await page.evaluate( await page.evaluate(
() => matchMedia('(prefers-reduced-motion: reduce)').matches () => matchMedia('(prefers-reduced-motion: reduce)').matches
@ -1682,8 +1682,8 @@ await page.evaluate(
// → false // → false
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'prefers-color-scheme', value: 'dark' }, {name: 'prefers-color-scheme', value: 'dark'},
{ name: 'prefers-reduced-motion', value: 'reduce' }, {name: 'prefers-reduced-motion', value: 'reduce'},
]); ]);
await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches); await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches);
// → true // → true
@ -1698,7 +1698,7 @@ await page.evaluate(
); );
// → false // → false
await page.emulateMediaFeatures([{ name: 'color-gamut', value: 'p3' }]); await page.emulateMediaFeatures([{name: 'color-gamut', value: 'p3'}]);
await page.evaluate(() => matchMedia('(color-gamut: srgb)').matches); await page.evaluate(() => matchMedia('(color-gamut: srgb)').matches);
// → true // → true
await page.evaluate(() => matchMedia('(color-gamut: p3)').matches); await page.evaluate(() => matchMedia('(color-gamut: p3)').matches);
@ -1774,13 +1774,13 @@ const puppeteer = require('puppeteer');
await page.goto('https://v8.dev/blog/10-years'); await page.goto('https://v8.dev/blog/10-years');
await page.emulateVisionDeficiency('achromatopsia'); await page.emulateVisionDeficiency('achromatopsia');
await page.screenshot({ path: 'achromatopsia.png' }); await page.screenshot({path: 'achromatopsia.png'});
await page.emulateVisionDeficiency('deuteranopia'); await page.emulateVisionDeficiency('deuteranopia');
await page.screenshot({ path: 'deuteranopia.png' }); await page.screenshot({path: 'deuteranopia.png'});
await page.emulateVisionDeficiency('blurredVision'); await page.emulateVisionDeficiency('blurredVision');
await page.screenshot({ path: 'blurred-vision.png' }); await page.screenshot({path: 'blurred-vision.png'});
await browser.close(); await browser.close();
})(); })();
@ -1799,7 +1799,7 @@ If the function passed to the `page.evaluate` returns a non-[Serializable] value
Passing arguments to `pageFunction`: Passing arguments to `pageFunction`:
```js ```js
const result = await page.evaluate((x) => { const result = await page.evaluate(x => {
return Promise.resolve(8 * x); return Promise.resolve(8 * x);
}, 7); }, 7);
console.log(result); // prints "56" console.log(result); // prints "56"
@ -1817,7 +1817,7 @@ console.log(await page.evaluate(`1 + ${x}`)); // prints "11"
```js ```js
const bodyHandle = await page.$('body'); const bodyHandle = await page.$('body');
const html = await page.evaluate((body) => body.innerHTML, bodyHandle); const html = await page.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose(); await bodyHandle.dispose();
``` ```
@ -1843,10 +1843,7 @@ const aHandle = await page.evaluateHandle('document'); // Handle for the 'docume
```js ```js
const aHandle = await page.evaluateHandle(() => document.body); const aHandle = await page.evaluateHandle(() => document.body);
const resultHandle = await page.evaluateHandle( const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle);
(body) => body.innerHTML,
aHandle
);
console.log(await resultHandle.jsonValue()); console.log(await resultHandle.jsonValue());
await resultHandle.dispose(); await resultHandle.dispose();
``` ```
@ -1915,8 +1912,8 @@ const crypto = require('crypto');
(async () => { (async () => {
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
page.on('console', (msg) => console.log(msg.text())); page.on('console', msg => console.log(msg.text()));
await page.exposeFunction('md5', (text) => await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex') crypto.createHash('md5').update(text).digest('hex')
); );
await page.evaluate(async () => { await page.evaluate(async () => {
@ -1938,8 +1935,8 @@ const fs = require('fs');
(async () => { (async () => {
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
page.on('console', (msg) => console.log(msg.text())); page.on('console', msg => console.log(msg.text()));
await page.exposeFunction('readfile', async (filePath) => { await page.exposeFunction('readfile', async filePath => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, text) => { fs.readFile(filePath, 'utf8', (err, text) => {
if (err) reject(err); if (err) reject(err);
@ -2128,7 +2125,7 @@ Page is guaranteed to have a main frame which persists during navigations.
```js ```js
// Generates a PDF with 'screen' media type. // Generates a PDF with 'screen' media type.
await page.emulateMediaType('screen'); await page.emulateMediaType('screen');
await page.pdf({ path: 'page.pdf' }); await page.pdf({path: 'page.pdf'});
``` ```
The `width`, `height`, and `margin` options accept values labeled with units. Unlabeled values are treated as pixels. The `width`, `height`, and `margin` options accept values labeled with units. Unlabeled values are treated as pixels.
@ -2180,7 +2177,7 @@ const mapPrototype = await page.evaluateHandle(() => Map.prototype);
// Query all map instances into an array // Query all map instances into an array
const mapInstances = await page.queryObjects(mapPrototype); const mapInstances = await page.queryObjects(mapPrototype);
// Count amount of map objects in heap // Count amount of map objects in heap
const count = await page.evaluate((maps) => maps.length, mapInstances); const count = await page.evaluate(maps => maps.length, mapInstances);
await mapInstances.dispose(); await mapInstances.dispose();
await mapPrototype.dispose(); await mapPrototype.dispose();
``` ```
@ -2343,7 +2340,7 @@ The extra HTTP headers will be sent with every request the page initiates.
Sets the page's geolocation. Sets the page's geolocation.
```js ```js
await page.setGeolocation({ latitude: 59.95, longitude: 30.31667 }); await page.setGeolocation({latitude: 59.95, longitude: 30.31667});
``` ```
> **NOTE** Consider using [browserContext.overridePermissions](#browsercontextoverridepermissionsorigin-permissions) to grant permissions for the page to read its geolocation. > **NOTE** Consider using [browserContext.overridePermissions](#browsercontextoverridepermissionsorigin-permissions) to grant permissions for the page to read its geolocation.
@ -2380,7 +2377,7 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.setRequestInterception(true); await page.setRequestInterception(true);
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
if (interceptedRequest.isInterceptResolutionHandled()) return; if (interceptedRequest.isInterceptResolutionHandled()) return;
if ( if (
interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.png') ||
@ -2411,7 +2408,7 @@ This example demonstrates two synchronous handlers working together:
/* /*
This first handler will succeed in calling request.continue because the request interception has never been resolved. This first handler will succeed in calling request.continue because the request interception has never been resolved.
*/ */
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
if (interceptedRequest.isInterceptResolutionHandled()) return; if (interceptedRequest.isInterceptResolutionHandled()) return;
interceptedRequest.continue(); interceptedRequest.continue();
}); });
@ -2420,7 +2417,7 @@ page.on('request', (interceptedRequest) => {
This second handler will return before calling request.abort because request.continue was already This second handler will return before calling request.abort because request.continue was already
called by the first handler. called by the first handler.
*/ */
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
if (interceptedRequest.isInterceptResolutionHandled()) return; if (interceptedRequest.isInterceptResolutionHandled()) return;
interceptedRequest.abort(); interceptedRequest.abort();
}); });
@ -2432,12 +2429,12 @@ This example demonstrates asynchronous handlers working together:
/* /*
This first handler will succeed in calling request.continue because the request interception has never been resolved. This first handler will succeed in calling request.continue because the request interception has never been resolved.
*/ */
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
// The interception has not been handled yet. Control will pass through this guard. // The interception has not been handled yet. Control will pass through this guard.
if (interceptedRequest.isInterceptResolutionHandled()) return; if (interceptedRequest.isInterceptResolutionHandled()) return;
// It is not strictly necessary to return a promise, but doing so will allow Puppeteer to await this handler. // It is not strictly necessary to return a promise, but doing so will allow Puppeteer to await this handler.
return new Promise((resolve) => { return new Promise(resolve => {
// Continue after 500ms // Continue after 500ms
setTimeout(() => { setTimeout(() => {
// Inside, check synchronously to verify that the intercept wasn't handled already. // Inside, check synchronously to verify that the intercept wasn't handled already.
@ -2451,7 +2448,7 @@ page.on('request', (interceptedRequest) => {
}, 500); }, 500);
}); });
}); });
page.on('request', async (interceptedRequest) => { page.on('request', async interceptedRequest => {
// The interception has not been handled yet. Control will pass through this guard. // The interception has not been handled yet. Control will pass through this guard.
if (interceptedRequest.isInterceptResolutionHandled()) return; if (interceptedRequest.isInterceptResolutionHandled()) return;
@ -2471,18 +2468,18 @@ Here is the example above rewritten using `request.interceptResolutionState`
/* /*
This first handler will succeed in calling request.continue because the request interception has never been resolved. This first handler will succeed in calling request.continue because the request interception has never been resolved.
*/ */
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
// The interception has not been handled yet. Control will pass through this guard. // The interception has not been handled yet. Control will pass through this guard.
const { action } = interceptedRequest.interceptResolutionState(); const {action} = interceptedRequest.interceptResolutionState();
if (action === InterceptResolutionAction.AlreadyHandled) return; if (action === InterceptResolutionAction.AlreadyHandled) return;
// It is not strictly necessary to return a promise, but doing so will allow Puppeteer to await this handler. // It is not strictly necessary to return a promise, but doing so will allow Puppeteer to await this handler.
return new Promise((resolve) => { return new Promise(resolve => {
// Continue after 500ms // Continue after 500ms
setTimeout(() => { setTimeout(() => {
// Inside, check synchronously to verify that the intercept wasn't handled already. // Inside, check synchronously to verify that the intercept wasn't handled already.
// It might have been handled during the 500ms while the other handler awaited an async op of its own. // It might have been handled during the 500ms while the other handler awaited an async op of its own.
const { action } = interceptedRequest.interceptResolutionState(); const {action} = interceptedRequest.interceptResolutionState();
if (action === InterceptResolutionAction.AlreadyHandled) { if (action === InterceptResolutionAction.AlreadyHandled) {
resolve(); resolve();
return; return;
@ -2492,7 +2489,7 @@ page.on('request', (interceptedRequest) => {
}, 500); }, 500);
}); });
}); });
page.on('request', async (interceptedRequest) => { page.on('request', async interceptedRequest => {
// The interception has not been handled yet. Control will pass through this guard. // The interception has not been handled yet. Control will pass through this guard.
if ( if (
interceptedRequest.interceptResolutionState().action === interceptedRequest.interceptResolutionState().action ===
@ -2534,13 +2531,13 @@ In this example, Legacy Mode prevails and the request is aborted immediately bec
```ts ```ts
// Final outcome: immediate abort() // Final outcome: immediate abort()
page.setRequestInterception(true); page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Legacy Mode: interception is aborted immediately. // Legacy Mode: interception is aborted immediately.
request.abort('failed'); request.abort('failed');
}); });
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Control will never reach this point because the request was already aborted in Legacy Mode // Control will never reach this point because the request was already aborted in Legacy Mode
@ -2554,13 +2551,13 @@ In this example, Legacy Mode prevails and the request is continued because at le
```ts ```ts
// Final outcome: immediate continue() // Final outcome: immediate continue()
page.setRequestInterception(true); page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Cooperative Intercept Mode: votes to abort at priority 0. // Cooperative Intercept Mode: votes to abort at priority 0.
request.abort('failed', 0); request.abort('failed', 0);
}); });
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Control reaches this point because the request was cooperatively aborted which postpones resolution. // Control reaches this point because the request was cooperatively aborted which postpones resolution.
@ -2571,7 +2568,7 @@ page.on('request', (request) => {
// Legacy Mode: intercept continues immediately. // Legacy Mode: intercept continues immediately.
request.continue({}); request.continue({});
}); });
page.on('request', (request) => { page.on('request', request => {
// { action: InterceptResolutionAction.AlreadyHandled }, because continue in Legacy Mode was called // { action: InterceptResolutionAction.AlreadyHandled }, because continue in Legacy Mode was called
console.log(request.interceptResolutionState()); console.log(request.interceptResolutionState());
}); });
@ -2582,19 +2579,19 @@ In this example, Cooperative Intercept Mode is active because all handlers speci
```ts ```ts
// Final outcome: cooperative continue() @ 5 // Final outcome: cooperative continue() @ 5
page.setRequestInterception(true); page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Cooperative Intercept Mode: votes to abort at priority 10 // Cooperative Intercept Mode: votes to abort at priority 10
request.abort('failed', 0); request.abort('failed', 0);
}); });
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Cooperative Intercept Mode: votes to continue at priority 5 // Cooperative Intercept Mode: votes to continue at priority 5
request.continue(request.continueRequestOverrides(), 5); request.continue(request.continueRequestOverrides(), 5);
}); });
page.on('request', (request) => { page.on('request', request => {
// { action: InterceptResolutionAction.Continue, priority: 5 }, because continue @ 5 > abort @ 0 // { action: InterceptResolutionAction.Continue, priority: 5 }, because continue @ 5 > abort @ 0
console.log(request.interceptResolutionState()); console.log(request.interceptResolutionState());
}); });
@ -2605,31 +2602,31 @@ In this example, Cooperative Intercept Mode is active because all handlers speci
```ts ```ts
// Final outcome: cooperative respond() @ 15 // Final outcome: cooperative respond() @ 15
page.setRequestInterception(true); page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Cooperative Intercept Mode: votes to abort at priority 10 // Cooperative Intercept Mode: votes to abort at priority 10
request.abort('failed', 10); request.abort('failed', 10);
}); });
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Cooperative Intercept Mode: votes to continue at priority 15 // Cooperative Intercept Mode: votes to continue at priority 15
request.continue(request.continueRequestOverrides(), 15); request.continue(request.continueRequestOverrides(), 15);
}); });
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Cooperative Intercept Mode: votes to respond at priority 15 // Cooperative Intercept Mode: votes to respond at priority 15
request.respond(request.responseForRequest(), 15); request.respond(request.responseForRequest(), 15);
}); });
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Cooperative Intercept Mode: votes to respond at priority 12 // Cooperative Intercept Mode: votes to respond at priority 12
request.respond(request.responseForRequest(), 12); request.respond(request.responseForRequest(), 12);
}); });
page.on('request', (request) => { page.on('request', request => {
// { action: InterceptResolutionAction.Respond, priority: 15 }, because respond @ 15 > continue @ 15 > respond @ 12 > abort @ 10 // { action: InterceptResolutionAction.Respond, priority: 15 }, because respond @ 15 > continue @ 15 > respond @ 12 > abort @ 10
console.log(request.interceptResolutionState()); console.log(request.interceptResolutionState());
}); });
@ -2656,7 +2653,7 @@ To summarize, reason through whether your use of `request.continue` is just mean
If you are package maintainer and your package uses intercept handlers, you can update your intercept handlers to use Cooperative Intercept Mode. Suppose you have the following existing handler: If you are package maintainer and your package uses intercept handlers, you can update your intercept handlers to use Cooperative Intercept Mode. Suppose you have the following existing handler:
```ts ```ts
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
if ( if (
interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.png') ||
@ -2670,7 +2667,7 @@ page.on('request', (interceptedRequest) => {
To use Cooperative Intercept Mode, upgrade `continue()` and `abort()`: To use Cooperative Intercept Mode, upgrade `continue()` and `abort()`:
```ts ```ts
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
if ( if (
interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.png') ||
@ -2706,7 +2703,7 @@ export const setInterceptResolutionConfig = (priority = 0) =>
* Note that this handler uses `DEFAULT_INTERCEPT_RESOLUTION_PRIORITY` to "pass" on this request. It is important to use * Note that this handler uses `DEFAULT_INTERCEPT_RESOLUTION_PRIORITY` to "pass" on this request. It is important to use
* the default priority when your handler has no opinion on the request and the intent is to continue() by default. * the default priority when your handler has no opinion on the request and the intent is to continue() by default.
*/ */
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
if ( if (
interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.png') ||
@ -2742,9 +2739,9 @@ let _config: Partial<InterceptResolutionConfig> = {};
export const setInterceptResolutionConfig = ( export const setInterceptResolutionConfig = (
config: InterceptResolutionConfig config: InterceptResolutionConfig
) => (_config = { ...DEFAULT_CONFIG, ...config }); ) => (_config = {...DEFAULT_CONFIG, ...config});
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
if ( if (
interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.png') ||
@ -2868,7 +2865,7 @@ To press a special key, like `Control` or `ArrowDown`, use [`keyboard.press`](#k
```js ```js
await page.type('#mytextarea', 'Hello'); // Types instantly await page.type('#mytextarea', 'Hello'); // Types instantly
await page.type('#mytextarea', 'World', { delay: 100 }); // Types slower, like a user await page.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
``` ```
Shortcut for [page.mainFrame().type(selector, text[, options])](#frametypeselector-text-options). Shortcut for [page.mainFrame().type(selector, text[, options])](#frametypeselector-text-options).
@ -2931,7 +2928,7 @@ To pass arguments from node.js to the predicate of `page.waitFor` function:
```js ```js
const selector = '.foo'; const selector = '.foo';
await page.waitFor( await page.waitFor(
(selector) => !!document.querySelector(selector), selector => !!document.querySelector(selector),
{}, {},
selector selector
); );
@ -2970,7 +2967,7 @@ await fileChooser.accept(['/tmp/myfile.pdf']);
- returns: <[Promise]<[Frame]>> Promise which resolves to the matched frame. - returns: <[Promise]<[Frame]>> Promise which resolves to the matched frame.
```js ```js
const frame = await page.waitForFrame(async (frame) => { const frame = await page.waitForFrame(async frame => {
return frame.name() === 'Test'; return frame.name() === 'Test';
}); });
``` ```
@ -2995,7 +2992,7 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
const watchDog = page.waitForFunction('window.innerWidth < 100'); const watchDog = page.waitForFunction('window.innerWidth < 100');
await page.setViewport({ width: 50, height: 50 }); await page.setViewport({width: 50, height: 50});
await watchDog; await watchDog;
await browser.close(); await browser.close();
})(); })();
@ -3006,7 +3003,7 @@ To pass arguments from node.js to the predicate of `page.waitForFunction` functi
```js ```js
const selector = '.foo'; const selector = '.foo';
await page.waitForFunction( await page.waitForFunction(
(selector) => !!document.querySelector(selector), selector => !!document.querySelector(selector),
{}, {},
selector selector
); );
@ -3017,7 +3014,7 @@ The predicate of `page.waitForFunction` can be asynchronous too:
```js ```js
const username = 'github-username'; const username = 'github-username';
await page.waitForFunction( await page.waitForFunction(
async (username) => { async username => {
const githubResponse = await fetch( const githubResponse = await fetch(
`https://api.github.com/users/${username}` `https://api.github.com/users/${username}`
); );
@ -3083,7 +3080,7 @@ page.waitForNetworkIdle(); // The promise resolves after fetch above finishes
```js ```js
const firstRequest = await page.waitForRequest('http://example.com/resource'); const firstRequest = await page.waitForRequest('http://example.com/resource');
const finalRequest = await page.waitForRequest( const finalRequest = await page.waitForRequest(
(request) => request =>
request.url() === 'http://example.com' && request.method() === 'GET' request.url() === 'http://example.com' && request.method() === 'GET'
); );
return firstRequest.url(); return firstRequest.url();
@ -3101,10 +3098,10 @@ const firstResponse = await page.waitForResponse(
'https://example.com/resource' 'https://example.com/resource'
); );
const finalResponse = await page.waitForResponse( const finalResponse = await page.waitForResponse(
(response) => response =>
response.url() === 'https://example.com' && response.status() === 200 response.url() === 'https://example.com' && response.status() === 200
); );
const finalResponse = await page.waitForResponse(async (response) => { const finalResponse = await page.waitForResponse(async response => {
return (await response.text()).includes('<html>'); return (await response.text()).includes('<html>');
}); });
return finalResponse.ok(); return finalResponse.ok();
@ -3228,10 +3225,10 @@ The WebWorker class represents a [WebWorker](https://developer.mozilla.org/en-US
The events `workercreated` and `workerdestroyed` are emitted on the page object to signal the worker lifecycle. The events `workercreated` and `workerdestroyed` are emitted on the page object to signal the worker lifecycle.
```js ```js
page.on('workercreated', (worker) => page.on('workercreated', worker =>
console.log('Worker created: ' + worker.url()) console.log('Worker created: ' + worker.url())
); );
page.on('workerdestroyed', (worker) => page.on('workerdestroyed', worker =>
console.log('Worker destroyed: ' + worker.url()) console.log('Worker destroyed: ' + worker.url())
); );
@ -3435,7 +3432,7 @@ To press a special key, like `Control` or `ArrowDown`, use [`keyboard.press`](#k
```js ```js
await page.keyboard.type('Hello'); // Types instantly await page.keyboard.type('Hello'); // Types instantly
await page.keyboard.type('World', { delay: 100 }); // Types slower, like a user await page.keyboard.type('World', {delay: 100}); // Types slower, like a user
``` ```
> **NOTE** Modifier keys DO NOT affect `keyboard.type`. Holding down `Shift` will not type the text in upper case. > **NOTE** Modifier keys DO NOT affect `keyboard.type`. Holding down `Shift` will not type the text in upper case.
@ -3627,7 +3624,7 @@ await page.mouse.move(
boundingBox.y + boundingBox.height / 2 boundingBox.y + boundingBox.height / 2
); );
await page.mouse.wheel({ deltaY: -100 }); await page.mouse.wheel({deltaY: -100});
``` ```
### class: Touchscreen ### class: Touchscreen
@ -3645,7 +3642,7 @@ Dispatches a `touchstart` and `touchend` event.
You can use [`tracing.start`](#tracingstartoptions) and [`tracing.stop`](#tracingstop) to create a trace file which can be opened in Chrome DevTools or [timeline viewer](https://chromedevtools.github.io/timeline-viewer/). You can use [`tracing.start`](#tracingstartoptions) and [`tracing.stop`](#tracingstop) to create a trace file which can be opened in Chrome DevTools or [timeline viewer](https://chromedevtools.github.io/timeline-viewer/).
```js ```js
await page.tracing.start({ path: 'trace.json' }); await page.tracing.start({path: 'trace.json'});
await page.goto('https://www.google.com'); await page.goto('https://www.google.com');
await page.tracing.stop(); await page.tracing.stop();
``` ```
@ -3708,7 +3705,7 @@ const puppeteer = require('puppeteer');
(async () => { (async () => {
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
page.on('dialog', async (dialog) => { page.on('dialog', async dialog => {
console.log(dialog.message()); console.log(dialog.message());
await dialog.dismiss(); await dialog.dismiss();
await browser.close(); await browser.close();
@ -3804,8 +3801,8 @@ const puppeteer = require('puppeteer');
An example of getting text from an iframe element: An example of getting text from an iframe element:
```js ```js
const frame = page.frames().find((frame) => frame.name() === 'myframe'); const frame = page.frames().find(frame => frame.name() === 'myframe');
const text = await frame.$eval('.selector', (element) => element.textContent); const text = await frame.$eval('.selector', element => element.textContent);
console.log(text); console.log(text);
``` ```
@ -3837,7 +3834,7 @@ If `pageFunction` returns a [Promise], then `frame.$$eval` would wait for the pr
Examples: Examples:
```js ```js
const divsCounts = await frame.$$eval('div', (divs) => divs.length); const divsCounts = await frame.$$eval('div', divs => divs.length);
``` ```
#### frame.$eval(selector, pageFunction[, ...args]) #### frame.$eval(selector, pageFunction[, ...args])
@ -3854,9 +3851,9 @@ If `pageFunction` returns a [Promise], then `frame.$eval` would wait for the pro
Examples: Examples:
```js ```js
const searchValue = await frame.$eval('#search', (el) => el.value); const searchValue = await frame.$eval('#search', el => el.value);
const preloadHref = await frame.$eval('link[rel=preload]', (el) => el.href); const preloadHref = await frame.$eval('link[rel=preload]', el => el.href);
const html = await frame.$eval('.main-container', (e) => e.outerHTML); const html = await frame.$eval('.main-container', e => e.outerHTML);
``` ```
#### frame.$x(expression) #### frame.$x(expression)
@ -3946,7 +3943,7 @@ console.log(await frame.evaluate('1 + 2')); // prints "3"
```js ```js
const bodyHandle = await frame.$('body'); const bodyHandle = await frame.$('body');
const html = await frame.evaluate((body) => body.innerHTML, bodyHandle); const html = await frame.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose(); await bodyHandle.dispose();
``` ```
@ -3978,7 +3975,7 @@ const aHandle = await frame.evaluateHandle('document'); // Handle for the 'docum
```js ```js
const aHandle = await frame.evaluateHandle(() => document.body); const aHandle = await frame.evaluateHandle(() => document.body);
const resultHandle = await frame.evaluateHandle( const resultHandle = await frame.evaluateHandle(
(body) => body.innerHTML, body => body.innerHTML,
aHandle aHandle
); );
console.log(await resultHandle.jsonValue()); console.log(await resultHandle.jsonValue());
@ -4112,7 +4109,7 @@ To press a special key, like `Control` or `ArrowDown`, use [`keyboard.press`](#k
```js ```js
await frame.type('#mytextarea', 'Hello'); // Types instantly await frame.type('#mytextarea', 'Hello'); // Types instantly
await frame.type('#mytextarea', 'World', { delay: 100 }); // Types slower, like a user await frame.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
``` ```
#### frame.url() #### frame.url()
@ -4157,7 +4154,7 @@ To pass arguments from node.js to the predicate of `page.waitFor` function:
```js ```js
const selector = '.foo'; const selector = '.foo';
await page.waitFor( await page.waitFor(
(selector) => !!document.querySelector(selector), selector => !!document.querySelector(selector),
{}, {},
selector selector
); );
@ -4183,7 +4180,7 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
const watchDog = page.mainFrame().waitForFunction('window.innerWidth < 100'); const watchDog = page.mainFrame().waitForFunction('window.innerWidth < 100');
page.setViewport({ width: 50, height: 50 }); page.setViewport({width: 50, height: 50});
await watchDog; await watchDog;
await browser.close(); await browser.close();
})(); })();
@ -4194,7 +4191,7 @@ To pass arguments from node.js to the predicate of `page.waitForFunction` functi
```js ```js
const selector = '.foo'; const selector = '.foo';
await page.waitForFunction( await page.waitForFunction(
(selector) => !!document.querySelector(selector), selector => !!document.querySelector(selector),
{}, {},
selector selector
); );
@ -4395,7 +4392,7 @@ const aHandle = await context.evaluateHandle('1 + 2'); // Handle for the '3' obj
```js ```js
const aHandle = await context.evaluateHandle(() => document.body); const aHandle = await context.evaluateHandle(() => document.body);
const resultHandle = await context.evaluateHandle( const resultHandle = await context.evaluateHandle(
(body) => body.innerHTML, body => body.innerHTML,
aHandle aHandle
); );
console.log(await resultHandle.jsonValue()); // prints body's innerHTML console.log(await resultHandle.jsonValue()); // prints body's innerHTML
@ -4424,7 +4421,7 @@ const mapPrototype = await page.evaluateHandle(() => Map.prototype);
// Query all map instances into an array // Query all map instances into an array
const mapInstances = await page.queryObjects(mapPrototype); const mapInstances = await page.queryObjects(mapPrototype);
// Count amount of map objects in heap // Count amount of map objects in heap
const count = await page.evaluate((maps) => maps.length, mapInstances); const count = await page.evaluate(maps => maps.length, mapInstances);
await mapInstances.dispose(); await mapInstances.dispose();
await mapPrototype.dispose(); await mapPrototype.dispose();
``` ```
@ -4468,7 +4465,7 @@ Examples:
```js ```js
const tweetHandle = await page.$('.tweet .retweets'); const tweetHandle = await page.$('.tweet .retweets');
expect(await tweetHandle.evaluate((node) => node.innerText)).toBe('10'); expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10');
``` ```
#### jsHandle.evaluateHandle(pageFunction[, ...args]) #### jsHandle.evaluateHandle(pageFunction[, ...args])
@ -4500,7 +4497,7 @@ Returns execution context the handle belongs to.
The method returns a map with property names as keys and JSHandle instances for the property values. The method returns a map with property names as keys and JSHandle instances for the property values.
```js ```js
const handle = await page.evaluateHandle(() => ({ window, document })); const handle = await page.evaluateHandle(() => ({window, document}));
const properties = await handle.getProperties(); const properties = await handle.getProperties();
const windowHandle = properties.get('window'); const windowHandle = properties.get('window');
const documentHandle = properties.get('document'); const documentHandle = properties.get('document');
@ -4584,7 +4581,7 @@ Examples:
```js ```js
const feedHandle = await page.$('.feed'); const feedHandle = await page.$('.feed');
expect( expect(
await feedHandle.$$eval('.tweet', (nodes) => nodes.map((n) => n.innerText)) await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText))
).toEqual(['Hello!', 'Hi!']); ).toEqual(['Hello!', 'Hi!']);
``` ```
@ -4603,10 +4600,8 @@ Examples:
```js ```js
const tweetHandle = await page.$('.tweet'); const tweetHandle = await page.$('.tweet');
expect(await tweetHandle.$eval('.like', (node) => node.innerText)).toBe('100'); expect(await tweetHandle.$eval('.like', node => node.innerText)).toBe('100');
expect(await tweetHandle.$eval('.retweets', (node) => node.innerText)).toBe( expect(await tweetHandle.$eval('.retweets', node => node.innerText)).toBe('10');
'10'
);
``` ```
#### elementHandle.$x(expression) #### elementHandle.$x(expression)
@ -4740,7 +4735,7 @@ Examples:
```js ```js
const tweetHandle = await page.$('.tweet .retweets'); const tweetHandle = await page.$('.tweet .retweets');
expect(await tweetHandle.evaluate((node) => node.innerText)).toBe('10'); expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10');
``` ```
#### elementHandle.evaluateHandle(pageFunction[, ...args]) #### elementHandle.evaluateHandle(pageFunction[, ...args])
@ -4873,7 +4868,7 @@ To press a special key, like `Control` or `ArrowDown`, use [`elementHandle.press
```js ```js
await elementHandle.type('Hello'); // Types instantly await elementHandle.type('Hello'); // Types instantly
await elementHandle.type('World', { delay: 100 }); // Types slower, like a user await elementHandle.type('World', {delay: 100}); // Types slower, like a user
``` ```
An example of typing into a text field and then submitting the form: An example of typing into a text field and then submitting the form:
@ -5005,7 +5000,7 @@ your handler has no opinion about it.
```js ```js
await page.setRequestInterception(true); await page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
// Override headers // Override headers
@ -5013,7 +5008,7 @@ page.on('request', (request) => {
foo: 'bar', // set "foo" header foo: 'bar', // set "foo" header
origin: undefined, // remove "origin" header origin: undefined, // remove "origin" header
}); });
request.continue({ headers }); request.continue({headers});
}); });
``` ```
@ -5044,7 +5039,7 @@ The method returns `null` unless this request was failed, as reported by
Example of logging all failed requests: Example of logging all failed requests:
```js ```js
page.on('requestfailed', (request) => { page.on('requestfailed', request => {
console.log(request.url() + ' ' + request.failure().errorText); console.log(request.url() + ' ' + request.failure().errorText);
}); });
``` ```
@ -5091,8 +5086,8 @@ This example will `continue()` a request at a slightly higher priority than the
already handled and is not already being continued. already handled and is not already being continued.
```js ```js
page.on('request', (interceptedRequest) => { page.on('request', interceptedRequest => {
const { action, priority } = interceptedRequest.interceptResolutionState(); const {action, priority} = interceptedRequest.interceptResolutionState();
if (action === InterceptResolutionAction.AlreadyHandled) return; if (action === InterceptResolutionAction.AlreadyHandled) return;
if (action === InterceptResolutionAction.Continue) return; if (action === InterceptResolutionAction.Continue) return;
@ -5180,7 +5175,7 @@ An example of fulfilling all requests with 404 responses:
```js ```js
await page.setRequestInterception(true); await page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
if (request.isInterceptResolutionHandled()) return; if (request.isInterceptResolutionHandled()) return;
request.respond({ request.respond({

View File

@ -22,7 +22,7 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.setRequestInterception(true); await page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
if (request.resourceType() === 'image') { if (request.resourceType() === 'image') {
request.abort(); request.abort();
} else { } else {
@ -30,7 +30,7 @@ const puppeteer = require('puppeteer');
} }
}); });
await page.goto('https://news.google.com/news/'); await page.goto('https://news.google.com/news/');
await page.screenshot({ path: 'news.png', fullPage: true }); await page.screenshot({path: 'news.png', fullPage: true});
await browser.close(); await browser.close();
})(); })();

View File

@ -35,9 +35,9 @@ const firefoxOptions = {
// Extract articles from the page. // Extract articles from the page.
const resultsSelector = '.titlelink'; const resultsSelector = '.titlelink';
const links = await page.evaluate((resultsSelector) => { const links = await page.evaluate(resultsSelector => {
const anchors = Array.from(document.querySelectorAll(resultsSelector)); const anchors = Array.from(document.querySelectorAll(resultsSelector));
return anchors.map((anchor) => { return anchors.map(anchor => {
const title = anchor.textContent.trim(); const title = anchor.textContent.trim();
return `${title} - ${anchor.href}`; return `${title} - ${anchor.href}`;
}); });

View File

@ -23,7 +23,7 @@ const puppeteer = require('puppeteer');
const page = await browser.newPage(); const page = await browser.newPage();
// Define a window.onCustomEvent function on the page. // Define a window.onCustomEvent function on the page.
await page.exposeFunction('onCustomEvent', (e) => { await page.exposeFunction('onCustomEvent', e => {
console.log(`${e.type} fired`, e.detail || ''); console.log(`${e.type} fired`, e.detail || '');
}); });
@ -33,9 +33,9 @@ const puppeteer = require('puppeteer');
* @returns {!Promise} * @returns {!Promise}
*/ */
function listenFor(type) { function listenFor(type) {
return page.evaluateOnNewDocument((type) => { return page.evaluateOnNewDocument(type => {
document.addEventListener(type, (e) => { document.addEventListener(type, e => {
window.onCustomEvent({ type, detail: e.detail }); window.onCustomEvent({type, detail: e.detail});
}); });
}, type); }, type);
} }

View File

@ -37,7 +37,7 @@ function sniffDetector() {
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.evaluateOnNewDocument(sniffDetector); await page.evaluateOnNewDocument(sniffDetector);
await page.goto('https://www.google.com', { waitUntil: 'networkidle2' }); await page.goto('https://www.google.com', {waitUntil: 'networkidle2'});
console.log( console.log(
'Sniffed: ' + 'Sniffed: ' +
(await page.evaluate(() => { (await page.evaluate(() => {

View File

@ -23,7 +23,7 @@ async function attachFrame(frameId, url) {
frame.src = url; frame.src = url;
frame.id = frameId; frame.id = frameId;
document.body.appendChild(frame); document.body.appendChild(frame);
await new Promise((x) => { await new Promise(x => {
return (frame.onload = x); return (frame.onload = x);
}); });
return frame; return frame;
@ -31,7 +31,7 @@ async function attachFrame(frameId, url) {
(async () => { (async () => {
// Launch browser in non-headless mode. // Launch browser in non-headless mode.
const browser = await puppeteer.launch({ headless: false }); const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage(); const page = await browser.newPage();
// Load a page from one origin: // Load a page from one origin:

View File

@ -23,6 +23,6 @@ const puppeteer = require('puppeteer');
const page = await browser.newPage(); const page = await browser.newPage();
await page.emulate(puppeteer.devices['iPhone 6']); await page.emulate(puppeteer.devices['iPhone 6']);
await page.goto('https://www.nytimes.com/'); await page.goto('https://www.nytimes.com/');
await page.screenshot({ path: 'full.png', fullPage: true }); await page.screenshot({path: 'full.png', fullPage: true});
await browser.close(); await browser.close();
})(); })();

View File

@ -22,6 +22,6 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch(); const browser = await puppeteer.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto('http://example.com'); await page.goto('http://example.com');
await page.screenshot({ path: 'example.png' }); await page.screenshot({path: 'example.png'});
await browser.close(); await browser.close();
})(); })();

View File

@ -42,9 +42,9 @@ const puppeteer = require('puppeteer');
await page.waitForSelector(resultsSelector); await page.waitForSelector(resultsSelector);
// Extract the results from the page. // Extract the results from the page.
const links = await page.evaluate((resultsSelector) => { const links = await page.evaluate(resultsSelector => {
const anchors = Array.from(document.querySelectorAll(resultsSelector)); const anchors = Array.from(document.querySelectorAll(resultsSelector));
return anchors.map((anchor) => { return anchors.map(anchor => {
const title = anchor.textContent.split('|')[0].trim(); const title = anchor.textContent.split('|')[0].trim();
return `${title} - ${anchor.href}`; return `${title} - ${anchor.href}`;
}); });

View File

@ -114,8 +114,9 @@
"eslint-plugin-tsdoc": "0.2.16", "eslint-plugin-tsdoc": "0.2.16",
"esprima": "4.0.1", "esprima": "4.0.1",
"expect": "25.2.7", "expect": "25.2.7",
"gts": "3.1.0",
"husky": "8.0.1", "husky": "8.0.1",
"jpeg-js": "0.4.3", "jpeg-js": "0.4.4",
"mime": "3.0.0", "mime": "3.0.0",
"minimist": "1.2.6", "minimist": "1.2.6",
"mocha": "10.0.0", "mocha": "10.0.0",

View File

@ -1,5 +0,0 @@
module.exports = {
semi: true,
trailingComma: 'es5',
singleQuote: true,
};

View File

@ -34,8 +34,8 @@
*/ */
// eslint-disable-next-line import/extensions // eslint-disable-next-line import/extensions
import { PUPPETEER_REVISIONS } from '../src/revisions'; import {PUPPETEER_REVISIONS} from '../src/revisions';
import { execSync } from 'child_process'; import {execSync} from 'child_process';
import packageJson from '../package.json'; import packageJson from '../package.json';

View File

@ -16,7 +16,7 @@
import packageJson from '../package.json'; import packageJson from '../package.json';
const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies }; const allDeps = {...packageJson.dependencies, ...packageJson.devDependencies};
const invalidDeps = new Map<string, string>(); const invalidDeps = new Map<string, string>();
@ -32,7 +32,7 @@ if (invalidDeps.size > 0) {
console.error('Found non-pinned dependencies in package.json:'); console.error('Found non-pinned dependencies in package.json:');
console.log( console.log(
[...invalidDeps.keys()] [...invalidDeps.keys()]
.map((k) => { .map(k => {
return ` ${k}`; return ` ${k}`;
}) })
.join('\n') .join('\n')

View File

@ -1,5 +1,5 @@
import { spawnSync } from 'child_process'; import {spawnSync} from 'child_process';
import { version } from '../package.json'; import {version} from '../package.json';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
const PROJECT_FOLDERS_ROOT = 'test-ts-types'; const PROJECT_FOLDERS_ROOT = 'test-ts-types';
@ -108,7 +108,7 @@ const tar = packPuppeteer();
const tarPath = path.join(process.cwd(), tar); const tarPath = path.join(process.cwd(), tar);
function compileAndCatchErrors(projectLocation: string) { function compileAndCatchErrors(projectLocation: string) {
const { status, stdout, stderr } = spawnSync('npm', ['run', 'compile'], { const {status, stdout, stderr} = spawnSync('npm', ['run', 'compile'], {
cwd: projectLocation, cwd: projectLocation,
encoding: 'utf-8', encoding: 'utf-8',
}); });
@ -146,18 +146,14 @@ function testProject(folder: string) {
// there was no node_modules folder, which is fine. // there was no node_modules folder, which is fine.
} }
console.log('===> Installing Puppeteer from tar file', tarLocation); console.log('===> Installing Puppeteer from tar file', tarLocation);
const { status, stderr, stdout } = spawnSync( const {status, stderr, stdout} = spawnSync('npm', ['install', tarLocation], {
'npm', env: {
['install', tarLocation], ...process.env,
{ PUPPETEER_SKIP_DOWNLOAD: '1',
env: { },
...process.env, cwd: projectLocation,
PUPPETEER_SKIP_DOWNLOAD: '1', encoding: 'utf-8',
}, });
cwd: projectLocation,
encoding: 'utf-8',
}
);
if (status) { if (status) {
console.error( console.error(
@ -171,7 +167,7 @@ function testProject(folder: string) {
const result = compileAndCatchErrors(projectLocation); const result = compileAndCatchErrors(projectLocation);
const expectedErrors = EXPECTED_ERRORS.get(folder) || []; const expectedErrors = EXPECTED_ERRORS.get(folder) || [];
if ( if (
result.tsErrorMesssage.find((line) => { result.tsErrorMesssage.find(line => {
return line.includes('good.ts') || line.includes('good.js'); return line.includes('good.ts') || line.includes('good.js');
}) })
) { ) {
@ -182,12 +178,12 @@ function testProject(folder: string) {
); );
process.exit(1); process.exit(1);
} }
const errorsInTsMessage = result.tsErrorMesssage.filter((line) => { const errorsInTsMessage = result.tsErrorMesssage.filter(line => {
return line.includes('bad.ts') || line.includes('bad.js'); return line.includes('bad.ts') || line.includes('bad.js');
}); });
const expectedErrorsThatHaveOccurred = new Set<string>(); const expectedErrorsThatHaveOccurred = new Set<string>();
const unexpectedErrors = errorsInTsMessage.filter((message) => { const unexpectedErrors = errorsInTsMessage.filter(message => {
const isExpected = expectedErrors.some((expectedError) => { const isExpected = expectedErrors.some(expectedError => {
const isExpected = message.startsWith(expectedError); const isExpected = message.startsWith(expectedError);
if (isExpected) { if (isExpected) {
expectedErrorsThatHaveOccurred.add(expectedError); expectedErrorsThatHaveOccurred.add(expectedError);
@ -205,7 +201,7 @@ function testProject(folder: string) {
); );
process.exit(1); process.exit(1);
} }
expectedErrors.forEach((expected) => { expectedErrors.forEach(expected => {
if (!expectedErrorsThatHaveOccurred.has(expected)) { if (!expectedErrorsThatHaveOccurred.has(expected)) {
console.error( console.error(
`${projectLocation} expected error that was not thrown: ${expected}` `${projectLocation} expected error that was not thrown: ${expected}`
@ -216,6 +212,6 @@ function testProject(folder: string) {
console.log('===> ✅ Type-checked correctly.'); console.log('===> ✅ Type-checked correctly.');
} }
PROJECT_FOLDERS.forEach((folder) => { PROJECT_FOLDERS.forEach(folder => {
testProject(folder); testProject(folder);
}); });

View File

@ -18,14 +18,14 @@ import {
LaunchOptions, LaunchOptions,
BrowserLaunchArgumentOptions, BrowserLaunchArgumentOptions,
} from './node/LaunchOptions.js'; } from './node/LaunchOptions.js';
import { BrowserConnectOptions } from './common/BrowserConnector.js'; import {BrowserConnectOptions} from './common/BrowserConnector.js';
import { Product } from './common/Product.js'; import {Product} from './common/Product.js';
import { Browser } from './common/Browser.js'; import {Browser} from './common/Browser.js';
import { ConnectOptions } from './common/Puppeteer.js'; import {ConnectOptions} from './common/Puppeteer.js';
import { DevicesMap } from './common/DeviceDescriptors.js'; import {DevicesMap} from './common/DeviceDescriptors.js';
import { PuppeteerErrors } from './common/Errors.js'; import {PuppeteerErrors} from './common/Errors.js';
import { PredefinedNetworkConditions } from './common/NetworkConditions.js'; import {PredefinedNetworkConditions} from './common/NetworkConditions.js';
import { CustomQueryHandler } from './common/QueryHandler.js'; import {CustomQueryHandler} from './common/QueryHandler.js';
/* /*
* This file re-exports any APIs that we want to have documentation generated * This file re-exports any APIs that we want to have documentation generated

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { ElementHandle } from './JSHandle.js'; import {ElementHandle} from './JSHandle.js';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
/** /**
* Represents a Node and the properties of it that are relevant to Accessibility. * Represents a Node and the properties of it that are relevant to Accessibility.
@ -181,11 +181,11 @@ export class Accessibility {
public async snapshot( public async snapshot(
options: SnapshotOptions = {} options: SnapshotOptions = {}
): Promise<SerializedAXNode | null> { ): Promise<SerializedAXNode | null> {
const { interestingOnly = true, root = null } = options; const {interestingOnly = true, root = null} = options;
const { nodes } = await this.#client.send('Accessibility.getFullAXTree'); const {nodes} = await this.#client.send('Accessibility.getFullAXTree');
let backendNodeId: number | undefined; let backendNodeId: number | undefined;
if (root) { if (root) {
const { node } = await this.#client.send('DOM.describeNode', { const {node} = await this.#client.send('DOM.describeNode', {
objectId: root._remoteObject.objectId, objectId: root._remoteObject.objectId,
}); });
backendNodeId = node.backendNodeId; backendNodeId = node.backendNodeId;
@ -193,7 +193,7 @@ export class Accessibility {
const defaultRoot = AXNode.createTree(nodes); const defaultRoot = AXNode.createTree(nodes);
let needle: AXNode | null = defaultRoot; let needle: AXNode | null = defaultRoot;
if (backendNodeId) { if (backendNodeId) {
needle = defaultRoot.find((node) => { needle = defaultRoot.find(node => {
return node.payload.backendDOMNodeId === backendNodeId; return node.payload.backendDOMNodeId === backendNodeId;
}); });
if (!needle) { if (!needle) {

View File

@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { InternalQueryHandler } from './QueryHandler.js'; import {InternalQueryHandler} from './QueryHandler.js';
import { ElementHandle, JSHandle } from './JSHandle.js'; import {ElementHandle, JSHandle} from './JSHandle.js';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { DOMWorld, PageBinding, WaitForSelectorOptions } from './DOMWorld.js'; import {DOMWorld, PageBinding, WaitForSelectorOptions} from './DOMWorld.js';
import { assert } from './assert.js'; import {assert} from './assert.js';
async function queryAXTree( async function queryAXTree(
client: CDPSession, client: CDPSession,
@ -27,7 +27,7 @@ async function queryAXTree(
accessibleName?: string, accessibleName?: string,
role?: string role?: string
): Promise<Protocol.Accessibility.AXNode[]> { ): Promise<Protocol.Accessibility.AXNode[]> {
const { nodes } = await client.send('Accessibility.queryAXTree', { const {nodes} = await client.send('Accessibility.queryAXTree', {
objectId: element._remoteObject.objectId, objectId: element._remoteObject.objectId,
accessibleName, accessibleName,
role, role,
@ -47,7 +47,7 @@ const knownAttributes = new Set(['name', 'role']);
const attributeRegexp = const attributeRegexp =
/\[\s*(?<attribute>\w+)\s*=\s*(?<quote>"|')(?<value>\\.|.*?(?=\k<quote>))\k<quote>\s*\]/g; /\[\s*(?<attribute>\w+)\s*=\s*(?<quote>"|')(?<value>\\.|.*?(?=\k<quote>))\k<quote>\s*\]/g;
type ARIAQueryOption = { name?: string; role?: string }; type ARIAQueryOption = {name?: string; role?: string};
function isKnownAttribute( function isKnownAttribute(
attribute: string attribute: string
): attribute is keyof ARIAQueryOption { ): attribute is keyof ARIAQueryOption {
@ -89,7 +89,7 @@ const queryOne = async (
selector: string selector: string
): Promise<ElementHandle | null> => { ): Promise<ElementHandle | null> => {
const exeCtx = element.executionContext(); const exeCtx = element.executionContext();
const { name, role } = parseAriaSelector(selector); const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role); const res = await queryAXTree(exeCtx._client, element, name, role);
if (!res[0] || !res[0].backendDOMNodeId) { if (!res[0] || !res[0].backendDOMNodeId) {
return null; return null;
@ -129,10 +129,10 @@ const queryAll = async (
selector: string selector: string
): Promise<ElementHandle[]> => { ): Promise<ElementHandle[]> => {
const exeCtx = element.executionContext(); const exeCtx = element.executionContext();
const { name, role } = parseAriaSelector(selector); const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role); const res = await queryAXTree(exeCtx._client, element, name, role);
return Promise.all( return Promise.all(
res.map((axNode) => { res.map(axNode => {
return exeCtx._adoptBackendNodeId(axNode.backendDOMNodeId); return exeCtx._adoptBackendNodeId(axNode.backendDOMNodeId);
}) })
); );

View File

@ -14,16 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
import { ChildProcess } from 'child_process'; import {ChildProcess} from 'child_process';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { Connection, ConnectionEmittedEvents } from './Connection.js'; import {Connection, ConnectionEmittedEvents} from './Connection.js';
import { EventEmitter } from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import { waitWithTimeout } from './util.js'; import {waitWithTimeout} from './util.js';
import { Page } from './Page.js'; import {Page} from './Page.js';
import { Viewport } from './PuppeteerViewport.js'; import {Viewport} from './PuppeteerViewport.js';
import { Target } from './Target.js'; import {Target} from './Target.js';
import { TaskQueue } from './TaskQueue.js'; import {TaskQueue} from './TaskQueue.js';
/** /**
* BrowserContext options. * BrowserContext options.
@ -237,7 +237,7 @@ export class Browser extends EventEmitter {
targetFilterCallback, targetFilterCallback,
isPageTargetCallback isPageTargetCallback
); );
await connection.send('Target.setDiscoverTargets', { discover: true }); await connection.send('Target.setDiscoverTargets', {discover: true});
return browser; return browser;
} }
#ignoreHTTPSErrors: boolean; #ignoreHTTPSErrors: boolean;
@ -358,9 +358,9 @@ export class Browser extends EventEmitter {
async createIncognitoBrowserContext( async createIncognitoBrowserContext(
options: BrowserContextOptions = {} options: BrowserContextOptions = {}
): Promise<BrowserContext> { ): Promise<BrowserContext> {
const { proxyServer, proxyBypassList } = options; const {proxyServer, proxyBypassList} = options;
const { browserContextId } = await this.#connection.send( const {browserContextId} = await this.#connection.send(
'Target.createBrowserContext', 'Target.createBrowserContext',
{ {
proxyServer, proxyServer,
@ -408,7 +408,7 @@ export class Browser extends EventEmitter {
event: Protocol.Target.TargetCreatedEvent event: Protocol.Target.TargetCreatedEvent
): Promise<void> { ): Promise<void> {
const targetInfo = event.targetInfo; const targetInfo = event.targetInfo;
const { browserContextId } = targetInfo; const {browserContextId} = targetInfo;
const context = const context =
browserContextId && this.#contexts.has(browserContextId) browserContextId && this.#contexts.has(browserContextId)
? this.#contexts.get(browserContextId) ? this.#contexts.get(browserContextId)
@ -447,7 +447,7 @@ export class Browser extends EventEmitter {
} }
} }
async #targetDestroyed(event: { targetId: string }): Promise<void> { async #targetDestroyed(event: {targetId: string}): Promise<void> {
if (this.#ignoredTargets.has(event.targetId)) { if (this.#ignoredTargets.has(event.targetId)) {
return; return;
} }
@ -522,7 +522,7 @@ export class Browser extends EventEmitter {
* @internal * @internal
*/ */
async _createPageInContext(contextId?: string): Promise<Page> { async _createPageInContext(contextId?: string): Promise<Page> {
const { targetId } = await this.#connection.send('Target.createTarget', { const {targetId} = await this.#connection.send('Target.createTarget', {
url: 'about:blank', url: 'about:blank',
browserContextId: contextId || undefined, browserContextId: contextId || undefined,
}); });
@ -548,7 +548,7 @@ export class Browser extends EventEmitter {
* an array with all the targets in all browser contexts. * an array with all the targets in all browser contexts.
*/ */
targets(): Target[] { targets(): Target[] {
return Array.from(this.#targets.values()).filter((target) => { return Array.from(this.#targets.values()).filter(target => {
return target._isInitialized; return target._isInitialized;
}); });
} }
@ -557,7 +557,7 @@ export class Browser extends EventEmitter {
* The target associated with the browser. * The target associated with the browser.
*/ */
target(): Target { target(): Target {
const browserTarget = this.targets().find((target) => { const browserTarget = this.targets().find(target => {
return target.type() === 'browser'; return target.type() === 'browser';
}); });
if (!browserTarget) { if (!browserTarget) {
@ -584,10 +584,10 @@ export class Browser extends EventEmitter {
predicate: (x: Target) => boolean | Promise<boolean>, predicate: (x: Target) => boolean | Promise<boolean>,
options: WaitForTargetOptions = {} options: WaitForTargetOptions = {}
): Promise<Target> { ): Promise<Target> {
const { timeout = 30000 } = options; const {timeout = 30000} = options;
let resolve: (value: Target | PromiseLike<Target>) => void; let resolve: (value: Target | PromiseLike<Target>) => void;
let isResolved = false; let isResolved = false;
const targetPromise = new Promise<Target>((x) => { const targetPromise = new Promise<Target>(x => {
return (resolve = x); return (resolve = x);
}); });
this.on(BrowserEmittedEvents.TargetCreated, check); this.on(BrowserEmittedEvents.TargetCreated, check);
@ -622,7 +622,7 @@ export class Browser extends EventEmitter {
*/ */
async pages(): Promise<Page[]> { async pages(): Promise<Page[]> {
const contextPages = await Promise.all( const contextPages = await Promise.all(
this.browserContexts().map((context) => { this.browserContexts().map(context => {
return context.pages(); return context.pages();
}) })
); );
@ -762,7 +762,7 @@ export class BrowserContext extends EventEmitter {
* An array of all active targets inside the browser context. * An array of all active targets inside the browser context.
*/ */
targets(): Target[] { targets(): Target[] {
return this.#browser.targets().filter((target) => { return this.#browser.targets().filter(target => {
return target.browserContext() === this; return target.browserContext() === this;
}); });
} }
@ -786,9 +786,9 @@ export class BrowserContext extends EventEmitter {
*/ */
waitForTarget( waitForTarget(
predicate: (x: Target) => boolean | Promise<boolean>, predicate: (x: Target) => boolean | Promise<boolean>,
options: { timeout?: number } = {} options: {timeout?: number} = {}
): Promise<Target> { ): Promise<Target> {
return this.#browser.waitForTarget((target) => { return this.#browser.waitForTarget(target => {
return target.browserContext() === this && predicate(target); return target.browserContext() === this && predicate(target);
}, options); }, options);
} }
@ -803,7 +803,7 @@ export class BrowserContext extends EventEmitter {
async pages(): Promise<Page[]> { async pages(): Promise<Page[]> {
const pages = await Promise.all( const pages = await Promise.all(
this.targets() this.targets()
.filter((target) => { .filter(target => {
return ( return (
target.type() === 'page' || target.type() === 'page' ||
(target.type() === 'other' && (target.type() === 'other' &&
@ -812,7 +812,7 @@ export class BrowserContext extends EventEmitter {
)) ))
); );
}) })
.map((target) => { .map(target => {
return target.page(); return target.page();
}) })
); );
@ -847,7 +847,7 @@ export class BrowserContext extends EventEmitter {
origin: string, origin: string,
permissions: Permission[] permissions: Permission[]
): Promise<void> { ): Promise<void> {
const protocolPermissions = permissions.map((permission) => { const protocolPermissions = permissions.map(permission => {
const protocolPermission = const protocolPermission =
WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission); WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission);
if (!protocolPermission) { if (!protocolPermission) {

View File

@ -14,18 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { debugError, isErrorLike } from './util.js'; import {debugError, isErrorLike} from './util.js';
import { isNode } from '../environment.js'; import {isNode} from '../environment.js';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { import {
Browser, Browser,
IsPageTargetCallback, IsPageTargetCallback,
TargetFilterCallback, TargetFilterCallback,
} from './Browser.js'; } from './Browser.js';
import { Connection } from './Connection.js'; import {Connection} from './Connection.js';
import { ConnectionTransport } from './ConnectionTransport.js'; import {ConnectionTransport} from './ConnectionTransport.js';
import { getFetch } from './fetch.js'; import {getFetch} from './fetch.js';
import { Viewport } from './PuppeteerViewport.js'; import {Viewport} from './PuppeteerViewport.js';
/** /**
* Generic browser options that can be passed when launching any browser or when * Generic browser options that can be passed when launching any browser or when
@ -81,7 +81,7 @@ export async function _connectToBrowser(
browserWSEndpoint, browserWSEndpoint,
browserURL, browserURL,
ignoreHTTPSErrors = false, ignoreHTTPSErrors = false,
defaultViewport = { width: 800, height: 600 }, defaultViewport = {width: 800, height: 600},
transport, transport,
slowMo = 0, slowMo = 0,
targetFilter, targetFilter,
@ -110,7 +110,7 @@ export async function _connectToBrowser(
connection = new Connection(connectionURL, connectionTransport, slowMo); connection = new Connection(connectionURL, connectionTransport, slowMo);
} }
const { browserContextIds } = await connection.send( const {browserContextIds} = await connection.send(
'Target.getBrowserContexts' 'Target.getBrowserContexts'
); );
return Browser._create( return Browser._create(

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ConnectionTransport } from './ConnectionTransport.js'; import {ConnectionTransport} from './ConnectionTransport.js';
export class BrowserWebSocketTransport implements ConnectionTransport { export class BrowserWebSocketTransport implements ConnectionTransport {
static create(url: string): Promise<BrowserWebSocketTransport> { static create(url: string): Promise<BrowserWebSocketTransport> {
@ -33,7 +33,7 @@ export class BrowserWebSocketTransport implements ConnectionTransport {
constructor(ws: WebSocket) { constructor(ws: WebSocket) {
this.#ws = ws; this.#ws = ws;
this.#ws.addEventListener('message', (event) => { this.#ws.addEventListener('message', event => {
if (this.onmessage) { if (this.onmessage) {
this.onmessage.call(null, event.data); this.onmessage.call(null, event.data);
} }

View File

@ -13,21 +13,21 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { assert } from './assert.js'; import {assert} from './assert.js';
import { debug } from './Debug.js'; import {debug} from './Debug.js';
const debugProtocolSend = debug('puppeteer:protocol:SEND ►'); const debugProtocolSend = debug('puppeteer:protocol:SEND ►');
const debugProtocolReceive = debug('puppeteer:protocol:RECV ◀'); const debugProtocolReceive = debug('puppeteer:protocol:RECV ◀');
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js'; import {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
import { ConnectionTransport } from './ConnectionTransport.js'; import {ConnectionTransport} from './ConnectionTransport.js';
import { EventEmitter } from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import { ProtocolError } from './Errors.js'; import {ProtocolError} from './Errors.js';
/** /**
* @public * @public
*/ */
export { ConnectionTransport, ProtocolMapping }; export {ConnectionTransport, ProtocolMapping};
/** /**
* @public * @public
@ -104,7 +104,7 @@ export class Connection extends EventEmitter {
// type-inference. // type-inference.
// So now we check if there are any params or not and deal with them accordingly. // So now we check if there are any params or not and deal with them accordingly.
const params = paramArgs.length ? paramArgs[0] : undefined; const params = paramArgs.length ? paramArgs[0] : undefined;
const id = this._rawSend({ method, params }); const id = this._rawSend({method, params});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.#callbacks.set(id, { this.#callbacks.set(id, {
resolve, resolve,
@ -120,9 +120,7 @@ export class Connection extends EventEmitter {
*/ */
_rawSend(message: Record<string, unknown>): number { _rawSend(message: Record<string, unknown>): number {
const id = ++this.#lastId; const id = ++this.#lastId;
const stringifiedMessage = JSON.stringify( const stringifiedMessage = JSON.stringify(Object.assign({}, message, {id}));
Object.assign({}, message, { id })
);
debugProtocolSend(stringifiedMessage); debugProtocolSend(stringifiedMessage);
this.#transport.send(stringifiedMessage); this.#transport.send(stringifiedMessage);
return id; return id;
@ -130,7 +128,7 @@ export class Connection extends EventEmitter {
async #onMessage(message: string): Promise<void> { async #onMessage(message: string): Promise<void> {
if (this.#delay) { if (this.#delay) {
await new Promise((f) => { await new Promise(f => {
return setTimeout(f, this.#delay); return setTimeout(f, this.#delay);
}); });
} }
@ -219,7 +217,7 @@ export class Connection extends EventEmitter {
async createSession( async createSession(
targetInfo: Protocol.Target.TargetInfo targetInfo: Protocol.Target.TargetInfo
): Promise<CDPSession> { ): Promise<CDPSession> {
const { sessionId } = await this.send('Target.attachToTarget', { const {sessionId} = await this.send('Target.attachToTarget', {
targetId: targetInfo.targetId, targetId: targetInfo.targetId,
flatten: true, flatten: true,
}); });
@ -238,7 +236,7 @@ export interface CDPSessionOnMessageObject {
id?: number; id?: number;
method: string; method: string;
params: Record<string, unknown>; params: Record<string, unknown>;
error: { message: string; data: any; code: number }; error: {message: string; data: any; code: number};
result?: any; result?: any;
} }
@ -394,7 +392,7 @@ export class CDPSession extends EventEmitter {
function createProtocolError( function createProtocolError(
error: ProtocolError, error: ProtocolError,
method: string, method: string,
object: { error: { message: string; data: any; code: number } } object: {error: {message: string; data: any; code: number}}
): Error { ): Error {
let message = `Protocol error (${method}): ${object.error.message}`; let message = `Protocol error (${method}): ${object.error.message}`;
if ('data' in object.error) { if ('data' in object.error) {

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { JSHandle } from './JSHandle.js'; import {JSHandle} from './JSHandle.js';
/** /**
* @public * @public

View File

@ -14,22 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { assert } from './assert.js'; import {assert} from './assert.js';
import { import {addEventListener, debugError, PuppeteerEventListener} from './util.js';
addEventListener, import {Protocol} from 'devtools-protocol';
debugError, import {CDPSession} from './Connection.js';
PuppeteerEventListener,
} from './util.js';
import { Protocol } from 'devtools-protocol';
import { CDPSession } from './Connection.js';
import { EVALUATION_SCRIPT_URL } from './ExecutionContext.js'; import {EVALUATION_SCRIPT_URL} from './ExecutionContext.js';
import { removeEventListeners } from './util.js'; import {removeEventListeners} from './util.js';
/** /**
* @internal * @internal
*/ */
export { PuppeteerEventListener }; export {PuppeteerEventListener};
/** /**
* The CoverageEntry class represents one entry of the coverage report. * The CoverageEntry class represents one entry of the coverage report.
@ -47,7 +43,7 @@ export interface CoverageEntry {
/** /**
* The covered range as start and end positions. * The covered range as start and end positions.
*/ */
ranges: Array<{ start: number; end: number }>; ranges: Array<{start: number; end: number}>;
} }
/** /**
@ -239,7 +235,7 @@ export class JSCoverage {
detailed: true, detailed: true,
}), }),
this.#client.send('Debugger.enable'), this.#client.send('Debugger.enable'),
this.#client.send('Debugger.setSkipAllPauses', { skip: true }), this.#client.send('Debugger.setSkipAllPauses', {skip: true}),
]); ]);
} }
@ -305,9 +301,9 @@ export class JSCoverage {
} }
const ranges = convertToDisjointRanges(flattenRanges); const ranges = convertToDisjointRanges(flattenRanges);
if (!this.#includeRawScriptCoverage) { if (!this.#includeRawScriptCoverage) {
coverage.push({ url, ranges, text }); coverage.push({url, ranges, text});
} else { } else {
coverage.push({ url, ranges, text, rawScriptCoverage: entry }); coverage.push({url, ranges, text, rawScriptCoverage: entry});
} }
} }
return coverage; return coverage;
@ -329,9 +325,9 @@ export class CSSCoverage {
this.#client = client; this.#client = client;
} }
async start(options: { resetOnNavigation?: boolean } = {}): Promise<void> { async start(options: {resetOnNavigation?: boolean} = {}): Promise<void> {
assert(!this.#enabled, 'CSSCoverage is already enabled'); assert(!this.#enabled, 'CSSCoverage is already enabled');
const { resetOnNavigation = true } = options; const {resetOnNavigation = true} = options;
this.#resetOnNavigation = resetOnNavigation; this.#resetOnNavigation = resetOnNavigation;
this.#enabled = true; this.#enabled = true;
this.#stylesheetURLs.clear(); this.#stylesheetURLs.clear();
@ -417,7 +413,7 @@ export class CSSCoverage {
const ranges = convertToDisjointRanges( const ranges = convertToDisjointRanges(
styleSheetIdToCoverage.get(styleSheetId) || [] styleSheetIdToCoverage.get(styleSheetId) || []
); );
coverage.push({ url, ranges, text }); coverage.push({url, ranges, text});
} }
return coverage; return coverage;
@ -425,12 +421,12 @@ export class CSSCoverage {
} }
function convertToDisjointRanges( function convertToDisjointRanges(
nestedRanges: Array<{ startOffset: number; endOffset: number; count: number }> nestedRanges: Array<{startOffset: number; endOffset: number; count: number}>
): Array<{ start: number; end: number }> { ): Array<{start: number; end: number}> {
const points = []; const points = [];
for (const range of nestedRanges) { for (const range of nestedRanges) {
points.push({ offset: range.startOffset, type: 0, range }); points.push({offset: range.startOffset, type: 0, range});
points.push({ offset: range.endOffset, type: 1, range }); points.push({offset: range.endOffset, type: 1, range});
} }
// Sort points to form a valid parenthesis sequence. // Sort points to form a valid parenthesis sequence.
points.sort((a, b) => { points.sort((a, b) => {
@ -469,7 +465,7 @@ function convertToDisjointRanges(
if (lastResult && lastResult.end === lastOffset) { if (lastResult && lastResult.end === lastOffset) {
lastResult.end = point.offset; lastResult.end = point.offset;
} else { } else {
results.push({ start: lastOffset, end: point.offset }); results.push({start: lastOffset, end: point.offset});
} }
} }
lastOffset = point.offset; lastOffset = point.offset;
@ -480,7 +476,7 @@ function convertToDisjointRanges(
} }
} }
// Filter out empty ranges. // Filter out empty ranges.
return results.filter((range) => { return results.filter(range => {
return range.end - range.start > 1; return range.end - range.start > 1;
}); });
} }

View File

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { TimeoutError } from './Errors.js'; import {TimeoutError} from './Errors.js';
import { import {
EvaluateFn, EvaluateFn,
EvaluateFnReturnType, EvaluateFnReturnType,
@ -26,8 +26,8 @@ import {
UnwrapPromiseLike, UnwrapPromiseLike,
WrapElementHandle, WrapElementHandle,
} from './EvalTypes.js'; } from './EvalTypes.js';
import { ExecutionContext } from './ExecutionContext.js'; import {ExecutionContext} from './ExecutionContext.js';
import { Frame, FrameManager } from './FrameManager.js'; import {Frame, FrameManager} from './FrameManager.js';
import { import {
debugError, debugError,
isNumber, isNumber,
@ -35,14 +35,11 @@ import {
makePredicateString, makePredicateString,
pageBindingInitString, pageBindingInitString,
} from './util.js'; } from './util.js';
import { MouseButton } from './Input.js'; import {MouseButton} from './Input.js';
import { ElementHandle, JSHandle } from './JSHandle.js'; import {ElementHandle, JSHandle} from './JSHandle.js';
import { import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
LifecycleWatcher, import {_getQueryHandlerAndSelector} from './QueryHandler.js';
PuppeteerLifeCycleEvent, import {TimeoutSettings} from './TimeoutSettings.js';
} from './LifecycleWatcher.js';
import { _getQueryHandlerAndSelector } from './QueryHandler.js';
import { TimeoutSettings } from './TimeoutSettings.js';
// predicateQueryHandler and checkWaitForOptions are declared here so that // predicateQueryHandler and checkWaitForOptions are declared here so that
// TypeScript knows about them when used in the predicate function below. // TypeScript knows about them when used in the predicate function below.
@ -149,7 +146,7 @@ export class DOMWorld {
} }
} else { } else {
this.#documentPromise = null; this.#documentPromise = null;
this.#contextPromise = new Promise((fulfill) => { this.#contextPromise = new Promise(fulfill => {
this.#contextResolveCallback = fulfill; this.#contextResolveCallback = fulfill;
}); });
} }
@ -221,7 +218,7 @@ export class DOMWorld {
if (this.#documentPromise) { if (this.#documentPromise) {
return this.#documentPromise; return this.#documentPromise;
} }
this.#documentPromise = this.executionContext().then(async (context) => { this.#documentPromise = this.executionContext().then(async context => {
const document = await context.evaluateHandle('document'); const document = await context.evaluateHandle('document');
const element = document.asElement(); const element = document.asElement();
if (element === null) { if (element === null) {
@ -301,7 +298,7 @@ export class DOMWorld {
} = options; } = options;
// We rely upon the fact that document.open() will reset frame lifecycle with "init" // We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658 // lifecycle event. @see https://crrev.com/608658
await this.evaluate<(x: string) => void>((html) => { await this.evaluate<(x: string) => void>(html => {
document.open(); document.open();
document.write(html); document.write(html);
document.close(); document.close();
@ -445,7 +442,7 @@ export class DOMWorld {
script.id = id; script.id = id;
} }
let error = null; let error = null;
script.onerror = (e) => { script.onerror = e => {
return (error = e); return (error = e);
}; };
document.head.appendChild(script); document.head.appendChild(script);
@ -471,7 +468,7 @@ export class DOMWorld {
path?: string; path?: string;
content?: string; content?: string;
}): Promise<ElementHandle> { }): Promise<ElementHandle> {
const { url = null, path = null, content = null } = options; const {url = null, path = null, content = null} = options;
if (url !== null) { if (url !== null) {
try { try {
const context = await this.executionContext(); const context = await this.executionContext();
@ -553,7 +550,7 @@ export class DOMWorld {
async click( async click(
selector: string, selector: string,
options: { delay?: number; button?: MouseButton; clickCount?: number } options: {delay?: number; button?: MouseButton; clickCount?: number}
): Promise<void> { ): Promise<void> {
const handle = await this.$(selector); const handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`); assert(handle, `No element found for selector: ${selector}`);
@ -593,7 +590,7 @@ export class DOMWorld {
async type( async type(
selector: string, selector: string,
text: string, text: string,
options?: { delay: number } options?: {delay: number}
): Promise<void> { ): Promise<void> {
const handle = await this.$(selector); const handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`); assert(handle, `No element found for selector: ${selector}`);
@ -605,7 +602,7 @@ export class DOMWorld {
selector: string, selector: string,
options: WaitForSelectorOptions options: WaitForSelectorOptions
): Promise<ElementHandle | null> { ): Promise<ElementHandle | null> {
const { updatedSelector, queryHandler } = const {updatedSelector, queryHandler} =
_getQueryHandlerAndSelector(selector); _getQueryHandlerAndSelector(selector);
assert(queryHandler.waitFor, 'Query handler does not support waiting'); assert(queryHandler.waitFor, 'Query handler does not support waiting');
return queryHandler.waitFor(this, updatedSelector, options); return queryHandler.waitFor(this, updatedSelector, options);
@ -677,7 +674,7 @@ export class DOMWorld {
#onBindingCalled = async ( #onBindingCalled = async (
event: Protocol.Runtime.BindingCalledEvent event: Protocol.Runtime.BindingCalledEvent
): Promise<void> => { ): Promise<void> => {
let payload: { type: string; name: string; seq: number; args: unknown[] }; let payload: {type: string; name: string; seq: number; args: unknown[]};
if (!this._hasContext()) { if (!this._hasContext()) {
return; return;
} }
@ -689,7 +686,7 @@ export class DOMWorld {
// called before our wrapper was initialized. // called before our wrapper was initialized.
return; return;
} }
const { type, name, seq, args } = payload; const {type, name, seq, args} = payload;
if ( if (
type !== 'internal' || type !== 'internal' ||
!this.#ctxBindings.has( !this.#ctxBindings.has(
@ -827,10 +824,10 @@ export class DOMWorld {
waitForFunction( waitForFunction(
pageFunction: Function | string, pageFunction: Function | string,
options: { polling?: string | number; timeout?: number } = {}, options: {polling?: string | number; timeout?: number} = {},
...args: SerializableOrJSHandle[] ...args: SerializableOrJSHandle[]
): Promise<JSHandle> { ): Promise<JSHandle> {
const { polling = 'raf', timeout = this.#timeoutSettings.timeout() } = const {polling = 'raf', timeout = this.#timeoutSettings.timeout()} =
options; options;
const waitTaskOptions: WaitTaskOptions = { const waitTaskOptions: WaitTaskOptions = {
domWorld: this, domWorld: this,
@ -992,7 +989,7 @@ export class WaitTask {
if ( if (
!error && !error &&
(await this.#domWorld (await this.#domWorld
.evaluate((s) => { .evaluate(s => {
return !s; return !s;
}, success) }, success)
.catch(() => { .catch(() => {
@ -1085,7 +1082,7 @@ async function waitForPredicatePageFunction(
} }
let fulfill = (_?: unknown) => {}; let fulfill = (_?: unknown) => {};
const result = new Promise((x) => { const result = new Promise(x => {
return (fulfill = x); return (fulfill = x);
}); });
const observer = new MutationObserver(async () => { const observer = new MutationObserver(async () => {
@ -1114,7 +1111,7 @@ async function waitForPredicatePageFunction(
async function pollRaf(): Promise<unknown> { async function pollRaf(): Promise<unknown> {
let fulfill = (_?: unknown): void => {}; let fulfill = (_?: unknown): void => {};
const result = new Promise((x) => { const result = new Promise(x => {
return (fulfill = x); return (fulfill = x);
}); });
await onRaf(); await onRaf();
@ -1138,7 +1135,7 @@ async function waitForPredicatePageFunction(
async function pollInterval(pollInterval: number): Promise<unknown> { async function pollInterval(pollInterval: number): Promise<unknown> {
let fulfill = (_?: unknown): void => {}; let fulfill = (_?: unknown): void => {};
const result = new Promise((x) => { const result = new Promise(x => {
return (fulfill = x); return (fulfill = x);
}); });
await onTimeout(); await onTimeout();

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { isNode } from '../environment.js'; import {isNode} from '../environment.js';
declare global { declare global {
// eslint-disable-next-line no-var // eslint-disable-next-line no-var

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { assert } from './assert.js'; import {assert} from './assert.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
/** /**
* Dialog instances are dispatched by the {@link Page} via the `dialog` event. * Dialog instances are dispatched by the {@link Page} via the `dialog` event.

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { Viewport } from './PuppeteerViewport.js'; import {Viewport} from './PuppeteerViewport.js';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
export class EmulationManager { export class EmulationManager {
#client: CDPSession; #client: CDPSession;
@ -33,8 +33,8 @@ export class EmulationManager {
const deviceScaleFactor = viewport.deviceScaleFactor || 1; const deviceScaleFactor = viewport.deviceScaleFactor || 1;
const screenOrientation: Protocol.Emulation.ScreenOrientation = const screenOrientation: Protocol.Emulation.ScreenOrientation =
viewport.isLandscape viewport.isLandscape
? { angle: 90, type: 'landscapePrimary' } ? {angle: 90, type: 'landscapePrimary'}
: { angle: 0, type: 'portraitPrimary' }; : {angle: 0, type: 'portraitPrimary'};
const hasTouch = viewport.hasTouch || false; const hasTouch = viewport.hasTouch || false;
await Promise.all([ await Promise.all([

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { JSHandle, ElementHandle } from './JSHandle.js'; import {JSHandle, ElementHandle} from './JSHandle.js';
/** /**
* @public * @public

View File

@ -7,7 +7,7 @@ import mitt, {
/** /**
* @public * @public
*/ */
export { EventType, Handler }; export {EventType, Handler};
/** /**
* @public * @public
@ -110,7 +110,7 @@ export class EventEmitter implements CommonEventEmitter {
* @returns `this` to enable you to chain method calls. * @returns `this` to enable you to chain method calls.
*/ */
once(event: EventType, handler: Handler): EventEmitter { once(event: EventType, handler: Handler): EventEmitter {
const onceHandler: Handler = (eventData) => { const onceHandler: Handler = eventData => {
handler(eventData); handler(eventData);
this.off(event, onceHandler); this.off(event, onceHandler);
}; };

View File

@ -14,18 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { DOMWorld } from './DOMWorld.js'; import {DOMWorld} from './DOMWorld.js';
import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes.js'; import {EvaluateHandleFn, SerializableOrJSHandle} from './EvalTypes.js';
import { Frame } from './FrameManager.js'; import {Frame} from './FrameManager.js';
import { import {getExceptionMessage, isString, valueFromRemoteObject} from './util.js';
getExceptionMessage, import {ElementHandle, JSHandle, _createJSHandle} from './JSHandle.js';
isString,
valueFromRemoteObject,
} from './util.js';
import { ElementHandle, JSHandle, _createJSHandle } from './JSHandle.js';
/** /**
* @public * @public
@ -208,7 +204,7 @@ export class ExecutionContext {
? expression ? expression
: expression + '\n' + suffix; : expression + '\n' + suffix;
const { exceptionDetails, result: remoteObject } = await this._client const {exceptionDetails, result: remoteObject} = await this._client
.send('Runtime.evaluate', { .send('Runtime.evaluate', {
expression: expressionWithSourceUrl, expression: expressionWithSourceUrl,
contextId, contextId,
@ -273,7 +269,7 @@ export class ExecutionContext {
} }
throw error; throw error;
} }
const { exceptionDetails, result: remoteObject } = const {exceptionDetails, result: remoteObject} =
await callFunctionOnPromise.catch(rewriteError); await callFunctionOnPromise.catch(rewriteError);
if (exceptionDetails) { if (exceptionDetails) {
throw new Error( throw new Error(
@ -290,19 +286,19 @@ export class ExecutionContext {
): Protocol.Runtime.CallArgument { ): Protocol.Runtime.CallArgument {
if (typeof arg === 'bigint') { if (typeof arg === 'bigint') {
// eslint-disable-line valid-typeof // eslint-disable-line valid-typeof
return { unserializableValue: `${arg.toString()}n` }; return {unserializableValue: `${arg.toString()}n`};
} }
if (Object.is(arg, -0)) { if (Object.is(arg, -0)) {
return { unserializableValue: '-0' }; return {unserializableValue: '-0'};
} }
if (Object.is(arg, Infinity)) { if (Object.is(arg, Infinity)) {
return { unserializableValue: 'Infinity' }; return {unserializableValue: 'Infinity'};
} }
if (Object.is(arg, -Infinity)) { if (Object.is(arg, -Infinity)) {
return { unserializableValue: '-Infinity' }; return {unserializableValue: '-Infinity'};
} }
if (Object.is(arg, NaN)) { if (Object.is(arg, NaN)) {
return { unserializableValue: 'NaN' }; return {unserializableValue: 'NaN'};
} }
const objectHandle = arg && arg instanceof JSHandle ? arg : null; const objectHandle = arg && arg instanceof JSHandle ? arg : null;
if (objectHandle) { if (objectHandle) {
@ -320,19 +316,19 @@ export class ExecutionContext {
}; };
} }
if (!objectHandle._remoteObject.objectId) { if (!objectHandle._remoteObject.objectId) {
return { value: objectHandle._remoteObject.value }; return {value: objectHandle._remoteObject.value};
} }
return { objectId: objectHandle._remoteObject.objectId }; return {objectId: objectHandle._remoteObject.objectId};
} }
return { value: arg }; return {value: arg};
} }
function rewriteError(error: Error): Protocol.Runtime.EvaluateResponse { function rewriteError(error: Error): Protocol.Runtime.EvaluateResponse {
if (error.message.includes('Object reference chain is too long')) { if (error.message.includes('Object reference chain is too long')) {
return { result: { type: 'undefined' } }; return {result: {type: 'undefined'}};
} }
if (error.message.includes("Object couldn't be returned by value")) { if (error.message.includes("Object couldn't be returned by value")) {
return { result: { type: 'undefined' } }; return {result: {type: 'undefined'}};
} }
if ( if (
@ -387,7 +383,7 @@ export class ExecutionContext {
async _adoptBackendNodeId( async _adoptBackendNodeId(
backendNodeId?: Protocol.DOM.BackendNodeId backendNodeId?: Protocol.DOM.BackendNodeId
): Promise<ElementHandle> { ): Promise<ElementHandle> {
const { object } = await this._client.send('DOM.resolveNode', { const {object} = await this._client.send('DOM.resolveNode', {
backendNodeId: backendNodeId, backendNodeId: backendNodeId,
executionContextId: this._contextId, executionContextId: this._contextId,
}); });

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { ElementHandle } from './JSHandle.js'; import {ElementHandle} from './JSHandle.js';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { assert } from './assert.js'; import {assert} from './assert.js';
/** /**
* File choosers let you react to the page requesting for a file. * File choosers let you react to the page requesting for a file.

View File

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { CDPSession, Connection } from './Connection.js'; import {CDPSession, Connection} from './Connection.js';
import { DOMWorld, WaitForSelectorOptions } from './DOMWorld.js'; import {DOMWorld, WaitForSelectorOptions} from './DOMWorld.js';
import { import {
EvaluateFn, EvaluateFn,
EvaluateFnReturnType, EvaluateFnReturnType,
@ -26,19 +26,16 @@ import {
UnwrapPromiseLike, UnwrapPromiseLike,
WrapElementHandle, WrapElementHandle,
} from './EvalTypes.js'; } from './EvalTypes.js';
import { EventEmitter } from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import { EVALUATION_SCRIPT_URL, ExecutionContext } from './ExecutionContext.js'; import {EVALUATION_SCRIPT_URL, ExecutionContext} from './ExecutionContext.js';
import { HTTPResponse } from './HTTPResponse.js'; import {HTTPResponse} from './HTTPResponse.js';
import { MouseButton } from './Input.js'; import {MouseButton} from './Input.js';
import { ElementHandle, JSHandle } from './JSHandle.js'; import {ElementHandle, JSHandle} from './JSHandle.js';
import { import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
LifecycleWatcher, import {NetworkManager} from './NetworkManager.js';
PuppeteerLifeCycleEvent, import {Page} from './Page.js';
} from './LifecycleWatcher.js'; import {TimeoutSettings} from './TimeoutSettings.js';
import { NetworkManager } from './NetworkManager.js'; import {debugError, isErrorLike, isNumber, isString} from './util.js';
import { Page } from './Page.js';
import { TimeoutSettings } from './TimeoutSettings.js';
import { debugError, isErrorLike, isNumber, isString } from './util.js';
const UTILITY_WORLD_NAME = '__puppeteer_utility_world__'; const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';
const xPathPattern = /^\(\/\/[^\)]+\)|^\/\//; const xPathPattern = /^\(\/\/[^\)]+\)|^\/\//;
@ -104,13 +101,13 @@ export class FrameManager extends EventEmitter {
} }
private setupEventListeners(session: CDPSession) { private setupEventListeners(session: CDPSession) {
session.on('Page.frameAttached', (event) => { session.on('Page.frameAttached', event => {
this.#onFrameAttached(session, event.frameId, event.parentFrameId); this.#onFrameAttached(session, event.frameId, event.parentFrameId);
}); });
session.on('Page.frameNavigated', (event) => { session.on('Page.frameNavigated', event => {
this.#onFrameNavigated(event.frame); this.#onFrameNavigated(event.frame);
}); });
session.on('Page.navigatedWithinDocument', (event) => { session.on('Page.navigatedWithinDocument', event => {
this.#onFrameNavigatedWithinDocument(event.frameId, event.url); this.#onFrameNavigatedWithinDocument(event.frameId, event.url);
}); });
session.on( session.on(
@ -122,28 +119,28 @@ export class FrameManager extends EventEmitter {
); );
} }
); );
session.on('Page.frameStartedLoading', (event) => { session.on('Page.frameStartedLoading', event => {
this.#onFrameStartedLoading(event.frameId); this.#onFrameStartedLoading(event.frameId);
}); });
session.on('Page.frameStoppedLoading', (event) => { session.on('Page.frameStoppedLoading', event => {
this.#onFrameStoppedLoading(event.frameId); this.#onFrameStoppedLoading(event.frameId);
}); });
session.on('Runtime.executionContextCreated', (event) => { session.on('Runtime.executionContextCreated', event => {
this.#onExecutionContextCreated(event.context, session); this.#onExecutionContextCreated(event.context, session);
}); });
session.on('Runtime.executionContextDestroyed', (event) => { session.on('Runtime.executionContextDestroyed', event => {
this.#onExecutionContextDestroyed(event.executionContextId, session); this.#onExecutionContextDestroyed(event.executionContextId, session);
}); });
session.on('Runtime.executionContextsCleared', () => { session.on('Runtime.executionContextsCleared', () => {
this.#onExecutionContextsCleared(session); this.#onExecutionContextsCleared(session);
}); });
session.on('Page.lifecycleEvent', (event) => { session.on('Page.lifecycleEvent', event => {
this.#onLifecycleEvent(event); this.#onLifecycleEvent(event);
}); });
session.on('Target.attachedToTarget', async (event) => { session.on('Target.attachedToTarget', async event => {
this.#onAttachedToTarget(event); this.#onAttachedToTarget(event);
}); });
session.on('Target.detachedFromTarget', async (event) => { session.on('Target.detachedFromTarget', async event => {
this.#onDetachedFromTarget(event); this.#onDetachedFromTarget(event);
}); });
} }
@ -162,10 +159,10 @@ export class FrameManager extends EventEmitter {
: Promise.resolve(), : Promise.resolve(),
]); ]);
const { frameTree } = result[1]; const {frameTree} = result[1];
this.#handleFrameTree(client, frameTree); this.#handleFrameTree(client, frameTree);
await Promise.all([ await Promise.all([
client.send('Page.setLifecycleEventsEnabled', { enabled: true }), client.send('Page.setLifecycleEventsEnabled', {enabled: true}),
client.send('Runtime.enable').then(() => { client.send('Runtime.enable').then(() => {
return this._ensureIsolatedWorld(client, UTILITY_WORLD_NAME); return this._ensureIsolatedWorld(client, UTILITY_WORLD_NAME);
}), }),
@ -443,10 +440,10 @@ export class FrameManager extends EventEmitter {
// Frames might be removed before we send this. // Frames might be removed before we send this.
await Promise.all( await Promise.all(
this.frames() this.frames()
.filter((frame) => { .filter(frame => {
return frame._client() === session; return frame._client() === session;
}) })
.map((frame) => { .map(frame => {
return session return session
.send('Page.createIsolatedWorld', { .send('Page.createIsolatedWorld', {
frameId: frame._id, frameId: frame._id,
@ -489,7 +486,7 @@ export class FrameManager extends EventEmitter {
contextPayload: Protocol.Runtime.ExecutionContextDescription, contextPayload: Protocol.Runtime.ExecutionContextDescription,
session: CDPSession session: CDPSession
): void { ): void {
const auxData = contextPayload.auxData as { frameId?: string } | undefined; const auxData = contextPayload.auxData as {frameId?: string} | undefined;
const frameId = auxData && auxData.frameId; const frameId = auxData && auxData.frameId;
const frame = const frame =
typeof frameId === 'string' ? this.#frames.get(frameId) : undefined; typeof frameId === 'string' ? this.#frames.get(frameId) : undefined;
@ -1236,7 +1233,7 @@ export class Frame {
async type( async type(
selector: string, selector: string,
text: string, text: string,
options?: { delay: number } options?: {delay: number}
): Promise<void> { ): Promise<void> {
return this._mainWorld.type(selector, text, options); return this._mainWorld.type(selector, text, options);
} }
@ -1283,7 +1280,7 @@ export class Frame {
return this.waitForSelector(string, options); return this.waitForSelector(string, options);
} }
if (isNumber(selectorOrFunctionOrTimeout)) { if (isNumber(selectorOrFunctionOrTimeout)) {
return new Promise((fulfill) => { return new Promise(fulfill => {
return setTimeout(fulfill, selectorOrFunctionOrTimeout); return setTimeout(fulfill, selectorOrFunctionOrTimeout);
}); });
} }
@ -1320,7 +1317,7 @@ export class Frame {
* @param milliseconds - the number of milliseconds to wait. * @param milliseconds - the number of milliseconds to wait.
*/ */
waitForTimeout(milliseconds: number): Promise<void> { waitForTimeout(milliseconds: number): Promise<void> {
return new Promise((resolve) => { return new Promise(resolve => {
setTimeout(resolve, milliseconds); setTimeout(resolve, milliseconds);
}); });
} }

View File

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js'; import {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { ProtocolError } from './Errors.js'; import {ProtocolError} from './Errors.js';
import { EventEmitter } from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import { Frame } from './FrameManager.js'; import {Frame} from './FrameManager.js';
import { debugError, isString } from './util.js'; import {debugError, isString} from './util.js';
import { HTTPResponse } from './HTTPResponse.js'; import {HTTPResponse} from './HTTPResponse.js';
/** /**
* @public * @public
@ -236,12 +236,12 @@ export class HTTPRequest {
*/ */
interceptResolutionState(): InterceptResolutionState { interceptResolutionState(): InterceptResolutionState {
if (!this.#allowInterception) { if (!this.#allowInterception) {
return { action: InterceptResolutionAction.Disabled }; return {action: InterceptResolutionAction.Disabled};
} }
if (this.#interceptionHandled) { if (this.#interceptionHandled) {
return { action: InterceptResolutionAction.AlreadyHandled }; return {action: InterceptResolutionAction.AlreadyHandled};
} }
return { ...this.#interceptResolutionState }; return {...this.#interceptResolutionState};
} }
/** /**
@ -272,7 +272,7 @@ export class HTTPRequest {
await this.#interceptHandlers.reduce((promiseChain, interceptAction) => { await this.#interceptHandlers.reduce((promiseChain, interceptAction) => {
return promiseChain.then(interceptAction); return promiseChain.then(interceptAction);
}, Promise.resolve()); }, Promise.resolve());
const { action } = this.interceptResolutionState(); const {action} = this.interceptResolutionState();
switch (action) { switch (action) {
case 'abort': case 'abort':
return this.#abort(this.#abortErrorReason); return this.#abort(this.#abortErrorReason);
@ -397,7 +397,7 @@ export class HTTPRequest {
* message, e.g. `net::ERR_FAILED`. It is not guaranteed that there will be * message, e.g. `net::ERR_FAILED`. It is not guaranteed that there will be
* failure text if the request fails. * failure text if the request fails.
*/ */
failure(): { errorText: string } | null { failure(): {errorText: string} | null {
if (!this._failureText) { if (!this._failureText) {
return null; return null;
} }
@ -472,7 +472,7 @@ export class HTTPRequest {
} }
async #continue(overrides: ContinueRequestOverrides = {}): Promise<void> { async #continue(overrides: ContinueRequestOverrides = {}): Promise<void> {
const { url, method, postData, headers } = overrides; const {url, method, postData, headers} = overrides;
this.#interceptionHandled = true; this.#interceptionHandled = true;
const postDataBinaryBase64 = postData const postDataBinaryBase64 = postData
@ -492,7 +492,7 @@ export class HTTPRequest {
postData: postDataBinaryBase64, postData: postDataBinaryBase64,
headers: headers ? headersArray(headers) : undefined, headers: headers ? headersArray(headers) : undefined,
}) })
.catch((error) => { .catch(error => {
this.#interceptionHandled = false; this.#interceptionHandled = false;
return handleError(error); return handleError(error);
}); });
@ -575,7 +575,7 @@ export class HTTPRequest {
const value = response.headers[header]; const value = response.headers[header];
responseHeaders[header.toLowerCase()] = Array.isArray(value) responseHeaders[header.toLowerCase()] = Array.isArray(value)
? value.map((item) => { ? value.map(item => {
return String(item); return String(item);
}) })
: String(value); : String(value);
@ -604,7 +604,7 @@ export class HTTPRequest {
responseHeaders: headersArray(responseHeaders), responseHeaders: headersArray(responseHeaders),
body: responseBody ? responseBody.toString('base64') : undefined, body: responseBody ? responseBody.toString('base64') : undefined,
}) })
.catch((error) => { .catch(error => {
this.#interceptionHandled = false; this.#interceptionHandled = false;
return handleError(error); return handleError(error);
}); });
@ -731,7 +731,7 @@ export type ActionResult = 'continue' | 'abort' | 'respond';
function headersArray( function headersArray(
headers: Record<string, string | string[]> headers: Record<string, string | string[]>
): Array<{ name: string; value: string }> { ): Array<{name: string; value: string}> {
const result = []; const result = [];
for (const name in headers) { for (const name in headers) {
const value = headers[name]; const value = headers[name];
@ -740,8 +740,8 @@ function headersArray(
const values = Array.isArray(value) ? value : [value]; const values = Array.isArray(value) ? value : [value];
result.push( result.push(
...values.map((value) => { ...values.map(value => {
return { name, value: value + '' }; return {name, value: value + ''};
}) })
); );
} }
@ -762,7 +762,7 @@ async function handleError(error: ProtocolError) {
// List taken from // List taken from
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml // https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
// with extra 306 and 418 codes. // with extra 306 and 418 codes.
const STATUS_TEXTS: { [key: string]: string | undefined } = { const STATUS_TEXTS: {[key: string]: string | undefined} = {
'100': 'Continue', '100': 'Continue',
'101': 'Switching Protocols', '101': 'Switching Protocols',
'102': 'Processing', '102': 'Processing',

View File

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js'; import {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
import { EventEmitter } from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import { Frame } from './FrameManager.js'; import {Frame} from './FrameManager.js';
import { HTTPRequest } from './HTTPRequest.js'; import {HTTPRequest} from './HTTPRequest.js';
import { SecurityDetails } from './SecurityDetails.js'; import {SecurityDetails} from './SecurityDetails.js';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { ProtocolError } from './Errors.js'; import {ProtocolError} from './Errors.js';
/** /**
* @public * @public
@ -71,7 +71,7 @@ export class HTTPResponse {
this.#client = client; this.#client = client;
this.#request = request; this.#request = request;
this.#bodyLoadedPromise = new Promise((fulfill) => { this.#bodyLoadedPromise = new Promise(fulfill => {
this.#bodyLoadedPromiseFulfill = fulfill; this.#bodyLoadedPromiseFulfill = fulfill;
}); });
@ -195,7 +195,7 @@ export class HTTPResponse {
*/ */
buffer(): Promise<Buffer> { buffer(): Promise<Buffer> {
if (!this.#contentPromise) { if (!this.#contentPromise) {
this.#contentPromise = this.#bodyLoadedPromise.then(async (error) => { this.#contentPromise = this.#bodyLoadedPromise.then(async error => {
if (error) { if (error) {
throw error; throw error;
} }

View File

@ -14,15 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { assert } from './assert.js'; import {assert} from './assert.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { import {_keyDefinitions, KeyDefinition, KeyInput} from './USKeyboardLayout.js';
_keyDefinitions, import {Protocol} from 'devtools-protocol';
KeyDefinition, import {Point} from './JSHandle.js';
KeyInput,
} from './USKeyboardLayout.js';
import { Protocol } from 'devtools-protocol';
import { Point } from './JSHandle.js';
type KeyDescription = Required< type KeyDescription = Required<
Pick<KeyDefinition, 'keyCode' | 'key' | 'text' | 'code' | 'location'> Pick<KeyDefinition, 'keyCode' | 'key' | 'text' | 'code' | 'location'>
@ -110,7 +106,7 @@ export class Keyboard {
*/ */
async down( async down(
key: KeyInput, key: KeyInput,
options: { text?: string } = { text: undefined } options: {text?: string} = {text: undefined}
): Promise<void> { ): Promise<void> {
const description = this.#keyDescriptionForString(key); const description = this.#keyDescriptionForString(key);
@ -241,7 +237,7 @@ export class Keyboard {
* @param char - Character to send into the page. * @param char - Character to send into the page.
*/ */
async sendCharacter(char: string): Promise<void> { async sendCharacter(char: string): Promise<void> {
await this.#client.send('Input.insertText', { text: char }); await this.#client.send('Input.insertText', {text: char});
} }
private charIsKey(char: string): char is KeyInput { private charIsKey(char: string): char is KeyInput {
@ -270,14 +266,14 @@ export class Keyboard {
* if specified, is the time to wait between `keydown` and `keyup` in milliseconds. * if specified, is the time to wait between `keydown` and `keyup` in milliseconds.
* Defaults to 0. * Defaults to 0.
*/ */
async type(text: string, options: { delay?: number } = {}): Promise<void> { async type(text: string, options: {delay?: number} = {}): Promise<void> {
const delay = options.delay || undefined; const delay = options.delay || undefined;
for (const char of text) { for (const char of text) {
if (this.charIsKey(char)) { if (this.charIsKey(char)) {
await this.press(char, { delay }); await this.press(char, {delay});
} else { } else {
if (delay) { if (delay) {
await new Promise((f) => { await new Promise(f => {
return setTimeout(f, delay); return setTimeout(f, delay);
}); });
} }
@ -308,12 +304,12 @@ export class Keyboard {
*/ */
async press( async press(
key: KeyInput, key: KeyInput,
options: { delay?: number; text?: string } = {} options: {delay?: number; text?: string} = {}
): Promise<void> { ): Promise<void> {
const { delay = null } = options; const {delay = null} = options;
await this.down(key, options); await this.down(key, options);
if (delay) { if (delay) {
await new Promise((f) => { await new Promise(f => {
return setTimeout(f, options.delay); return setTimeout(f, options.delay);
}); });
} }
@ -424,9 +420,9 @@ export class Mouse {
async move( async move(
x: number, x: number,
y: number, y: number,
options: { steps?: number } = {} options: {steps?: number} = {}
): Promise<void> { ): Promise<void> {
const { steps = 1 } = options; const {steps = 1} = options;
const fromX = this.#x, const fromX = this.#x,
fromY = this.#y; fromY = this.#y;
this.#x = x; this.#x = x;
@ -451,13 +447,13 @@ export class Mouse {
async click( async click(
x: number, x: number,
y: number, y: number,
options: MouseOptions & { delay?: number } = {} options: MouseOptions & {delay?: number} = {}
): Promise<void> { ): Promise<void> {
const { delay = null } = options; const {delay = null} = options;
if (delay !== null) { if (delay !== null) {
await this.move(x, y); await this.move(x, y);
await this.down(options); await this.down(options);
await new Promise((f) => { await new Promise(f => {
return setTimeout(f, delay); return setTimeout(f, delay);
}); });
await this.up(options); await this.up(options);
@ -473,7 +469,7 @@ export class Mouse {
* @param options - Optional `MouseOptions`. * @param options - Optional `MouseOptions`.
*/ */
async down(options: MouseOptions = {}): Promise<void> { async down(options: MouseOptions = {}): Promise<void> {
const { button = 'left', clickCount = 1 } = options; const {button = 'left', clickCount = 1} = options;
this.#button = button; this.#button = button;
await this.#client.send('Input.dispatchMouseEvent', { await this.#client.send('Input.dispatchMouseEvent', {
type: 'mousePressed', type: 'mousePressed',
@ -490,7 +486,7 @@ export class Mouse {
* @param options - Optional `MouseOptions`. * @param options - Optional `MouseOptions`.
*/ */
async up(options: MouseOptions = {}): Promise<void> { async up(options: MouseOptions = {}): Promise<void> {
const { button = 'left', clickCount = 1 } = options; const {button = 'left', clickCount = 1} = options;
this.#button = 'none'; this.#button = 'none';
await this.#client.send('Input.dispatchMouseEvent', { await this.#client.send('Input.dispatchMouseEvent', {
type: 'mouseReleased', type: 'mouseReleased',
@ -522,7 +518,7 @@ export class Mouse {
* ``` * ```
*/ */
async wheel(options: MouseWheelOptions = {}): Promise<void> { async wheel(options: MouseWheelOptions = {}): Promise<void> {
const { deltaX = 0, deltaY = 0 } = options; const {deltaX = 0, deltaY = 0} = options;
await this.#client.send('Input.dispatchMouseEvent', { await this.#client.send('Input.dispatchMouseEvent', {
type: 'mouseWheel', type: 'mouseWheel',
x: this.#x, x: this.#x,
@ -540,8 +536,8 @@ export class Mouse {
* @param target - point to drag to * @param target - point to drag to
*/ */
async drag(start: Point, target: Point): Promise<Protocol.Input.DragData> { async drag(start: Point, target: Point): Promise<Protocol.Input.DragData> {
const promise = new Promise<Protocol.Input.DragData>((resolve) => { const promise = new Promise<Protocol.Input.DragData>(resolve => {
this.#client.once('Input.dragIntercepted', (event) => { this.#client.once('Input.dragIntercepted', event => {
return resolve(event.data); return resolve(event.data);
}); });
}); });
@ -607,14 +603,14 @@ export class Mouse {
async dragAndDrop( async dragAndDrop(
start: Point, start: Point,
target: Point, target: Point,
options: { delay?: number } = {} options: {delay?: number} = {}
): Promise<void> { ): Promise<void> {
const { delay = null } = options; const {delay = null} = options;
const data = await this.drag(start, target); const data = await this.drag(start, target);
await this.dragEnter(target, data); await this.dragEnter(target, data);
await this.dragOver(target, data); await this.dragOver(target, data);
if (delay) { if (delay) {
await new Promise((resolve) => { await new Promise(resolve => {
return setTimeout(resolve, delay); return setTimeout(resolve, delay);
}); });
} }
@ -645,7 +641,7 @@ export class Touchscreen {
* @param y - Vertical position of the tap. * @param y - Vertical position of the tap.
*/ */
async tap(x: number, y: number): Promise<void> { async tap(x: number, y: number): Promise<void> {
const touchPoints = [{ x: Math.round(x), y: Math.round(y) }]; const touchPoints = [{x: Math.round(x), y: Math.round(y)}];
await this.#client.send('Input.dispatchTouchEvent', { await this.#client.send('Input.dispatchTouchEvent', {
type: 'touchStart', type: 'touchStart',
touchPoints, touchPoints,

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { import {
EvaluateFn, EvaluateFn,
EvaluateFnReturnType, EvaluateFnReturnType,
@ -25,12 +25,12 @@ import {
UnwrapPromiseLike, UnwrapPromiseLike,
WrapElementHandle, WrapElementHandle,
} from './EvalTypes.js'; } from './EvalTypes.js';
import { ExecutionContext } from './ExecutionContext.js'; import {ExecutionContext} from './ExecutionContext.js';
import { Frame, FrameManager } from './FrameManager.js'; import {Frame, FrameManager} from './FrameManager.js';
import { MouseButton } from './Input.js'; import {MouseButton} from './Input.js';
import { Page, ScreenshotOptions } from './Page.js'; import {Page, ScreenshotOptions} from './Page.js';
import { _getQueryHandlerAndSelector } from './QueryHandler.js'; import {_getQueryHandlerAndSelector} from './QueryHandler.js';
import { KeyInput } from './USKeyboardLayout.js'; import {KeyInput} from './USKeyboardLayout.js';
import { import {
debugError, debugError,
isString, isString,
@ -91,8 +91,8 @@ const applyOffsetsToQuad = (
offsetX: number, offsetX: number,
offsetY: number offsetY: number
) => { ) => {
return quad.map((part) => { return quad.map(part => {
return { x: part.x + offsetX, y: part.y + offsetY }; return {x: part.x + offsetX, y: part.y + offsetY};
}); });
}; };
@ -219,7 +219,7 @@ export class JSHandle<HandleObjectType = unknown> {
async getProperty(propertyName: string): Promise<JSHandle> { async getProperty(propertyName: string): Promise<JSHandle> {
const objectHandle = await this.evaluateHandle( const objectHandle = await this.evaluateHandle(
(object: Element, propertyName: keyof Element) => { (object: Element, propertyName: keyof Element) => {
const result: Record<string, unknown> = { __proto__: null }; const result: Record<string, unknown> = {__proto__: null};
result[propertyName] = object[propertyName]; result[propertyName] = object[propertyName];
return result; return result;
}, },
@ -561,8 +561,8 @@ export class ElementHandle<
}); });
return false; return false;
} }
const visibleRatio = await new Promise((resolve) => { const visibleRatio = await new Promise(resolve => {
const observer = new IntersectionObserver((entries) => { const observer = new IntersectionObserver(entries => {
resolve(entries[0]!.intersectionRatio); resolve(entries[0]!.intersectionRatio);
observer.disconnect(); observer.disconnect();
}); });
@ -590,7 +590,7 @@ export class ElementHandle<
async #getOOPIFOffsets( async #getOOPIFOffsets(
frame: Frame frame: Frame
): Promise<{ offsetX: number; offsetY: number }> { ): Promise<{offsetX: number; offsetY: number}> {
let offsetX = 0; let offsetX = 0;
let offsetY = 0; let offsetY = 0;
let currentFrame: Frame | null = frame; let currentFrame: Frame | null = frame;
@ -600,11 +600,9 @@ export class ElementHandle<
currentFrame = parent; currentFrame = parent;
continue; continue;
} }
const { backendNodeId } = await parent const {backendNodeId} = await parent._client().send('DOM.getFrameOwner', {
._client() frameId: currentFrame._id,
.send('DOM.getFrameOwner', { });
frameId: currentFrame._id,
});
const result = await parent._client().send('DOM.getBoxModel', { const result = await parent._client().send('DOM.getBoxModel', {
backendNodeId: backendNodeId, backendNodeId: backendNodeId,
}); });
@ -617,7 +615,7 @@ export class ElementHandle<
offsetY += topLeftCorner!.y; offsetY += topLeftCorner!.y;
currentFrame = parent; currentFrame = parent;
} }
return { offsetX, offsetY }; return {offsetX, offsetY};
} }
/** /**
@ -637,20 +635,20 @@ export class ElementHandle<
} }
// Filter out quads that have too small area to click into. // Filter out quads that have too small area to click into.
// Fallback to `layoutViewport` in case of using Firefox. // Fallback to `layoutViewport` in case of using Firefox.
const { clientWidth, clientHeight } = const {clientWidth, clientHeight} =
layoutMetrics.cssLayoutViewport || layoutMetrics.layoutViewport; layoutMetrics.cssLayoutViewport || layoutMetrics.layoutViewport;
const { offsetX, offsetY } = await this.#getOOPIFOffsets(this.#frame); const {offsetX, offsetY} = await this.#getOOPIFOffsets(this.#frame);
const quads = result.quads const quads = result.quads
.map((quad) => { .map(quad => {
return this.#fromProtocolQuad(quad); return this.#fromProtocolQuad(quad);
}) })
.map((quad) => { .map(quad => {
return applyOffsetsToQuad(quad, offsetX, offsetY); return applyOffsetsToQuad(quad, offsetX, offsetY);
}) })
.map((quad) => { .map(quad => {
return this.#intersectQuadWithViewport(quad, clientWidth, clientHeight); return this.#intersectQuadWithViewport(quad, clientWidth, clientHeight);
}) })
.filter((quad) => { .filter(quad => {
return computeQuadArea(quad) > 1; return computeQuadArea(quad) > 1;
}); });
if (!quads.length) { if (!quads.length) {
@ -696,17 +694,17 @@ export class ElementHandle<
const params: Protocol.DOM.GetBoxModelRequest = { const params: Protocol.DOM.GetBoxModelRequest = {
objectId: this._remoteObject.objectId, objectId: this._remoteObject.objectId,
}; };
return this._client.send('DOM.getBoxModel', params).catch((error) => { return this._client.send('DOM.getBoxModel', params).catch(error => {
return debugError(error); return debugError(error);
}); });
} }
#fromProtocolQuad(quad: number[]): Point[] { #fromProtocolQuad(quad: number[]): Point[] {
return [ return [
{ x: quad[0]!, y: quad[1]! }, {x: quad[0]!, y: quad[1]!},
{ x: quad[2]!, y: quad[3]! }, {x: quad[2]!, y: quad[3]!},
{ x: quad[4]!, y: quad[5]! }, {x: quad[4]!, y: quad[5]!},
{ x: quad[6]!, y: quad[7]! }, {x: quad[6]!, y: quad[7]!},
]; ];
} }
@ -715,7 +713,7 @@ export class ElementHandle<
width: number, width: number,
height: number height: number
): Point[] { ): Point[] {
return quad.map((point) => { return quad.map(point => {
return { return {
x: Math.min(Math.max(point.x, 0), width), x: Math.min(Math.max(point.x, 0), width),
y: Math.min(Math.max(point.y, 0), height), y: Math.min(Math.max(point.y, 0), height),
@ -730,7 +728,7 @@ export class ElementHandle<
*/ */
async hover(): Promise<void> { async hover(): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const { x, y } = await this.clickablePoint(); const {x, y} = await this.clickablePoint();
await this.#page.mouse.move(x, y); await this.#page.mouse.move(x, y);
} }
@ -741,7 +739,7 @@ export class ElementHandle<
*/ */
async click(options: ClickOptions = {}): Promise<void> { async click(options: ClickOptions = {}): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const { x, y } = await this.clickablePoint(options.offset); const {x, y} = await this.clickablePoint(options.offset);
await this.#page.mouse.click(x, y, options); await this.#page.mouse.click(x, y, options);
} }
@ -762,7 +760,7 @@ export class ElementHandle<
* This method creates a `dragenter` event on the element. * This method creates a `dragenter` event on the element.
*/ */
async dragEnter( async dragEnter(
data: Protocol.Input.DragData = { items: [], dragOperationsMask: 1 } data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> { ): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const target = await this.clickablePoint(); const target = await this.clickablePoint();
@ -773,7 +771,7 @@ export class ElementHandle<
* This method creates a `dragover` event on the element. * This method creates a `dragover` event on the element.
*/ */
async dragOver( async dragOver(
data: Protocol.Input.DragData = { items: [], dragOperationsMask: 1 } data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> { ): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const target = await this.clickablePoint(); const target = await this.clickablePoint();
@ -784,7 +782,7 @@ export class ElementHandle<
* This method triggers a drop on the element. * This method triggers a drop on the element.
*/ */
async drop( async drop(
data: Protocol.Input.DragData = { items: [], dragOperationsMask: 1 } data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> { ): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const destination = await this.clickablePoint(); const destination = await this.clickablePoint();
@ -796,7 +794,7 @@ export class ElementHandle<
*/ */
async dragAndDrop( async dragAndDrop(
target: ElementHandle, target: ElementHandle,
options?: { delay: number } options?: {delay: number}
): Promise<void> { ): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const startPoint = await this.clickablePoint(); const startPoint = await this.clickablePoint();
@ -856,8 +854,8 @@ export class ElementHandle<
} }
} }
} }
element.dispatchEvent(new Event('input', { bubbles: true })); element.dispatchEvent(new Event('input', {bubbles: true}));
element.dispatchEvent(new Event('change', { bubbles: true })); element.dispatchEvent(new Event('change', {bubbles: true}));
return [...selectedValues.values()]; return [...selectedValues.values()];
}, values); }, values);
} }
@ -874,7 +872,7 @@ export class ElementHandle<
*/ */
async uploadFile(...filePaths: string[]): Promise<void> { async uploadFile(...filePaths: string[]): Promise<void> {
const isMultiple = await this.evaluate<(element: Element) => boolean>( const isMultiple = await this.evaluate<(element: Element) => boolean>(
(element) => { element => {
if (!(element instanceof HTMLInputElement)) { if (!(element instanceof HTMLInputElement)) {
throw new Error('uploadFile can only be called on an input element.'); throw new Error('uploadFile can only be called on an input element.');
} }
@ -898,28 +896,28 @@ export class ElementHandle<
} }
throw error; throw error;
} }
const files = filePaths.map((filePath) => { const files = filePaths.map(filePath => {
if (path.win32.isAbsolute(filePath) || path.posix.isAbsolute(filePath)) { if (path.win32.isAbsolute(filePath) || path.posix.isAbsolute(filePath)) {
return filePath; return filePath;
} else { } else {
return path.resolve(filePath); return path.resolve(filePath);
} }
}); });
const { objectId } = this._remoteObject; const {objectId} = this._remoteObject;
const { node } = await this._client.send('DOM.describeNode', { objectId }); const {node} = await this._client.send('DOM.describeNode', {objectId});
const { backendNodeId } = node; const {backendNodeId} = node;
/* The zero-length array is a special case, it seems that /* The zero-length array is a special case, it seems that
DOM.setFileInputFiles does not actually update the files in that case, DOM.setFileInputFiles does not actually update the files in that case,
so the solution is to eval the element value to a new FileList directly. so the solution is to eval the element value to a new FileList directly.
*/ */
if (files.length === 0) { if (files.length === 0) {
await (this as ElementHandle<HTMLInputElement>).evaluate((element) => { await (this as ElementHandle<HTMLInputElement>).evaluate(element => {
element.files = new DataTransfer().files; element.files = new DataTransfer().files;
// Dispatch events for this case because it should behave akin to a user action. // Dispatch events for this case because it should behave akin to a user action.
element.dispatchEvent(new Event('input', { bubbles: true })); element.dispatchEvent(new Event('input', {bubbles: true}));
element.dispatchEvent(new Event('change', { bubbles: true })); element.dispatchEvent(new Event('change', {bubbles: true}));
}); });
} else { } else {
await this._client.send('DOM.setFileInputFiles', { await this._client.send('DOM.setFileInputFiles', {
@ -937,7 +935,7 @@ export class ElementHandle<
*/ */
async tap(): Promise<void> { async tap(): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const { x, y } = await this.clickablePoint(); const {x, y} = await this.clickablePoint();
await this.#page.touchscreen.tap(x, y); await this.#page.touchscreen.tap(x, y);
} }
@ -945,7 +943,7 @@ export class ElementHandle<
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element. * Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element.
*/ */
async focus(): Promise<void> { async focus(): Promise<void> {
await (this as ElementHandle<HTMLElement>).evaluate((element) => { await (this as ElementHandle<HTMLElement>).evaluate(element => {
return element.focus(); return element.focus();
}); });
} }
@ -972,7 +970,7 @@ export class ElementHandle<
* await elementHandle.press('Enter'); * await elementHandle.press('Enter');
* ``` * ```
*/ */
async type(text: string, options?: { delay: number }): Promise<void> { async type(text: string, options?: {delay: number}): Promise<void> {
await this.focus(); await this.focus();
await this.#page.keyboard.type(text, options); await this.#page.keyboard.type(text, options);
} }
@ -1007,14 +1005,14 @@ export class ElementHandle<
return null; return null;
} }
const { offsetX, offsetY } = await this.#getOOPIFOffsets(this.#frame); const {offsetX, offsetY} = await this.#getOOPIFOffsets(this.#frame);
const quad = result.model.border; const quad = result.model.border;
const x = Math.min(quad[0]!, quad[2]!, quad[4]!, quad[6]!); const x = Math.min(quad[0]!, quad[2]!, quad[4]!, quad[6]!);
const y = Math.min(quad[1]!, quad[3]!, quad[5]!, quad[7]!); const y = Math.min(quad[1]!, quad[3]!, quad[5]!, quad[7]!);
const width = Math.max(quad[0]!, quad[2]!, quad[4]!, quad[6]!) - x; const width = Math.max(quad[0]!, quad[2]!, quad[4]!, quad[6]!) - x;
const height = Math.max(quad[1]!, quad[3]!, quad[5]!, quad[7]!) - y; const height = Math.max(quad[1]!, quad[3]!, quad[5]!, quad[7]!) - y;
return { x: x + offsetX, y: y + offsetY, width, height }; return {x: x + offsetX, y: y + offsetY, width, height};
} }
/** /**
@ -1032,9 +1030,9 @@ export class ElementHandle<
return null; return null;
} }
const { offsetX, offsetY } = await this.#getOOPIFOffsets(this.#frame); const {offsetX, offsetY} = await this.#getOOPIFOffsets(this.#frame);
const { content, padding, border, margin, width, height } = result.model; const {content, padding, border, margin, width, height} = result.model;
return { return {
content: applyOffsetsToQuad( content: applyOffsetsToQuad(
this.#fromProtocolQuad(content), this.#fromProtocolQuad(content),
@ -1097,7 +1095,7 @@ export class ElementHandle<
const layoutMetrics = await this._client.send('Page.getLayoutMetrics'); const layoutMetrics = await this._client.send('Page.getLayoutMetrics');
// Fallback to `layoutViewport` in case of using Firefox. // Fallback to `layoutViewport` in case of using Firefox.
const { pageX, pageY } = const {pageX, pageY} =
layoutMetrics.cssVisualViewport || layoutMetrics.layoutViewport; layoutMetrics.cssVisualViewport || layoutMetrics.layoutViewport;
const clip = Object.assign({}, boundingBox); const clip = Object.assign({}, boundingBox);
@ -1131,7 +1129,7 @@ export class ElementHandle<
async $<T extends Element = Element>( async $<T extends Element = Element>(
selector: string selector: string
): Promise<ElementHandle<T> | null> { ): Promise<ElementHandle<T> | null> {
const { updatedSelector, queryHandler } = const {updatedSelector, queryHandler} =
_getQueryHandlerAndSelector(selector); _getQueryHandlerAndSelector(selector);
assert( assert(
queryHandler.queryOne, queryHandler.queryOne,
@ -1154,7 +1152,7 @@ export class ElementHandle<
async $$<T extends Element = Element>( async $$<T extends Element = Element>(
selector: string selector: string
): Promise<Array<ElementHandle<T>>> { ): Promise<Array<ElementHandle<T>>> {
const { updatedSelector, queryHandler } = const {updatedSelector, queryHandler} =
_getQueryHandlerAndSelector(selector); _getQueryHandlerAndSelector(selector);
assert( assert(
queryHandler.queryAll, queryHandler.queryAll,
@ -1243,7 +1241,7 @@ export class ElementHandle<
>, >,
...args: SerializableOrJSHandle[] ...args: SerializableOrJSHandle[]
): Promise<WrapElementHandle<ReturnType>> { ): Promise<WrapElementHandle<ReturnType>> {
const { updatedSelector, queryHandler } = const {updatedSelector, queryHandler} =
_getQueryHandlerAndSelector(selector); _getQueryHandlerAndSelector(selector);
assert(queryHandler.queryAllArray); assert(queryHandler.queryAllArray);
const arrayHandle = await queryHandler.queryAllArray(this, updatedSelector); const arrayHandle = await queryHandler.queryAllArray(this, updatedSelector);
@ -1300,10 +1298,10 @@ export class ElementHandle<
async isIntersectingViewport(options?: { async isIntersectingViewport(options?: {
threshold?: number; threshold?: number;
}): Promise<boolean> { }): Promise<boolean> {
const { threshold = 0 } = options || {}; const {threshold = 0} = options || {};
return await this.evaluate(async (element: Element, threshold: number) => { return await this.evaluate(async (element: Element, threshold: number) => {
const visibleRatio = await new Promise<number>((resolve) => { const visibleRatio = await new Promise<number>(resolve => {
const observer = new IntersectionObserver((entries) => { const observer = new IntersectionObserver(entries => {
resolve(entries[0]!.intersectionRatio); resolve(entries[0]!.intersectionRatio);
observer.disconnect(); observer.disconnect();
}); });

View File

@ -14,22 +14,22 @@
* limitations under the License. * limitations under the License.
*/ */
import { assert } from './assert.js'; import {assert} from './assert.js';
import { import {
addEventListener, addEventListener,
PuppeteerEventListener, PuppeteerEventListener,
removeEventListeners, removeEventListeners,
} from './util.js'; } from './util.js';
import { TimeoutError } from './Errors.js'; import {TimeoutError} from './Errors.js';
import { import {
FrameManager, FrameManager,
Frame, Frame,
FrameManagerEmittedEvents, FrameManagerEmittedEvents,
} from './FrameManager.js'; } from './FrameManager.js';
import { HTTPRequest } from './HTTPRequest.js'; import {HTTPRequest} from './HTTPRequest.js';
import { HTTPResponse } from './HTTPResponse.js'; import {HTTPResponse} from './HTTPResponse.js';
import { NetworkManagerEmittedEvents } from './NetworkManager.js'; import {NetworkManagerEmittedEvents} from './NetworkManager.js';
import { CDPSessionEmittedEvents } from './Connection.js'; import {CDPSessionEmittedEvents} from './Connection.js';
/** /**
* @public * @public
*/ */
@ -72,24 +72,24 @@ export class LifecycleWatcher {
#eventListeners: PuppeteerEventListener[]; #eventListeners: PuppeteerEventListener[];
#sameDocumentNavigationCompleteCallback: (x?: Error) => void = noop; #sameDocumentNavigationCompleteCallback: (x?: Error) => void = noop;
#sameDocumentNavigationPromise = new Promise<Error | undefined>((fulfill) => { #sameDocumentNavigationPromise = new Promise<Error | undefined>(fulfill => {
this.#sameDocumentNavigationCompleteCallback = fulfill; this.#sameDocumentNavigationCompleteCallback = fulfill;
}); });
#lifecycleCallback: () => void = noop; #lifecycleCallback: () => void = noop;
#lifecyclePromise: Promise<void> = new Promise((fulfill) => { #lifecyclePromise: Promise<void> = new Promise(fulfill => {
this.#lifecycleCallback = fulfill; this.#lifecycleCallback = fulfill;
}); });
#newDocumentNavigationCompleteCallback: (x?: Error) => void = noop; #newDocumentNavigationCompleteCallback: (x?: Error) => void = noop;
#newDocumentNavigationPromise: Promise<Error | undefined> = new Promise( #newDocumentNavigationPromise: Promise<Error | undefined> = new Promise(
(fulfill) => { fulfill => {
this.#newDocumentNavigationCompleteCallback = fulfill; this.#newDocumentNavigationCompleteCallback = fulfill;
} }
); );
#terminationCallback: (x?: Error) => void = noop; #terminationCallback: (x?: Error) => void = noop;
#terminationPromise: Promise<Error | undefined> = new Promise((fulfill) => { #terminationPromise: Promise<Error | undefined> = new Promise(fulfill => {
this.#terminationCallback = fulfill; this.#terminationCallback = fulfill;
}); });
@ -111,7 +111,7 @@ export class LifecycleWatcher {
} else if (typeof waitUntil === 'string') { } else if (typeof waitUntil === 'string') {
waitUntil = [waitUntil]; waitUntil = [waitUntil];
} }
this.#expectedLifecycle = waitUntil.map((value) => { this.#expectedLifecycle = waitUntil.map(value => {
const protocolEvent = puppeteerToProtocolLifecycle.get(value); const protocolEvent = puppeteerToProtocolLifecycle.get(value);
assert(protocolEvent, 'Unknown value for options.waitUntil: ' + value); assert(protocolEvent, 'Unknown value for options.waitUntil: ' + value);
return protocolEvent as ProtocolLifeCycleEvent; return protocolEvent as ProtocolLifeCycleEvent;
@ -214,7 +214,7 @@ export class LifecycleWatcher {
} }
const errorMessage = const errorMessage =
'Navigation timeout of ' + this.#timeout + ' ms exceeded'; 'Navigation timeout of ' + this.#timeout + ' ms exceeded';
await new Promise((fulfill) => { await new Promise(fulfill => {
return (this.#maximumTimer = setTimeout(fulfill, this.#timeout)); return (this.#maximumTimer = setTimeout(fulfill, this.#timeout));
}); });
return new TimeoutError(errorMessage); return new TimeoutError(errorMessage);

View File

@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { NetworkConditions } from './NetworkManager.js'; import {NetworkConditions} from './NetworkManager.js';
/** /**
* @public * @public
*/ */
export type PredefinedNetworkConditions = { [name: string]: NetworkConditions }; export type PredefinedNetworkConditions = {[name: string]: NetworkConditions};
/** /**
* @public * @public

View File

@ -1,5 +1,5 @@
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { HTTPRequest } from './HTTPRequest.js'; import {HTTPRequest} from './HTTPRequest.js';
export type QueuedEventGroup = { export type QueuedEventGroup = {
responseReceivedEvent: Protocol.Network.ResponseReceivedEvent; responseReceivedEvent: Protocol.Network.ResponseReceivedEvent;

View File

@ -14,15 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js'; import {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { EventEmitter } from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import { Frame } from './FrameManager.js'; import {Frame} from './FrameManager.js';
import { HTTPRequest } from './HTTPRequest.js'; import {HTTPRequest} from './HTTPRequest.js';
import { HTTPResponse } from './HTTPResponse.js'; import {HTTPResponse} from './HTTPResponse.js';
import { FetchRequestId, NetworkEventManager } from './NetworkEventManager.js'; import {FetchRequestId, NetworkEventManager} from './NetworkEventManager.js';
import { debugError, isString } from './util.js'; import {debugError, isString} from './util.js';
/** /**
* @public * @public
@ -231,7 +231,7 @@ export class NetworkManager extends EventEmitter {
this.#updateProtocolCacheDisabled(), this.#updateProtocolCacheDisabled(),
this.#client.send('Fetch.enable', { this.#client.send('Fetch.enable', {
handleAuthRequests: true, handleAuthRequests: true,
patterns: [{ urlPattern: '*' }], patterns: [{urlPattern: '*'}],
}), }),
]); ]);
} else { } else {
@ -258,7 +258,7 @@ export class NetworkManager extends EventEmitter {
this.#userRequestInterceptionEnabled && this.#userRequestInterceptionEnabled &&
!event.request.url.startsWith('data:') !event.request.url.startsWith('data:')
) { ) {
const { requestId: networkRequestId } = event; const {requestId: networkRequestId} = event;
this.#networkEventManager.storeRequestWillBeSent(networkRequestId, event); this.#networkEventManager.storeRequestWillBeSent(networkRequestId, event);
@ -268,7 +268,7 @@ export class NetworkManager extends EventEmitter {
const requestPausedEvent = const requestPausedEvent =
this.#networkEventManager.getRequestPaused(networkRequestId); this.#networkEventManager.getRequestPaused(networkRequestId);
if (requestPausedEvent) { if (requestPausedEvent) {
const { requestId: fetchRequestId } = requestPausedEvent; const {requestId: fetchRequestId} = requestPausedEvent;
this.#patchRequestEventHeaders(event, requestPausedEvent); this.#patchRequestEventHeaders(event, requestPausedEvent);
this.#onRequest(event, fetchRequestId); this.#onRequest(event, fetchRequestId);
this.#networkEventManager.forgetRequestPaused(networkRequestId); this.#networkEventManager.forgetRequestPaused(networkRequestId);
@ -291,14 +291,14 @@ export class NetworkManager extends EventEmitter {
response = 'ProvideCredentials'; response = 'ProvideCredentials';
this.#attemptedAuthentications.add(event.requestId); this.#attemptedAuthentications.add(event.requestId);
} }
const { username, password } = this.#credentials || { const {username, password} = this.#credentials || {
username: undefined, username: undefined,
password: undefined, password: undefined,
}; };
this.#client this.#client
.send('Fetch.continueWithAuth', { .send('Fetch.continueWithAuth', {
requestId: event.requestId, requestId: event.requestId,
authChallengeResponse: { response, username, password }, authChallengeResponse: {response, username, password},
}) })
.catch(debugError); .catch(debugError);
} }
@ -322,7 +322,7 @@ export class NetworkManager extends EventEmitter {
.catch(debugError); .catch(debugError);
} }
const { networkId: networkRequestId, requestId: fetchRequestId } = event; const {networkId: networkRequestId, requestId: fetchRequestId} = event;
if (!networkRequestId) { if (!networkRequestId) {
return; return;

View File

@ -186,15 +186,15 @@ export const _paperFormats: Record<
LowerCasePaperFormat, LowerCasePaperFormat,
PaperFormatDimensions PaperFormatDimensions
> = { > = {
letter: { width: 8.5, height: 11 }, letter: {width: 8.5, height: 11},
legal: { width: 8.5, height: 14 }, legal: {width: 8.5, height: 14},
tabloid: { width: 11, height: 17 }, tabloid: {width: 11, height: 17},
ledger: { width: 17, height: 11 }, ledger: {width: 17, height: 11},
a0: { width: 33.1, height: 46.8 }, a0: {width: 33.1, height: 46.8},
a1: { width: 23.4, height: 33.1 }, a1: {width: 23.4, height: 33.1},
a2: { width: 16.54, height: 23.4 }, a2: {width: 16.54, height: 23.4},
a3: { width: 11.7, height: 16.54 }, a3: {width: 11.7, height: 16.54},
a4: { width: 8.27, height: 11.7 }, a4: {width: 8.27, height: 11.7},
a5: { width: 5.83, height: 8.27 }, a5: {width: 5.83, height: 8.27},
a6: { width: 4.13, height: 5.83 }, a6: {width: 4.13, height: 5.83},
} as const; } as const;

View File

@ -14,20 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import type { Readable } from 'stream'; import type {Readable} from 'stream';
import { Accessibility } from './Accessibility.js'; import {Accessibility} from './Accessibility.js';
import { assert, assertNever } from './assert.js'; import {assert, assertNever} from './assert.js';
import { Browser, BrowserContext } from './Browser.js'; import {Browser, BrowserContext} from './Browser.js';
import { import {CDPSession, CDPSessionEmittedEvents, Connection} from './Connection.js';
CDPSession, import {ConsoleMessage, ConsoleMessageType} from './ConsoleMessage.js';
CDPSessionEmittedEvents, import {Coverage} from './Coverage.js';
Connection, import {Dialog} from './Dialog.js';
} from './Connection.js'; import {EmulationManager} from './EmulationManager.js';
import { ConsoleMessage, ConsoleMessageType } from './ConsoleMessage.js';
import { Coverage } from './Coverage.js';
import { Dialog } from './Dialog.js';
import { EmulationManager } from './EmulationManager.js';
import { import {
EvaluateFn, EvaluateFn,
EvaluateFnReturnType, EvaluateFnReturnType,
@ -36,8 +32,8 @@ import {
UnwrapPromiseLike, UnwrapPromiseLike,
WrapElementHandle, WrapElementHandle,
} from './EvalTypes.js'; } from './EvalTypes.js';
import { EventEmitter, Handler } from './EventEmitter.js'; import {EventEmitter, Handler} from './EventEmitter.js';
import { FileChooser } from './FileChooser.js'; import {FileChooser} from './FileChooser.js';
import { import {
Frame, Frame,
FrameManager, FrameManager,
@ -61,27 +57,23 @@ import {
waitForEvent, waitForEvent,
waitWithTimeout, waitWithTimeout,
} from './util.js'; } from './util.js';
import { HTTPRequest } from './HTTPRequest.js'; import {HTTPRequest} from './HTTPRequest.js';
import { HTTPResponse } from './HTTPResponse.js'; import {HTTPResponse} from './HTTPResponse.js';
import { Keyboard, Mouse, MouseButton, Touchscreen } from './Input.js'; import {Keyboard, Mouse, MouseButton, Touchscreen} from './Input.js';
import { ElementHandle, JSHandle, _createJSHandle } from './JSHandle.js'; import {ElementHandle, JSHandle, _createJSHandle} from './JSHandle.js';
import { PuppeteerLifeCycleEvent } from './LifecycleWatcher.js'; import {PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
import { import {
Credentials, Credentials,
NetworkConditions, NetworkConditions,
NetworkManagerEmittedEvents, NetworkManagerEmittedEvents,
} from './NetworkManager.js'; } from './NetworkManager.js';
import { import {LowerCasePaperFormat, PDFOptions, _paperFormats} from './PDFOptions.js';
LowerCasePaperFormat, import {Viewport} from './PuppeteerViewport.js';
PDFOptions, import {Target} from './Target.js';
_paperFormats, import {TaskQueue} from './TaskQueue.js';
} from './PDFOptions.js'; import {TimeoutSettings} from './TimeoutSettings.js';
import { Viewport } from './PuppeteerViewport.js'; import {Tracing} from './Tracing.js';
import { Target } from './Target.js'; import {WebWorker} from './WebWorker.js';
import { TaskQueue } from './TaskQueue.js';
import { TimeoutSettings } from './TimeoutSettings.js';
import { Tracing } from './Tracing.js';
import { WebWorker } from './WebWorker.js';
/** /**
* @public * @public
@ -378,7 +370,7 @@ export interface PageEventObject {
framedetached: Frame; framedetached: Frame;
framenavigated: Frame; framenavigated: Frame;
load: never; load: never;
metrics: { title: string; metrics: Metrics }; metrics: {title: string; metrics: Metrics};
pageerror: Error; pageerror: Error;
popup: Page; popup: Page;
request: HTTPRequest; request: HTTPRequest;
@ -545,7 +537,7 @@ export class Page extends EventEmitter {
} }
} }
); );
client.on('Target.detachedFromTarget', (event) => { client.on('Target.detachedFromTarget', event => {
const worker = this.#workers.get(event.sessionId); const worker = this.#workers.get(event.sessionId);
if (!worker) { if (!worker) {
return; return;
@ -554,33 +546,33 @@ export class Page extends EventEmitter {
this.emit(PageEmittedEvents.WorkerDestroyed, worker); this.emit(PageEmittedEvents.WorkerDestroyed, worker);
}); });
this.#frameManager.on(FrameManagerEmittedEvents.FrameAttached, (event) => { this.#frameManager.on(FrameManagerEmittedEvents.FrameAttached, event => {
return this.emit(PageEmittedEvents.FrameAttached, event); return this.emit(PageEmittedEvents.FrameAttached, event);
}); });
this.#frameManager.on(FrameManagerEmittedEvents.FrameDetached, (event) => { this.#frameManager.on(FrameManagerEmittedEvents.FrameDetached, event => {
return this.emit(PageEmittedEvents.FrameDetached, event); return this.emit(PageEmittedEvents.FrameDetached, event);
}); });
this.#frameManager.on(FrameManagerEmittedEvents.FrameNavigated, (event) => { this.#frameManager.on(FrameManagerEmittedEvents.FrameNavigated, event => {
return this.emit(PageEmittedEvents.FrameNavigated, event); return this.emit(PageEmittedEvents.FrameNavigated, event);
}); });
const networkManager = this.#frameManager.networkManager(); const networkManager = this.#frameManager.networkManager();
networkManager.on(NetworkManagerEmittedEvents.Request, (event) => { networkManager.on(NetworkManagerEmittedEvents.Request, event => {
return this.emit(PageEmittedEvents.Request, event); return this.emit(PageEmittedEvents.Request, event);
}); });
networkManager.on( networkManager.on(
NetworkManagerEmittedEvents.RequestServedFromCache, NetworkManagerEmittedEvents.RequestServedFromCache,
(event) => { event => {
return this.emit(PageEmittedEvents.RequestServedFromCache, event); return this.emit(PageEmittedEvents.RequestServedFromCache, event);
} }
); );
networkManager.on(NetworkManagerEmittedEvents.Response, (event) => { networkManager.on(NetworkManagerEmittedEvents.Response, event => {
return this.emit(PageEmittedEvents.Response, event); return this.emit(PageEmittedEvents.Response, event);
}); });
networkManager.on(NetworkManagerEmittedEvents.RequestFailed, (event) => { networkManager.on(NetworkManagerEmittedEvents.RequestFailed, event => {
return this.emit(PageEmittedEvents.RequestFailed, event); return this.emit(PageEmittedEvents.RequestFailed, event);
}); });
networkManager.on(NetworkManagerEmittedEvents.RequestFinished, (event) => { networkManager.on(NetworkManagerEmittedEvents.RequestFinished, event => {
return this.emit(PageEmittedEvents.RequestFinished, event); return this.emit(PageEmittedEvents.RequestFinished, event);
}); });
this.#fileChooserInterceptors = new Set(); this.#fileChooserInterceptors = new Set();
@ -591,28 +583,28 @@ export class Page extends EventEmitter {
client.on('Page.loadEventFired', () => { client.on('Page.loadEventFired', () => {
return this.emit(PageEmittedEvents.Load); return this.emit(PageEmittedEvents.Load);
}); });
client.on('Runtime.consoleAPICalled', (event) => { client.on('Runtime.consoleAPICalled', event => {
return this.#onConsoleAPI(event); return this.#onConsoleAPI(event);
}); });
client.on('Runtime.bindingCalled', (event) => { client.on('Runtime.bindingCalled', event => {
return this.#onBindingCalled(event); return this.#onBindingCalled(event);
}); });
client.on('Page.javascriptDialogOpening', (event) => { client.on('Page.javascriptDialogOpening', event => {
return this.#onDialog(event); return this.#onDialog(event);
}); });
client.on('Runtime.exceptionThrown', (exception) => { client.on('Runtime.exceptionThrown', exception => {
return this.#handleException(exception.exceptionDetails); return this.#handleException(exception.exceptionDetails);
}); });
client.on('Inspector.targetCrashed', () => { client.on('Inspector.targetCrashed', () => {
return this.#onTargetCrashed(); return this.#onTargetCrashed();
}); });
client.on('Performance.metrics', (event) => { client.on('Performance.metrics', event => {
return this.#emitMetrics(event); return this.#emitMetrics(event);
}); });
client.on('Log.entryAdded', (event) => { client.on('Log.entryAdded', event => {
return this.#onLogEntryAdded(event); return this.#onLogEntryAdded(event);
}); });
client.on('Page.fileChooserOpened', (event) => { client.on('Page.fileChooserOpened', event => {
return this.#onFileChooser(event); return this.#onFileChooser(event);
}); });
this.#target._isClosedPromise.then(() => { this.#target._isClosedPromise.then(() => {
@ -743,9 +735,9 @@ export class Page extends EventEmitter {
}); });
} }
const { timeout = this.#timeoutSettings.timeout() } = options; const {timeout = this.#timeoutSettings.timeout()} = options;
let callback!: (value: FileChooser | PromiseLike<FileChooser>) => void; let callback!: (value: FileChooser | PromiseLike<FileChooser>) => void;
const promise = new Promise<FileChooser>((x) => { const promise = new Promise<FileChooser>(x => {
return (callback = x); return (callback = x);
}); });
this.#fileChooserInterceptors.add(callback); this.#fileChooserInterceptors.add(callback);
@ -753,7 +745,7 @@ export class Page extends EventEmitter {
promise, promise,
'waiting for file chooser', 'waiting for file chooser',
timeout timeout
).catch((error) => { ).catch(error => {
this.#fileChooserInterceptors.delete(callback); this.#fileChooserInterceptors.delete(callback);
throw error; throw error;
}); });
@ -770,7 +762,7 @@ export class Page extends EventEmitter {
* ``` * ```
*/ */
async setGeolocation(options: GeolocationOptions): Promise<void> { async setGeolocation(options: GeolocationOptions): Promise<void> {
const { longitude, latitude, accuracy = 0 } = options; const {longitude, latitude, accuracy = 0} = options;
if (longitude < -180 || longitude > 180) { if (longitude < -180 || longitude > 180) {
throw new Error( throw new Error(
`Invalid longitude "${longitude}": precondition -180 <= LONGITUDE <= 180 failed.` `Invalid longitude "${longitude}": precondition -180 <= LONGITUDE <= 180 failed.`
@ -826,16 +818,16 @@ export class Page extends EventEmitter {
} }
#onLogEntryAdded(event: Protocol.Log.EntryAddedEvent): void { #onLogEntryAdded(event: Protocol.Log.EntryAddedEvent): void {
const { level, text, args, source, url, lineNumber } = event.entry; const {level, text, args, source, url, lineNumber} = event.entry;
if (args) { if (args) {
args.map((arg) => { args.map(arg => {
return releaseObject(this.#client, arg); return releaseObject(this.#client, arg);
}); });
} }
if (source !== 'worker') { if (source !== 'worker') {
this.emit( this.emit(
PageEmittedEvents.Console, PageEmittedEvents.Console,
new ConsoleMessage(level, text, [], [{ url, lineNumber }]) new ConsoleMessage(level, text, [], [{url, lineNumber}])
); );
} }
} }
@ -934,7 +926,7 @@ export class Page extends EventEmitter {
*/ */
async setDragInterception(enabled: boolean): Promise<void> { async setDragInterception(enabled: boolean): Promise<void> {
this.#userDragInterceptionEnabled = enabled; this.#userDragInterceptionEnabled = enabled;
return this.#client.send('Input.setInterceptDrags', { enabled }); return this.#client.send('Input.setInterceptDrags', {enabled});
} }
/** /**
@ -1337,7 +1329,7 @@ export class Page extends EventEmitter {
async setCookie(...cookies: Protocol.Network.CookieParam[]): Promise<void> { async setCookie(...cookies: Protocol.Network.CookieParam[]): Promise<void> {
const pageURL = this.url(); const pageURL = this.url();
const startsWithHTTP = pageURL.startsWith('http'); const startsWithHTTP = pageURL.startsWith('http');
const items = cookies.map((cookie) => { const items = cookies.map(cookie => {
const item = Object.assign({}, cookie); const item = Object.assign({}, cookie);
if (!item.url && startsWithHTTP) { if (!item.url && startsWithHTTP) {
item.url = pageURL; item.url = pageURL;
@ -1354,7 +1346,7 @@ export class Page extends EventEmitter {
}); });
await this.deleteCookie(...items); await this.deleteCookie(...items);
if (items.length) { if (items.length) {
await this.#client.send('Network.setCookies', { cookies: items }); await this.#client.send('Network.setCookies', {cookies: items});
} }
} }
@ -1450,7 +1442,7 @@ export class Page extends EventEmitter {
*/ */
async exposeFunction( async exposeFunction(
name: string, name: string,
puppeteerFunction: Function | { default: Function } puppeteerFunction: Function | {default: Function}
): Promise<void> { ): Promise<void> {
if (this.#pageBindings.has(name)) { if (this.#pageBindings.has(name)) {
throw new Error( throw new Error(
@ -1472,12 +1464,12 @@ export class Page extends EventEmitter {
this.#pageBindings.set(name, exposedFunction); this.#pageBindings.set(name, exposedFunction);
const expression = pageBindingInitString('exposedFun', name); const expression = pageBindingInitString('exposedFun', name);
await this.#client.send('Runtime.addBinding', { name: name }); await this.#client.send('Runtime.addBinding', {name: name});
await this.#client.send('Page.addScriptToEvaluateOnNewDocument', { await this.#client.send('Page.addScriptToEvaluateOnNewDocument', {
source: expression, source: expression,
}); });
await Promise.all( await Promise.all(
this.frames().map((frame) => { this.frames().map(frame => {
return frame.evaluate(expression).catch(debugError); return frame.evaluate(expression).catch(debugError);
}) })
); );
@ -1609,7 +1601,7 @@ export class Page extends EventEmitter {
event.executionContextId, event.executionContextId,
this.#client this.#client
); );
const values = event.args.map((arg) => { const values = event.args.map(arg => {
return _createJSHandle(context, arg); return _createJSHandle(context, arg);
}); });
this.#addConsoleMessage(event.type, values, event.stackTrace); this.#addConsoleMessage(event.type, values, event.stackTrace);
@ -1618,7 +1610,7 @@ export class Page extends EventEmitter {
async #onBindingCalled( async #onBindingCalled(
event: Protocol.Runtime.BindingCalledEvent event: Protocol.Runtime.BindingCalledEvent
): Promise<void> { ): Promise<void> {
let payload: { type: string; name: string; seq: number; args: unknown[] }; let payload: {type: string; name: string; seq: number; args: unknown[]};
try { try {
payload = JSON.parse(event.payload); payload = JSON.parse(event.payload);
} catch { } catch {
@ -1626,7 +1618,7 @@ export class Page extends EventEmitter {
// called before our wrapper was initialized. // called before our wrapper was initialized.
return; return;
} }
const { type, name, seq, args } = payload; const {type, name, seq, args} = payload;
if (type !== 'exposedFun' || !this.#pageBindings.has(name)) { if (type !== 'exposedFun' || !this.#pageBindings.has(name)) {
return; return;
} }
@ -1662,7 +1654,7 @@ export class Page extends EventEmitter {
stackTrace?: Protocol.Runtime.StackTrace stackTrace?: Protocol.Runtime.StackTrace
): void { ): void {
if (!this.listenerCount(PageEmittedEvents.Console)) { if (!this.listenerCount(PageEmittedEvents.Console)) {
args.forEach((arg) => { args.forEach(arg => {
return arg.dispose(); return arg.dispose();
}); });
return; return;
@ -1730,7 +1722,7 @@ export class Page extends EventEmitter {
*/ */
async #setTransparentBackgroundColor(): Promise<void> { async #setTransparentBackgroundColor(): Promise<void> {
await this.#client.send('Emulation.setDefaultBackgroundColorOverride', { await this.#client.send('Emulation.setDefaultBackgroundColorOverride', {
color: { r: 0, g: 0, b: 0, a: 0 }, color: {r: 0, g: 0, b: 0, a: 0},
}); });
} }
@ -1836,7 +1828,7 @@ export class Page extends EventEmitter {
*/ */
async goto( async goto(
url: string, url: string,
options: WaitForOptions & { referer?: string } = {} options: WaitForOptions & {referer?: string} = {}
): Promise<HTTPResponse | null> { ): Promise<HTTPResponse | null> {
return await this.#frameManager.mainFrame().goto(url, options); return await this.#frameManager.mainFrame().goto(url, options);
} }
@ -1910,7 +1902,7 @@ export class Page extends EventEmitter {
#sessionClosePromise(): Promise<Error> { #sessionClosePromise(): Promise<Error> {
if (!this.#disconnectPromise) { if (!this.#disconnectPromise) {
this.#disconnectPromise = new Promise((fulfill) => { this.#disconnectPromise = new Promise(fulfill => {
return this.#client.once(CDPSessionEmittedEvents.Disconnected, () => { return this.#client.once(CDPSessionEmittedEvents.Disconnected, () => {
return fulfill(new Error('Target closed')); return fulfill(new Error('Target closed'));
}); });
@ -1946,13 +1938,13 @@ export class Page extends EventEmitter {
*/ */
async waitForRequest( async waitForRequest(
urlOrPredicate: string | ((req: HTTPRequest) => boolean | Promise<boolean>), urlOrPredicate: string | ((req: HTTPRequest) => boolean | Promise<boolean>),
options: { timeout?: number } = {} options: {timeout?: number} = {}
): Promise<HTTPRequest> { ): Promise<HTTPRequest> {
const { timeout = this.#timeoutSettings.timeout() } = options; const {timeout = this.#timeoutSettings.timeout()} = options;
return waitForEvent( return waitForEvent(
this.#frameManager.networkManager(), this.#frameManager.networkManager(),
NetworkManagerEmittedEvents.Request, NetworkManagerEmittedEvents.Request,
(request) => { request => {
if (isString(urlOrPredicate)) { if (isString(urlOrPredicate)) {
return urlOrPredicate === request.url(); return urlOrPredicate === request.url();
} }
@ -1995,13 +1987,13 @@ export class Page extends EventEmitter {
urlOrPredicate: urlOrPredicate:
| string | string
| ((res: HTTPResponse) => boolean | Promise<boolean>), | ((res: HTTPResponse) => boolean | Promise<boolean>),
options: { timeout?: number } = {} options: {timeout?: number} = {}
): Promise<HTTPResponse> { ): Promise<HTTPResponse> {
const { timeout = this.#timeoutSettings.timeout() } = options; const {timeout = this.#timeoutSettings.timeout()} = options;
return waitForEvent( return waitForEvent(
this.#frameManager.networkManager(), this.#frameManager.networkManager(),
NetworkManagerEmittedEvents.Response, NetworkManagerEmittedEvents.Response,
async (response) => { async response => {
if (isString(urlOrPredicate)) { if (isString(urlOrPredicate)) {
return urlOrPredicate === response.url(); return urlOrPredicate === response.url();
} }
@ -2020,15 +2012,14 @@ export class Page extends EventEmitter {
* @returns Promise which resolves when network is idle * @returns Promise which resolves when network is idle
*/ */
async waitForNetworkIdle( async waitForNetworkIdle(
options: { idleTime?: number; timeout?: number } = {} options: {idleTime?: number; timeout?: number} = {}
): Promise<void> { ): Promise<void> {
const { idleTime = 500, timeout = this.#timeoutSettings.timeout() } = const {idleTime = 500, timeout = this.#timeoutSettings.timeout()} = options;
options;
const networkManager = this.#frameManager.networkManager(); const networkManager = this.#frameManager.networkManager();
let idleResolveCallback: () => void; let idleResolveCallback: () => void;
const idlePromise = new Promise<void>((resolve) => { const idlePromise = new Promise<void>(resolve => {
idleResolveCallback = resolve; idleResolveCallback = resolve;
}); });
@ -2081,11 +2072,11 @@ export class Page extends EventEmitter {
...eventPromises, ...eventPromises,
this.#sessionClosePromise(), this.#sessionClosePromise(),
]).then( ]).then(
(r) => { r => {
cleanup(); cleanup();
return r; return r;
}, },
(error) => { error => {
cleanup(); cleanup();
throw error; throw error;
} }
@ -2111,9 +2102,9 @@ export class Page extends EventEmitter {
*/ */
async waitForFrame( async waitForFrame(
urlOrPredicate: string | ((frame: Frame) => boolean | Promise<boolean>), urlOrPredicate: string | ((frame: Frame) => boolean | Promise<boolean>),
options: { timeout?: number } = {} options: {timeout?: number} = {}
): Promise<Frame> { ): Promise<Frame> {
const { timeout = this.#timeoutSettings.timeout() } = options; const {timeout = this.#timeoutSettings.timeout()} = options;
let predicate: (frame: Frame) => Promise<boolean>; let predicate: (frame: Frame) => Promise<boolean>;
if (isString(urlOrPredicate)) { if (isString(urlOrPredicate)) {
@ -2145,7 +2136,7 @@ export class Page extends EventEmitter {
timeout, timeout,
this.#sessionClosePromise() this.#sessionClosePromise()
), ),
...this.frames().map(async (frame) => { ...this.frames().map(async frame => {
if (await predicate(frame)) { if (await predicate(frame)) {
return frame; return frame;
} }
@ -2231,7 +2222,7 @@ export class Page extends EventEmitter {
} }
const result = await Promise.all([ const result = await Promise.all([
this.waitForNavigation(options), this.waitForNavigation(options),
this.#client.send('Page.navigateToHistoryEntry', { entryId: entry.id }), this.#client.send('Page.navigateToHistoryEntry', {entryId: entry.id}),
]); ]);
return result[0]; return result[0];
} }
@ -2302,7 +2293,7 @@ export class Page extends EventEmitter {
* before navigating to the domain. * before navigating to the domain.
*/ */
async setBypassCSP(enabled: boolean): Promise<void> { async setBypassCSP(enabled: boolean): Promise<void> {
await this.#client.send('Page.setBypassCSP', { enabled }); await this.#client.send('Page.setBypassCSP', {enabled});
} }
/** /**
@ -2850,17 +2841,17 @@ export class Page extends EventEmitter {
targetId: this.#target._targetId, targetId: this.#target._targetId,
}); });
let clip = options.clip ? processClip(options.clip) : undefined; let clip = options.clip ? processClip(options.clip) : undefined;
let { captureBeyondViewport = true } = options; let {captureBeyondViewport = true} = options;
captureBeyondViewport = captureBeyondViewport =
typeof captureBeyondViewport === 'boolean' ? captureBeyondViewport : true; typeof captureBeyondViewport === 'boolean' ? captureBeyondViewport : true;
if (options.fullPage) { if (options.fullPage) {
const metrics = await this.#client.send('Page.getLayoutMetrics'); const metrics = await this.#client.send('Page.getLayoutMetrics');
// Fallback to `contentSize` in case of using Firefox. // Fallback to `contentSize` in case of using Firefox.
const { width, height } = metrics.cssContentSize || metrics.contentSize; const {width, height} = metrics.cssContentSize || metrics.contentSize;
// Overwrite clip for full page. // Overwrite clip for full page.
clip = { x: 0, y: 0, width, height, scale: 1 }; clip = {x: 0, y: 0, width, height, scale: 1};
if (!captureBeyondViewport) { if (!captureBeyondViewport) {
const { const {
@ -2870,8 +2861,8 @@ export class Page extends EventEmitter {
} = this.#viewport || {}; } = this.#viewport || {};
const screenOrientation: Protocol.Emulation.ScreenOrientation = const screenOrientation: Protocol.Emulation.ScreenOrientation =
isLandscape isLandscape
? { angle: 90, type: 'landscapePrimary' } ? {angle: 90, type: 'landscapePrimary'}
: { angle: 0, type: 'portraitPrimary' }; : {angle: 0, type: 'portraitPrimary'};
await this.#client.send('Emulation.setDeviceMetricsOverride', { await this.#client.send('Emulation.setDeviceMetricsOverride', {
mobile: isMobile, mobile: isMobile,
width, width,
@ -2923,12 +2914,12 @@ export class Page extends EventEmitter {
function processClip( function processClip(
clip: ScreenshotClip clip: ScreenshotClip
): ScreenshotClip & { scale: number } { ): ScreenshotClip & {scale: number} {
const x = Math.round(clip.x); const x = Math.round(clip.x);
const y = Math.round(clip.y); const y = Math.round(clip.y);
const width = Math.round(clip.width + clip.x - x); const width = Math.round(clip.width + clip.x - x);
const height = Math.round(clip.height + clip.y - y); const height = Math.round(clip.height + clip.y - y);
return { x, y, width, height, scale: 1 }; return {x, y, width, height, scale: 1};
} }
} }
@ -3025,7 +3016,7 @@ export class Page extends EventEmitter {
* @returns * @returns
*/ */
async pdf(options: PDFOptions = {}): Promise<Buffer> { async pdf(options: PDFOptions = {}): Promise<Buffer> {
const { path = undefined } = options; const {path = undefined} = options;
const readable = await this.createPDFStream(options); const readable = await this.createPDFStream(options);
const buffer = await getReadableAsBuffer(readable, path); const buffer = await getReadableAsBuffer(readable, path);
assert(buffer, 'Could not create buffer'); assert(buffer, 'Could not create buffer');
@ -3042,7 +3033,7 @@ export class Page extends EventEmitter {
} }
async close( async close(
options: { runBeforeUnload?: boolean } = { runBeforeUnload: undefined } options: {runBeforeUnload?: boolean} = {runBeforeUnload: undefined}
): Promise<void> { ): Promise<void> {
const connection = this.#client.connection(); const connection = this.#client.connection();
assert( assert(
@ -3207,7 +3198,7 @@ export class Page extends EventEmitter {
type( type(
selector: string, selector: string,
text: string, text: string,
options?: { delay: number } options?: {delay: number}
): Promise<void> { ): Promise<void> {
return this.mainFrame().type(selector, text, options); return this.mainFrame().type(selector, text, options);
} }

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { puppeteerErrors, PuppeteerErrors } from './Errors.js'; import {puppeteerErrors, PuppeteerErrors} from './Errors.js';
import { ConnectionTransport } from './ConnectionTransport.js'; import {ConnectionTransport} from './ConnectionTransport.js';
import { _devicesMap, DevicesMap } from './DeviceDescriptors.js'; import {_devicesMap, DevicesMap} from './DeviceDescriptors.js';
import { Browser } from './Browser.js'; import {Browser} from './Browser.js';
import { import {
_registerCustomQueryHandler, _registerCustomQueryHandler,
_unregisterCustomQueryHandler, _unregisterCustomQueryHandler,
@ -24,11 +24,8 @@ import {
_clearCustomQueryHandlers, _clearCustomQueryHandlers,
CustomQueryHandler, CustomQueryHandler,
} from './QueryHandler.js'; } from './QueryHandler.js';
import { Product } from './Product.js'; import {Product} from './Product.js';
import { import {_connectToBrowser, BrowserConnectOptions} from './BrowserConnector.js';
_connectToBrowser,
BrowserConnectOptions,
} from './BrowserConnector.js';
import { import {
PredefinedNetworkConditions, PredefinedNetworkConditions,
networkConditions, networkConditions,

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { WaitForSelectorOptions, DOMWorld } from './DOMWorld.js'; import {WaitForSelectorOptions, DOMWorld} from './DOMWorld.js';
import { ElementHandle, JSHandle } from './JSHandle.js'; import {ElementHandle, JSHandle} from './JSHandle.js';
import { _ariaHandler } from './AriaQueryHandler.js'; import {_ariaHandler} from './AriaQueryHandler.js';
/** /**
* @internal * @internal
@ -211,7 +211,7 @@ export function _unregisterCustomQueryHandler(name: string): void {
* @internal * @internal
*/ */
export function _customQueryHandlerNames(): string[] { export function _customQueryHandlerNames(): string[] {
return [...queryHandlers.keys()].filter((name) => { return [...queryHandlers.keys()].filter(name => {
return !builtInHandlers.has(name); return !builtInHandlers.has(name);
}); });
} }
@ -232,7 +232,7 @@ export function _getQueryHandlerAndSelector(selector: string): {
} { } {
const hasCustomQueryHandler = /^[a-zA-Z]+\//.test(selector); const hasCustomQueryHandler = /^[a-zA-Z]+\//.test(selector);
if (!hasCustomQueryHandler) { if (!hasCustomQueryHandler) {
return { updatedSelector: selector, queryHandler: _defaultHandler }; return {updatedSelector: selector, queryHandler: _defaultHandler};
} }
const index = selector.indexOf('/'); const index = selector.indexOf('/');

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
/** /**
* The SecurityDetails class represents the security details of a * The SecurityDetails class represents the security details of a

View File

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Page, PageEmittedEvents } from './Page.js'; import {Page, PageEmittedEvents} from './Page.js';
import { WebWorker } from './WebWorker.js'; import {WebWorker} from './WebWorker.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { Browser, BrowserContext, IsPageTargetCallback } from './Browser.js'; import {Browser, BrowserContext, IsPageTargetCallback} from './Browser.js';
import { Viewport } from './PuppeteerViewport.js'; import {Viewport} from './PuppeteerViewport.js';
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { TaskQueue } from './TaskQueue.js'; import {TaskQueue} from './TaskQueue.js';
/** /**
* @public * @public
@ -84,9 +84,9 @@ export class Target {
this.#defaultViewport = defaultViewport ?? undefined; this.#defaultViewport = defaultViewport ?? undefined;
this.#screenshotTaskQueue = screenshotTaskQueue; this.#screenshotTaskQueue = screenshotTaskQueue;
this._isPageTargetCallback = isPageTargetCallback; this._isPageTargetCallback = isPageTargetCallback;
this._initializedPromise = new Promise<boolean>((fulfill) => { this._initializedPromise = new Promise<boolean>(fulfill => {
return (this._initializedCallback = fulfill); return (this._initializedCallback = fulfill);
}).then(async (success) => { }).then(async success => {
if (!success) { if (!success) {
return false; return false;
} }
@ -102,7 +102,7 @@ export class Target {
openerPage.emit(PageEmittedEvents.Popup, popupPage); openerPage.emit(PageEmittedEvents.Popup, popupPage);
return true; return true;
}); });
this._isClosedPromise = new Promise<void>((fulfill) => { this._isClosedPromise = new Promise<void>(fulfill => {
return (this._closedCallback = fulfill); return (this._closedCallback = fulfill);
}); });
this._isInitialized = this._isInitialized =
@ -132,7 +132,7 @@ export class Target {
*/ */
async page(): Promise<Page | null> { async page(): Promise<Page | null> {
if (this._isPageTargetCallback(this.#targetInfo) && !this.#pagePromise) { if (this._isPageTargetCallback(this.#targetInfo) && !this.#pagePromise) {
this.#pagePromise = this.#sessionFactory().then((client) => { this.#pagePromise = this.#sessionFactory().then(client => {
return Page._create( return Page._create(
client, client,
this, this,
@ -157,7 +157,7 @@ export class Target {
} }
if (!this.#workerPromise) { if (!this.#workerPromise) {
// TODO(einbinder): Make workers send their console logs. // TODO(einbinder): Make workers send their console logs.
this.#workerPromise = this.#sessionFactory().then((client) => { this.#workerPromise = this.#sessionFactory().then(client => {
return new WebWorker( return new WebWorker(
client, client,
this.#targetInfo.url, this.#targetInfo.url,
@ -220,7 +220,7 @@ export class Target {
* Get the target that opened this target. Top-level targets return `null`. * Get the target that opened this target. Top-level targets return `null`.
*/ */
opener(): Target | undefined { opener(): Target | undefined {
const { openerId } = this.#targetInfo; const {openerId} = this.#targetInfo;
if (!openerId) { if (!openerId) {
return; return;
} }

View File

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { assert } from './assert.js'; import {assert} from './assert.js';
import { import {
getReadableAsBuffer, getReadableAsBuffer,
getReadableFromProtocolStream, getReadableFromProtocolStream,
isErrorLike, isErrorLike,
} from './util.js'; } from './util.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
/** /**
* @public * @public
@ -83,24 +83,20 @@ export class Tracing {
'disabled-by-default-devtools.timeline.stack', 'disabled-by-default-devtools.timeline.stack',
'disabled-by-default-v8.cpu_profiler', 'disabled-by-default-v8.cpu_profiler',
]; ];
const { const {path, screenshots = false, categories = defaultCategories} = options;
path,
screenshots = false,
categories = defaultCategories,
} = options;
if (screenshots) { if (screenshots) {
categories.push('disabled-by-default-devtools.screenshot'); categories.push('disabled-by-default-devtools.screenshot');
} }
const excludedCategories = categories const excludedCategories = categories
.filter((cat) => { .filter(cat => {
return cat.startsWith('-'); return cat.startsWith('-');
}) })
.map((cat) => { .map(cat => {
return cat.slice(1); return cat.slice(1);
}); });
const includedCategories = categories.filter((cat) => { const includedCategories = categories.filter(cat => {
return !cat.startsWith('-'); return !cat.startsWith('-');
}); });
@ -126,7 +122,7 @@ export class Tracing {
resolve = x; resolve = x;
reject = y; reject = y;
}); });
this.#client.once('Tracing.tracingComplete', async (event) => { this.#client.once('Tracing.tracingComplete', async event => {
try { try {
const readable = await getReadableFromProtocolStream( const readable = await getReadableFromProtocolStream(
this.#client, this.#client,

View File

@ -295,22 +295,22 @@ export type KeyInput =
* @internal * @internal
*/ */
export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = { export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
'0': { keyCode: 48, key: '0', code: 'Digit0' }, '0': {keyCode: 48, key: '0', code: 'Digit0'},
'1': { keyCode: 49, key: '1', code: 'Digit1' }, '1': {keyCode: 49, key: '1', code: 'Digit1'},
'2': { keyCode: 50, key: '2', code: 'Digit2' }, '2': {keyCode: 50, key: '2', code: 'Digit2'},
'3': { keyCode: 51, key: '3', code: 'Digit3' }, '3': {keyCode: 51, key: '3', code: 'Digit3'},
'4': { keyCode: 52, key: '4', code: 'Digit4' }, '4': {keyCode: 52, key: '4', code: 'Digit4'},
'5': { keyCode: 53, key: '5', code: 'Digit5' }, '5': {keyCode: 53, key: '5', code: 'Digit5'},
'6': { keyCode: 54, key: '6', code: 'Digit6' }, '6': {keyCode: 54, key: '6', code: 'Digit6'},
'7': { keyCode: 55, key: '7', code: 'Digit7' }, '7': {keyCode: 55, key: '7', code: 'Digit7'},
'8': { keyCode: 56, key: '8', code: 'Digit8' }, '8': {keyCode: 56, key: '8', code: 'Digit8'},
'9': { keyCode: 57, key: '9', code: 'Digit9' }, '9': {keyCode: 57, key: '9', code: 'Digit9'},
Power: { key: 'Power', code: 'Power' }, Power: {key: 'Power', code: 'Power'},
Eject: { key: 'Eject', code: 'Eject' }, Eject: {key: 'Eject', code: 'Eject'},
Abort: { keyCode: 3, code: 'Abort', key: 'Cancel' }, Abort: {keyCode: 3, code: 'Abort', key: 'Cancel'},
Help: { keyCode: 6, code: 'Help', key: 'Help' }, Help: {keyCode: 6, code: 'Help', key: 'Help'},
Backspace: { keyCode: 8, code: 'Backspace', key: 'Backspace' }, Backspace: {keyCode: 8, code: 'Backspace', key: 'Backspace'},
Tab: { keyCode: 9, code: 'Tab', key: 'Tab' }, Tab: {keyCode: 9, code: 'Tab', key: 'Tab'},
Numpad5: { Numpad5: {
keyCode: 12, keyCode: 12,
shiftKeyCode: 101, shiftKeyCode: 101,
@ -326,11 +326,11 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
text: '\r', text: '\r',
location: 3, location: 3,
}, },
Enter: { keyCode: 13, code: 'Enter', key: 'Enter', text: '\r' }, Enter: {keyCode: 13, code: 'Enter', key: 'Enter', text: '\r'},
'\r': { keyCode: 13, code: 'Enter', key: 'Enter', text: '\r' }, '\r': {keyCode: 13, code: 'Enter', key: 'Enter', text: '\r'},
'\n': { keyCode: 13, code: 'Enter', key: 'Enter', text: '\r' }, '\n': {keyCode: 13, code: 'Enter', key: 'Enter', text: '\r'},
ShiftLeft: { keyCode: 16, code: 'ShiftLeft', key: 'Shift', location: 1 }, ShiftLeft: {keyCode: 16, code: 'ShiftLeft', key: 'Shift', location: 1},
ShiftRight: { keyCode: 16, code: 'ShiftRight', key: 'Shift', location: 2 }, ShiftRight: {keyCode: 16, code: 'ShiftRight', key: 'Shift', location: 2},
ControlLeft: { ControlLeft: {
keyCode: 17, keyCode: 17,
code: 'ControlLeft', code: 'ControlLeft',
@ -343,14 +343,14 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
key: 'Control', key: 'Control',
location: 2, location: 2,
}, },
AltLeft: { keyCode: 18, code: 'AltLeft', key: 'Alt', location: 1 }, AltLeft: {keyCode: 18, code: 'AltLeft', key: 'Alt', location: 1},
AltRight: { keyCode: 18, code: 'AltRight', key: 'Alt', location: 2 }, AltRight: {keyCode: 18, code: 'AltRight', key: 'Alt', location: 2},
Pause: { keyCode: 19, code: 'Pause', key: 'Pause' }, Pause: {keyCode: 19, code: 'Pause', key: 'Pause'},
CapsLock: { keyCode: 20, code: 'CapsLock', key: 'CapsLock' }, CapsLock: {keyCode: 20, code: 'CapsLock', key: 'CapsLock'},
Escape: { keyCode: 27, code: 'Escape', key: 'Escape' }, Escape: {keyCode: 27, code: 'Escape', key: 'Escape'},
Convert: { keyCode: 28, code: 'Convert', key: 'Convert' }, Convert: {keyCode: 28, code: 'Convert', key: 'Convert'},
NonConvert: { keyCode: 29, code: 'NonConvert', key: 'NonConvert' }, NonConvert: {keyCode: 29, code: 'NonConvert', key: 'NonConvert'},
Space: { keyCode: 32, code: 'Space', key: ' ' }, Space: {keyCode: 32, code: 'Space', key: ' '},
Numpad9: { Numpad9: {
keyCode: 33, keyCode: 33,
shiftKeyCode: 105, shiftKeyCode: 105,
@ -359,7 +359,7 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '9', shiftKey: '9',
location: 3, location: 3,
}, },
PageUp: { keyCode: 33, code: 'PageUp', key: 'PageUp' }, PageUp: {keyCode: 33, code: 'PageUp', key: 'PageUp'},
Numpad3: { Numpad3: {
keyCode: 34, keyCode: 34,
shiftKeyCode: 99, shiftKeyCode: 99,
@ -368,8 +368,8 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '3', shiftKey: '3',
location: 3, location: 3,
}, },
PageDown: { keyCode: 34, code: 'PageDown', key: 'PageDown' }, PageDown: {keyCode: 34, code: 'PageDown', key: 'PageDown'},
End: { keyCode: 35, code: 'End', key: 'End' }, End: {keyCode: 35, code: 'End', key: 'End'},
Numpad1: { Numpad1: {
keyCode: 35, keyCode: 35,
shiftKeyCode: 97, shiftKeyCode: 97,
@ -378,7 +378,7 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '1', shiftKey: '1',
location: 3, location: 3,
}, },
Home: { keyCode: 36, code: 'Home', key: 'Home' }, Home: {keyCode: 36, code: 'Home', key: 'Home'},
Numpad7: { Numpad7: {
keyCode: 36, keyCode: 36,
shiftKeyCode: 103, shiftKeyCode: 103,
@ -387,7 +387,7 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '7', shiftKey: '7',
location: 3, location: 3,
}, },
ArrowLeft: { keyCode: 37, code: 'ArrowLeft', key: 'ArrowLeft' }, ArrowLeft: {keyCode: 37, code: 'ArrowLeft', key: 'ArrowLeft'},
Numpad4: { Numpad4: {
keyCode: 37, keyCode: 37,
shiftKeyCode: 100, shiftKeyCode: 100,
@ -404,8 +404,8 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '8', shiftKey: '8',
location: 3, location: 3,
}, },
ArrowUp: { keyCode: 38, code: 'ArrowUp', key: 'ArrowUp' }, ArrowUp: {keyCode: 38, code: 'ArrowUp', key: 'ArrowUp'},
ArrowRight: { keyCode: 39, code: 'ArrowRight', key: 'ArrowRight' }, ArrowRight: {keyCode: 39, code: 'ArrowRight', key: 'ArrowRight'},
Numpad6: { Numpad6: {
keyCode: 39, keyCode: 39,
shiftKeyCode: 102, shiftKeyCode: 102,
@ -422,11 +422,11 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '2', shiftKey: '2',
location: 3, location: 3,
}, },
ArrowDown: { keyCode: 40, code: 'ArrowDown', key: 'ArrowDown' }, ArrowDown: {keyCode: 40, code: 'ArrowDown', key: 'ArrowDown'},
Select: { keyCode: 41, code: 'Select', key: 'Select' }, Select: {keyCode: 41, code: 'Select', key: 'Select'},
Open: { keyCode: 43, code: 'Open', key: 'Execute' }, Open: {keyCode: 43, code: 'Open', key: 'Execute'},
PrintScreen: { keyCode: 44, code: 'PrintScreen', key: 'PrintScreen' }, PrintScreen: {keyCode: 44, code: 'PrintScreen', key: 'PrintScreen'},
Insert: { keyCode: 45, code: 'Insert', key: 'Insert' }, Insert: {keyCode: 45, code: 'Insert', key: 'Insert'},
Numpad0: { Numpad0: {
keyCode: 45, keyCode: 45,
shiftKeyCode: 96, shiftKeyCode: 96,
@ -435,7 +435,7 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '0', shiftKey: '0',
location: 3, location: 3,
}, },
Delete: { keyCode: 46, code: 'Delete', key: 'Delete' }, Delete: {keyCode: 46, code: 'Delete', key: 'Delete'},
NumpadDecimal: { NumpadDecimal: {
keyCode: 46, keyCode: 46,
shiftKeyCode: 110, shiftKeyCode: 110,
@ -444,85 +444,85 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
shiftKey: '.', shiftKey: '.',
location: 3, location: 3,
}, },
Digit0: { keyCode: 48, code: 'Digit0', shiftKey: ')', key: '0' }, Digit0: {keyCode: 48, code: 'Digit0', shiftKey: ')', key: '0'},
Digit1: { keyCode: 49, code: 'Digit1', shiftKey: '!', key: '1' }, Digit1: {keyCode: 49, code: 'Digit1', shiftKey: '!', key: '1'},
Digit2: { keyCode: 50, code: 'Digit2', shiftKey: '@', key: '2' }, Digit2: {keyCode: 50, code: 'Digit2', shiftKey: '@', key: '2'},
Digit3: { keyCode: 51, code: 'Digit3', shiftKey: '#', key: '3' }, Digit3: {keyCode: 51, code: 'Digit3', shiftKey: '#', key: '3'},
Digit4: { keyCode: 52, code: 'Digit4', shiftKey: '$', key: '4' }, Digit4: {keyCode: 52, code: 'Digit4', shiftKey: '$', key: '4'},
Digit5: { keyCode: 53, code: 'Digit5', shiftKey: '%', key: '5' }, Digit5: {keyCode: 53, code: 'Digit5', shiftKey: '%', key: '5'},
Digit6: { keyCode: 54, code: 'Digit6', shiftKey: '^', key: '6' }, Digit6: {keyCode: 54, code: 'Digit6', shiftKey: '^', key: '6'},
Digit7: { keyCode: 55, code: 'Digit7', shiftKey: '&', key: '7' }, Digit7: {keyCode: 55, code: 'Digit7', shiftKey: '&', key: '7'},
Digit8: { keyCode: 56, code: 'Digit8', shiftKey: '*', key: '8' }, Digit8: {keyCode: 56, code: 'Digit8', shiftKey: '*', key: '8'},
Digit9: { keyCode: 57, code: 'Digit9', shiftKey: '(', key: '9' }, Digit9: {keyCode: 57, code: 'Digit9', shiftKey: '(', key: '9'},
KeyA: { keyCode: 65, code: 'KeyA', shiftKey: 'A', key: 'a' }, KeyA: {keyCode: 65, code: 'KeyA', shiftKey: 'A', key: 'a'},
KeyB: { keyCode: 66, code: 'KeyB', shiftKey: 'B', key: 'b' }, KeyB: {keyCode: 66, code: 'KeyB', shiftKey: 'B', key: 'b'},
KeyC: { keyCode: 67, code: 'KeyC', shiftKey: 'C', key: 'c' }, KeyC: {keyCode: 67, code: 'KeyC', shiftKey: 'C', key: 'c'},
KeyD: { keyCode: 68, code: 'KeyD', shiftKey: 'D', key: 'd' }, KeyD: {keyCode: 68, code: 'KeyD', shiftKey: 'D', key: 'd'},
KeyE: { keyCode: 69, code: 'KeyE', shiftKey: 'E', key: 'e' }, KeyE: {keyCode: 69, code: 'KeyE', shiftKey: 'E', key: 'e'},
KeyF: { keyCode: 70, code: 'KeyF', shiftKey: 'F', key: 'f' }, KeyF: {keyCode: 70, code: 'KeyF', shiftKey: 'F', key: 'f'},
KeyG: { keyCode: 71, code: 'KeyG', shiftKey: 'G', key: 'g' }, KeyG: {keyCode: 71, code: 'KeyG', shiftKey: 'G', key: 'g'},
KeyH: { keyCode: 72, code: 'KeyH', shiftKey: 'H', key: 'h' }, KeyH: {keyCode: 72, code: 'KeyH', shiftKey: 'H', key: 'h'},
KeyI: { keyCode: 73, code: 'KeyI', shiftKey: 'I', key: 'i' }, KeyI: {keyCode: 73, code: 'KeyI', shiftKey: 'I', key: 'i'},
KeyJ: { keyCode: 74, code: 'KeyJ', shiftKey: 'J', key: 'j' }, KeyJ: {keyCode: 74, code: 'KeyJ', shiftKey: 'J', key: 'j'},
KeyK: { keyCode: 75, code: 'KeyK', shiftKey: 'K', key: 'k' }, KeyK: {keyCode: 75, code: 'KeyK', shiftKey: 'K', key: 'k'},
KeyL: { keyCode: 76, code: 'KeyL', shiftKey: 'L', key: 'l' }, KeyL: {keyCode: 76, code: 'KeyL', shiftKey: 'L', key: 'l'},
KeyM: { keyCode: 77, code: 'KeyM', shiftKey: 'M', key: 'm' }, KeyM: {keyCode: 77, code: 'KeyM', shiftKey: 'M', key: 'm'},
KeyN: { keyCode: 78, code: 'KeyN', shiftKey: 'N', key: 'n' }, KeyN: {keyCode: 78, code: 'KeyN', shiftKey: 'N', key: 'n'},
KeyO: { keyCode: 79, code: 'KeyO', shiftKey: 'O', key: 'o' }, KeyO: {keyCode: 79, code: 'KeyO', shiftKey: 'O', key: 'o'},
KeyP: { keyCode: 80, code: 'KeyP', shiftKey: 'P', key: 'p' }, KeyP: {keyCode: 80, code: 'KeyP', shiftKey: 'P', key: 'p'},
KeyQ: { keyCode: 81, code: 'KeyQ', shiftKey: 'Q', key: 'q' }, KeyQ: {keyCode: 81, code: 'KeyQ', shiftKey: 'Q', key: 'q'},
KeyR: { keyCode: 82, code: 'KeyR', shiftKey: 'R', key: 'r' }, KeyR: {keyCode: 82, code: 'KeyR', shiftKey: 'R', key: 'r'},
KeyS: { keyCode: 83, code: 'KeyS', shiftKey: 'S', key: 's' }, KeyS: {keyCode: 83, code: 'KeyS', shiftKey: 'S', key: 's'},
KeyT: { keyCode: 84, code: 'KeyT', shiftKey: 'T', key: 't' }, KeyT: {keyCode: 84, code: 'KeyT', shiftKey: 'T', key: 't'},
KeyU: { keyCode: 85, code: 'KeyU', shiftKey: 'U', key: 'u' }, KeyU: {keyCode: 85, code: 'KeyU', shiftKey: 'U', key: 'u'},
KeyV: { keyCode: 86, code: 'KeyV', shiftKey: 'V', key: 'v' }, KeyV: {keyCode: 86, code: 'KeyV', shiftKey: 'V', key: 'v'},
KeyW: { keyCode: 87, code: 'KeyW', shiftKey: 'W', key: 'w' }, KeyW: {keyCode: 87, code: 'KeyW', shiftKey: 'W', key: 'w'},
KeyX: { keyCode: 88, code: 'KeyX', shiftKey: 'X', key: 'x' }, KeyX: {keyCode: 88, code: 'KeyX', shiftKey: 'X', key: 'x'},
KeyY: { keyCode: 89, code: 'KeyY', shiftKey: 'Y', key: 'y' }, KeyY: {keyCode: 89, code: 'KeyY', shiftKey: 'Y', key: 'y'},
KeyZ: { keyCode: 90, code: 'KeyZ', shiftKey: 'Z', key: 'z' }, KeyZ: {keyCode: 90, code: 'KeyZ', shiftKey: 'Z', key: 'z'},
MetaLeft: { keyCode: 91, code: 'MetaLeft', key: 'Meta', location: 1 }, MetaLeft: {keyCode: 91, code: 'MetaLeft', key: 'Meta', location: 1},
MetaRight: { keyCode: 92, code: 'MetaRight', key: 'Meta', location: 2 }, MetaRight: {keyCode: 92, code: 'MetaRight', key: 'Meta', location: 2},
ContextMenu: { keyCode: 93, code: 'ContextMenu', key: 'ContextMenu' }, ContextMenu: {keyCode: 93, code: 'ContextMenu', key: 'ContextMenu'},
NumpadMultiply: { NumpadMultiply: {
keyCode: 106, keyCode: 106,
code: 'NumpadMultiply', code: 'NumpadMultiply',
key: '*', key: '*',
location: 3, location: 3,
}, },
NumpadAdd: { keyCode: 107, code: 'NumpadAdd', key: '+', location: 3 }, NumpadAdd: {keyCode: 107, code: 'NumpadAdd', key: '+', location: 3},
NumpadSubtract: { NumpadSubtract: {
keyCode: 109, keyCode: 109,
code: 'NumpadSubtract', code: 'NumpadSubtract',
key: '-', key: '-',
location: 3, location: 3,
}, },
NumpadDivide: { keyCode: 111, code: 'NumpadDivide', key: '/', location: 3 }, NumpadDivide: {keyCode: 111, code: 'NumpadDivide', key: '/', location: 3},
F1: { keyCode: 112, code: 'F1', key: 'F1' }, F1: {keyCode: 112, code: 'F1', key: 'F1'},
F2: { keyCode: 113, code: 'F2', key: 'F2' }, F2: {keyCode: 113, code: 'F2', key: 'F2'},
F3: { keyCode: 114, code: 'F3', key: 'F3' }, F3: {keyCode: 114, code: 'F3', key: 'F3'},
F4: { keyCode: 115, code: 'F4', key: 'F4' }, F4: {keyCode: 115, code: 'F4', key: 'F4'},
F5: { keyCode: 116, code: 'F5', key: 'F5' }, F5: {keyCode: 116, code: 'F5', key: 'F5'},
F6: { keyCode: 117, code: 'F6', key: 'F6' }, F6: {keyCode: 117, code: 'F6', key: 'F6'},
F7: { keyCode: 118, code: 'F7', key: 'F7' }, F7: {keyCode: 118, code: 'F7', key: 'F7'},
F8: { keyCode: 119, code: 'F8', key: 'F8' }, F8: {keyCode: 119, code: 'F8', key: 'F8'},
F9: { keyCode: 120, code: 'F9', key: 'F9' }, F9: {keyCode: 120, code: 'F9', key: 'F9'},
F10: { keyCode: 121, code: 'F10', key: 'F10' }, F10: {keyCode: 121, code: 'F10', key: 'F10'},
F11: { keyCode: 122, code: 'F11', key: 'F11' }, F11: {keyCode: 122, code: 'F11', key: 'F11'},
F12: { keyCode: 123, code: 'F12', key: 'F12' }, F12: {keyCode: 123, code: 'F12', key: 'F12'},
F13: { keyCode: 124, code: 'F13', key: 'F13' }, F13: {keyCode: 124, code: 'F13', key: 'F13'},
F14: { keyCode: 125, code: 'F14', key: 'F14' }, F14: {keyCode: 125, code: 'F14', key: 'F14'},
F15: { keyCode: 126, code: 'F15', key: 'F15' }, F15: {keyCode: 126, code: 'F15', key: 'F15'},
F16: { keyCode: 127, code: 'F16', key: 'F16' }, F16: {keyCode: 127, code: 'F16', key: 'F16'},
F17: { keyCode: 128, code: 'F17', key: 'F17' }, F17: {keyCode: 128, code: 'F17', key: 'F17'},
F18: { keyCode: 129, code: 'F18', key: 'F18' }, F18: {keyCode: 129, code: 'F18', key: 'F18'},
F19: { keyCode: 130, code: 'F19', key: 'F19' }, F19: {keyCode: 130, code: 'F19', key: 'F19'},
F20: { keyCode: 131, code: 'F20', key: 'F20' }, F20: {keyCode: 131, code: 'F20', key: 'F20'},
F21: { keyCode: 132, code: 'F21', key: 'F21' }, F21: {keyCode: 132, code: 'F21', key: 'F21'},
F22: { keyCode: 133, code: 'F22', key: 'F22' }, F22: {keyCode: 133, code: 'F22', key: 'F22'},
F23: { keyCode: 134, code: 'F23', key: 'F23' }, F23: {keyCode: 134, code: 'F23', key: 'F23'},
F24: { keyCode: 135, code: 'F24', key: 'F24' }, F24: {keyCode: 135, code: 'F24', key: 'F24'},
NumLock: { keyCode: 144, code: 'NumLock', key: 'NumLock' }, NumLock: {keyCode: 144, code: 'NumLock', key: 'NumLock'},
ScrollLock: { keyCode: 145, code: 'ScrollLock', key: 'ScrollLock' }, ScrollLock: {keyCode: 145, code: 'ScrollLock', key: 'ScrollLock'},
AudioVolumeMute: { AudioVolumeMute: {
keyCode: 173, keyCode: 173,
code: 'AudioVolumeMute', code: 'AudioVolumeMute',
@ -533,7 +533,7 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
code: 'AudioVolumeDown', code: 'AudioVolumeDown',
key: 'AudioVolumeDown', key: 'AudioVolumeDown',
}, },
AudioVolumeUp: { keyCode: 175, code: 'AudioVolumeUp', key: 'AudioVolumeUp' }, AudioVolumeUp: {keyCode: 175, code: 'AudioVolumeUp', key: 'AudioVolumeUp'},
MediaTrackNext: { MediaTrackNext: {
keyCode: 176, keyCode: 176,
code: 'MediaTrackNext', code: 'MediaTrackNext',
@ -544,138 +544,138 @@ export const _keyDefinitions: Readonly<Record<KeyInput, KeyDefinition>> = {
code: 'MediaTrackPrevious', code: 'MediaTrackPrevious',
key: 'MediaTrackPrevious', key: 'MediaTrackPrevious',
}, },
MediaStop: { keyCode: 178, code: 'MediaStop', key: 'MediaStop' }, MediaStop: {keyCode: 178, code: 'MediaStop', key: 'MediaStop'},
MediaPlayPause: { MediaPlayPause: {
keyCode: 179, keyCode: 179,
code: 'MediaPlayPause', code: 'MediaPlayPause',
key: 'MediaPlayPause', key: 'MediaPlayPause',
}, },
Semicolon: { keyCode: 186, code: 'Semicolon', shiftKey: ':', key: ';' }, Semicolon: {keyCode: 186, code: 'Semicolon', shiftKey: ':', key: ';'},
Equal: { keyCode: 187, code: 'Equal', shiftKey: '+', key: '=' }, Equal: {keyCode: 187, code: 'Equal', shiftKey: '+', key: '='},
NumpadEqual: { keyCode: 187, code: 'NumpadEqual', key: '=', location: 3 }, NumpadEqual: {keyCode: 187, code: 'NumpadEqual', key: '=', location: 3},
Comma: { keyCode: 188, code: 'Comma', shiftKey: '<', key: ',' }, Comma: {keyCode: 188, code: 'Comma', shiftKey: '<', key: ','},
Minus: { keyCode: 189, code: 'Minus', shiftKey: '_', key: '-' }, Minus: {keyCode: 189, code: 'Minus', shiftKey: '_', key: '-'},
Period: { keyCode: 190, code: 'Period', shiftKey: '>', key: '.' }, Period: {keyCode: 190, code: 'Period', shiftKey: '>', key: '.'},
Slash: { keyCode: 191, code: 'Slash', shiftKey: '?', key: '/' }, Slash: {keyCode: 191, code: 'Slash', shiftKey: '?', key: '/'},
Backquote: { keyCode: 192, code: 'Backquote', shiftKey: '~', key: '`' }, Backquote: {keyCode: 192, code: 'Backquote', shiftKey: '~', key: '`'},
BracketLeft: { keyCode: 219, code: 'BracketLeft', shiftKey: '{', key: '[' }, BracketLeft: {keyCode: 219, code: 'BracketLeft', shiftKey: '{', key: '['},
Backslash: { keyCode: 220, code: 'Backslash', shiftKey: '|', key: '\\' }, Backslash: {keyCode: 220, code: 'Backslash', shiftKey: '|', key: '\\'},
BracketRight: { keyCode: 221, code: 'BracketRight', shiftKey: '}', key: ']' }, BracketRight: {keyCode: 221, code: 'BracketRight', shiftKey: '}', key: ']'},
Quote: { keyCode: 222, code: 'Quote', shiftKey: '"', key: "'" }, Quote: {keyCode: 222, code: 'Quote', shiftKey: '"', key: "'"},
AltGraph: { keyCode: 225, code: 'AltGraph', key: 'AltGraph' }, AltGraph: {keyCode: 225, code: 'AltGraph', key: 'AltGraph'},
Props: { keyCode: 247, code: 'Props', key: 'CrSel' }, Props: {keyCode: 247, code: 'Props', key: 'CrSel'},
Cancel: { keyCode: 3, key: 'Cancel', code: 'Abort' }, Cancel: {keyCode: 3, key: 'Cancel', code: 'Abort'},
Clear: { keyCode: 12, key: 'Clear', code: 'Numpad5', location: 3 }, Clear: {keyCode: 12, key: 'Clear', code: 'Numpad5', location: 3},
Shift: { keyCode: 16, key: 'Shift', code: 'ShiftLeft', location: 1 }, Shift: {keyCode: 16, key: 'Shift', code: 'ShiftLeft', location: 1},
Control: { keyCode: 17, key: 'Control', code: 'ControlLeft', location: 1 }, Control: {keyCode: 17, key: 'Control', code: 'ControlLeft', location: 1},
Alt: { keyCode: 18, key: 'Alt', code: 'AltLeft', location: 1 }, Alt: {keyCode: 18, key: 'Alt', code: 'AltLeft', location: 1},
Accept: { keyCode: 30, key: 'Accept' }, Accept: {keyCode: 30, key: 'Accept'},
ModeChange: { keyCode: 31, key: 'ModeChange' }, ModeChange: {keyCode: 31, key: 'ModeChange'},
' ': { keyCode: 32, key: ' ', code: 'Space' }, ' ': {keyCode: 32, key: ' ', code: 'Space'},
Print: { keyCode: 42, key: 'Print' }, Print: {keyCode: 42, key: 'Print'},
Execute: { keyCode: 43, key: 'Execute', code: 'Open' }, Execute: {keyCode: 43, key: 'Execute', code: 'Open'},
'\u0000': { keyCode: 46, key: '\u0000', code: 'NumpadDecimal', location: 3 }, '\u0000': {keyCode: 46, key: '\u0000', code: 'NumpadDecimal', location: 3},
a: { keyCode: 65, key: 'a', code: 'KeyA' }, a: {keyCode: 65, key: 'a', code: 'KeyA'},
b: { keyCode: 66, key: 'b', code: 'KeyB' }, b: {keyCode: 66, key: 'b', code: 'KeyB'},
c: { keyCode: 67, key: 'c', code: 'KeyC' }, c: {keyCode: 67, key: 'c', code: 'KeyC'},
d: { keyCode: 68, key: 'd', code: 'KeyD' }, d: {keyCode: 68, key: 'd', code: 'KeyD'},
e: { keyCode: 69, key: 'e', code: 'KeyE' }, e: {keyCode: 69, key: 'e', code: 'KeyE'},
f: { keyCode: 70, key: 'f', code: 'KeyF' }, f: {keyCode: 70, key: 'f', code: 'KeyF'},
g: { keyCode: 71, key: 'g', code: 'KeyG' }, g: {keyCode: 71, key: 'g', code: 'KeyG'},
h: { keyCode: 72, key: 'h', code: 'KeyH' }, h: {keyCode: 72, key: 'h', code: 'KeyH'},
i: { keyCode: 73, key: 'i', code: 'KeyI' }, i: {keyCode: 73, key: 'i', code: 'KeyI'},
j: { keyCode: 74, key: 'j', code: 'KeyJ' }, j: {keyCode: 74, key: 'j', code: 'KeyJ'},
k: { keyCode: 75, key: 'k', code: 'KeyK' }, k: {keyCode: 75, key: 'k', code: 'KeyK'},
l: { keyCode: 76, key: 'l', code: 'KeyL' }, l: {keyCode: 76, key: 'l', code: 'KeyL'},
m: { keyCode: 77, key: 'm', code: 'KeyM' }, m: {keyCode: 77, key: 'm', code: 'KeyM'},
n: { keyCode: 78, key: 'n', code: 'KeyN' }, n: {keyCode: 78, key: 'n', code: 'KeyN'},
o: { keyCode: 79, key: 'o', code: 'KeyO' }, o: {keyCode: 79, key: 'o', code: 'KeyO'},
p: { keyCode: 80, key: 'p', code: 'KeyP' }, p: {keyCode: 80, key: 'p', code: 'KeyP'},
q: { keyCode: 81, key: 'q', code: 'KeyQ' }, q: {keyCode: 81, key: 'q', code: 'KeyQ'},
r: { keyCode: 82, key: 'r', code: 'KeyR' }, r: {keyCode: 82, key: 'r', code: 'KeyR'},
s: { keyCode: 83, key: 's', code: 'KeyS' }, s: {keyCode: 83, key: 's', code: 'KeyS'},
t: { keyCode: 84, key: 't', code: 'KeyT' }, t: {keyCode: 84, key: 't', code: 'KeyT'},
u: { keyCode: 85, key: 'u', code: 'KeyU' }, u: {keyCode: 85, key: 'u', code: 'KeyU'},
v: { keyCode: 86, key: 'v', code: 'KeyV' }, v: {keyCode: 86, key: 'v', code: 'KeyV'},
w: { keyCode: 87, key: 'w', code: 'KeyW' }, w: {keyCode: 87, key: 'w', code: 'KeyW'},
x: { keyCode: 88, key: 'x', code: 'KeyX' }, x: {keyCode: 88, key: 'x', code: 'KeyX'},
y: { keyCode: 89, key: 'y', code: 'KeyY' }, y: {keyCode: 89, key: 'y', code: 'KeyY'},
z: { keyCode: 90, key: 'z', code: 'KeyZ' }, z: {keyCode: 90, key: 'z', code: 'KeyZ'},
Meta: { keyCode: 91, key: 'Meta', code: 'MetaLeft', location: 1 }, Meta: {keyCode: 91, key: 'Meta', code: 'MetaLeft', location: 1},
'*': { keyCode: 106, key: '*', code: 'NumpadMultiply', location: 3 }, '*': {keyCode: 106, key: '*', code: 'NumpadMultiply', location: 3},
'+': { keyCode: 107, key: '+', code: 'NumpadAdd', location: 3 }, '+': {keyCode: 107, key: '+', code: 'NumpadAdd', location: 3},
'-': { keyCode: 109, key: '-', code: 'NumpadSubtract', location: 3 }, '-': {keyCode: 109, key: '-', code: 'NumpadSubtract', location: 3},
'/': { keyCode: 111, key: '/', code: 'NumpadDivide', location: 3 }, '/': {keyCode: 111, key: '/', code: 'NumpadDivide', location: 3},
';': { keyCode: 186, key: ';', code: 'Semicolon' }, ';': {keyCode: 186, key: ';', code: 'Semicolon'},
'=': { keyCode: 187, key: '=', code: 'Equal' }, '=': {keyCode: 187, key: '=', code: 'Equal'},
',': { keyCode: 188, key: ',', code: 'Comma' }, ',': {keyCode: 188, key: ',', code: 'Comma'},
'.': { keyCode: 190, key: '.', code: 'Period' }, '.': {keyCode: 190, key: '.', code: 'Period'},
'`': { keyCode: 192, key: '`', code: 'Backquote' }, '`': {keyCode: 192, key: '`', code: 'Backquote'},
'[': { keyCode: 219, key: '[', code: 'BracketLeft' }, '[': {keyCode: 219, key: '[', code: 'BracketLeft'},
'\\': { keyCode: 220, key: '\\', code: 'Backslash' }, '\\': {keyCode: 220, key: '\\', code: 'Backslash'},
']': { keyCode: 221, key: ']', code: 'BracketRight' }, ']': {keyCode: 221, key: ']', code: 'BracketRight'},
"'": { keyCode: 222, key: "'", code: 'Quote' }, "'": {keyCode: 222, key: "'", code: 'Quote'},
Attn: { keyCode: 246, key: 'Attn' }, Attn: {keyCode: 246, key: 'Attn'},
CrSel: { keyCode: 247, key: 'CrSel', code: 'Props' }, CrSel: {keyCode: 247, key: 'CrSel', code: 'Props'},
ExSel: { keyCode: 248, key: 'ExSel' }, ExSel: {keyCode: 248, key: 'ExSel'},
EraseEof: { keyCode: 249, key: 'EraseEof' }, EraseEof: {keyCode: 249, key: 'EraseEof'},
Play: { keyCode: 250, key: 'Play' }, Play: {keyCode: 250, key: 'Play'},
ZoomOut: { keyCode: 251, key: 'ZoomOut' }, ZoomOut: {keyCode: 251, key: 'ZoomOut'},
')': { keyCode: 48, key: ')', code: 'Digit0' }, ')': {keyCode: 48, key: ')', code: 'Digit0'},
'!': { keyCode: 49, key: '!', code: 'Digit1' }, '!': {keyCode: 49, key: '!', code: 'Digit1'},
'@': { keyCode: 50, key: '@', code: 'Digit2' }, '@': {keyCode: 50, key: '@', code: 'Digit2'},
'#': { keyCode: 51, key: '#', code: 'Digit3' }, '#': {keyCode: 51, key: '#', code: 'Digit3'},
$: { keyCode: 52, key: '$', code: 'Digit4' }, $: {keyCode: 52, key: '$', code: 'Digit4'},
'%': { keyCode: 53, key: '%', code: 'Digit5' }, '%': {keyCode: 53, key: '%', code: 'Digit5'},
'^': { keyCode: 54, key: '^', code: 'Digit6' }, '^': {keyCode: 54, key: '^', code: 'Digit6'},
'&': { keyCode: 55, key: '&', code: 'Digit7' }, '&': {keyCode: 55, key: '&', code: 'Digit7'},
'(': { keyCode: 57, key: '(', code: 'Digit9' }, '(': {keyCode: 57, key: '(', code: 'Digit9'},
A: { keyCode: 65, key: 'A', code: 'KeyA' }, A: {keyCode: 65, key: 'A', code: 'KeyA'},
B: { keyCode: 66, key: 'B', code: 'KeyB' }, B: {keyCode: 66, key: 'B', code: 'KeyB'},
C: { keyCode: 67, key: 'C', code: 'KeyC' }, C: {keyCode: 67, key: 'C', code: 'KeyC'},
D: { keyCode: 68, key: 'D', code: 'KeyD' }, D: {keyCode: 68, key: 'D', code: 'KeyD'},
E: { keyCode: 69, key: 'E', code: 'KeyE' }, E: {keyCode: 69, key: 'E', code: 'KeyE'},
F: { keyCode: 70, key: 'F', code: 'KeyF' }, F: {keyCode: 70, key: 'F', code: 'KeyF'},
G: { keyCode: 71, key: 'G', code: 'KeyG' }, G: {keyCode: 71, key: 'G', code: 'KeyG'},
H: { keyCode: 72, key: 'H', code: 'KeyH' }, H: {keyCode: 72, key: 'H', code: 'KeyH'},
I: { keyCode: 73, key: 'I', code: 'KeyI' }, I: {keyCode: 73, key: 'I', code: 'KeyI'},
J: { keyCode: 74, key: 'J', code: 'KeyJ' }, J: {keyCode: 74, key: 'J', code: 'KeyJ'},
K: { keyCode: 75, key: 'K', code: 'KeyK' }, K: {keyCode: 75, key: 'K', code: 'KeyK'},
L: { keyCode: 76, key: 'L', code: 'KeyL' }, L: {keyCode: 76, key: 'L', code: 'KeyL'},
M: { keyCode: 77, key: 'M', code: 'KeyM' }, M: {keyCode: 77, key: 'M', code: 'KeyM'},
N: { keyCode: 78, key: 'N', code: 'KeyN' }, N: {keyCode: 78, key: 'N', code: 'KeyN'},
O: { keyCode: 79, key: 'O', code: 'KeyO' }, O: {keyCode: 79, key: 'O', code: 'KeyO'},
P: { keyCode: 80, key: 'P', code: 'KeyP' }, P: {keyCode: 80, key: 'P', code: 'KeyP'},
Q: { keyCode: 81, key: 'Q', code: 'KeyQ' }, Q: {keyCode: 81, key: 'Q', code: 'KeyQ'},
R: { keyCode: 82, key: 'R', code: 'KeyR' }, R: {keyCode: 82, key: 'R', code: 'KeyR'},
S: { keyCode: 83, key: 'S', code: 'KeyS' }, S: {keyCode: 83, key: 'S', code: 'KeyS'},
T: { keyCode: 84, key: 'T', code: 'KeyT' }, T: {keyCode: 84, key: 'T', code: 'KeyT'},
U: { keyCode: 85, key: 'U', code: 'KeyU' }, U: {keyCode: 85, key: 'U', code: 'KeyU'},
V: { keyCode: 86, key: 'V', code: 'KeyV' }, V: {keyCode: 86, key: 'V', code: 'KeyV'},
W: { keyCode: 87, key: 'W', code: 'KeyW' }, W: {keyCode: 87, key: 'W', code: 'KeyW'},
X: { keyCode: 88, key: 'X', code: 'KeyX' }, X: {keyCode: 88, key: 'X', code: 'KeyX'},
Y: { keyCode: 89, key: 'Y', code: 'KeyY' }, Y: {keyCode: 89, key: 'Y', code: 'KeyY'},
Z: { keyCode: 90, key: 'Z', code: 'KeyZ' }, Z: {keyCode: 90, key: 'Z', code: 'KeyZ'},
':': { keyCode: 186, key: ':', code: 'Semicolon' }, ':': {keyCode: 186, key: ':', code: 'Semicolon'},
'<': { keyCode: 188, key: '<', code: 'Comma' }, '<': {keyCode: 188, key: '<', code: 'Comma'},
_: { keyCode: 189, key: '_', code: 'Minus' }, _: {keyCode: 189, key: '_', code: 'Minus'},
'>': { keyCode: 190, key: '>', code: 'Period' }, '>': {keyCode: 190, key: '>', code: 'Period'},
'?': { keyCode: 191, key: '?', code: 'Slash' }, '?': {keyCode: 191, key: '?', code: 'Slash'},
'~': { keyCode: 192, key: '~', code: 'Backquote' }, '~': {keyCode: 192, key: '~', code: 'Backquote'},
'{': { keyCode: 219, key: '{', code: 'BracketLeft' }, '{': {keyCode: 219, key: '{', code: 'BracketLeft'},
'|': { keyCode: 220, key: '|', code: 'Backslash' }, '|': {keyCode: 220, key: '|', code: 'Backslash'},
'}': { keyCode: 221, key: '}', code: 'BracketRight' }, '}': {keyCode: 221, key: '}', code: 'BracketRight'},
'"': { keyCode: 222, key: '"', code: 'Quote' }, '"': {keyCode: 222, key: '"', code: 'Quote'},
SoftLeft: { key: 'SoftLeft', code: 'SoftLeft', location: 4 }, SoftLeft: {key: 'SoftLeft', code: 'SoftLeft', location: 4},
SoftRight: { key: 'SoftRight', code: 'SoftRight', location: 4 }, SoftRight: {key: 'SoftRight', code: 'SoftRight', location: 4},
Camera: { keyCode: 44, key: 'Camera', code: 'Camera', location: 4 }, Camera: {keyCode: 44, key: 'Camera', code: 'Camera', location: 4},
Call: { key: 'Call', code: 'Call', location: 4 }, Call: {key: 'Call', code: 'Call', location: 4},
EndCall: { keyCode: 95, key: 'EndCall', code: 'EndCall', location: 4 }, EndCall: {keyCode: 95, key: 'EndCall', code: 'EndCall', location: 4},
VolumeDown: { VolumeDown: {
keyCode: 182, keyCode: 182,
key: 'VolumeDown', key: 'VolumeDown',
code: 'VolumeDown', code: 'VolumeDown',
location: 4, location: 4,
}, },
VolumeUp: { keyCode: 183, key: 'VolumeUp', code: 'VolumeUp', location: 4 }, VolumeUp: {keyCode: 183, key: 'VolumeUp', code: 'VolumeUp', location: 4},
}; };

View File

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { ConsoleMessageType } from './ConsoleMessage.js'; import {ConsoleMessageType} from './ConsoleMessage.js';
import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes.js'; import {EvaluateHandleFn, SerializableOrJSHandle} from './EvalTypes.js';
import { EventEmitter } from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import { ExecutionContext } from './ExecutionContext.js'; import {ExecutionContext} from './ExecutionContext.js';
import { debugError } from './util.js'; import {debugError} from './util.js';
import { JSHandle } from './JSHandle.js'; import {JSHandle} from './JSHandle.js';
/** /**
* @internal * @internal
@ -79,14 +79,14 @@ export class WebWorker extends EventEmitter {
super(); super();
this.#client = client; this.#client = client;
this.#url = url; this.#url = url;
this.#executionContextPromise = new Promise<ExecutionContext>((x) => { this.#executionContextPromise = new Promise<ExecutionContext>(x => {
return (this.#executionContextCallback = x); return (this.#executionContextCallback = x);
}); });
let jsHandleFactory: JSHandleFactory; let jsHandleFactory: JSHandleFactory;
this.#client.once('Runtime.executionContextCreated', async (event) => { this.#client.once('Runtime.executionContextCreated', async event => {
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
jsHandleFactory = (remoteObject) => { jsHandleFactory = remoteObject => {
return new JSHandle(executionContext, client, remoteObject); return new JSHandle(executionContext, client, remoteObject);
}; };
const executionContext = new ExecutionContext(client, event.context); const executionContext = new ExecutionContext(client, event.context);
@ -95,14 +95,14 @@ export class WebWorker extends EventEmitter {
// This might fail if the target is closed before we receive all execution contexts. // This might fail if the target is closed before we receive all execution contexts.
this.#client.send('Runtime.enable').catch(debugError); this.#client.send('Runtime.enable').catch(debugError);
this.#client.on('Runtime.consoleAPICalled', (event) => { this.#client.on('Runtime.consoleAPICalled', event => {
return consoleAPICalled( return consoleAPICalled(
event.type, event.type,
event.args.map(jsHandleFactory), event.args.map(jsHandleFactory),
event.stackTrace event.stackTrace
); );
}); });
this.#client.on('Runtime.exceptionThrown', (exception) => { this.#client.on('Runtime.exceptionThrown', exception => {
return exceptionThrown(exception.exceptionDetails); return exceptionThrown(exception.exceptionDetails);
}); });
} }

View File

@ -14,14 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { Protocol } from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import type { Readable } from 'stream'; import type {Readable} from 'stream';
import { isNode } from '../environment.js'; import {isNode} from '../environment.js';
import { assert } from './assert.js'; import {assert} from './assert.js';
import { CDPSession } from './Connection.js'; import {CDPSession} from './Connection.js';
import { debug } from './Debug.js'; import {debug} from './Debug.js';
import { TimeoutError } from './Errors.js'; import {TimeoutError} from './Errors.js';
import { CommonEventEmitter } from './EventEmitter.js'; import {CommonEventEmitter} from './EventEmitter.js';
export const debugError = debug('puppeteer:error'); export const debugError = debug('puppeteer:error');
@ -84,8 +84,8 @@ export async function releaseObject(
return; return;
} }
await client await client
.send('Runtime.releaseObject', { objectId: remoteObject.objectId }) .send('Runtime.releaseObject', {objectId: remoteObject.objectId})
.catch((error) => { .catch(error => {
// Exceptions might happen in case of a page been navigated or closed. // Exceptions might happen in case of a page been navigated or closed.
// Swallow these since they are harmless and we don't leak anything in this case. // Swallow these since they are harmless and we don't leak anything in this case.
debugError(error); debugError(error);
@ -104,7 +104,7 @@ export function addEventListener(
handler: (...args: any[]) => void handler: (...args: any[]) => void
): PuppeteerEventListener { ): PuppeteerEventListener {
emitter.on(eventName, handler); emitter.on(eventName, handler);
return { emitter, eventName, handler }; return {emitter, eventName, handler};
} }
export function removeEventListeners( export function removeEventListeners(
@ -142,7 +142,7 @@ export async function waitForEvent<T>(
resolveCallback = resolve; resolveCallback = resolve;
rejectCallback = reject; rejectCallback = reject;
}); });
const listener = addEventListener(emitter, eventName, async (event) => { const listener = addEventListener(emitter, eventName, async event => {
if (!(await predicate(event))) { if (!(await predicate(event))) {
return; return;
} }
@ -160,11 +160,11 @@ export async function waitForEvent<T>(
clearTimeout(eventTimeout); clearTimeout(eventTimeout);
} }
const result = await Promise.race([promise, abortPromise]).then( const result = await Promise.race([promise, abortPromise]).then(
(r) => { r => {
cleanup(); cleanup();
return r; return r;
}, },
(error) => { error => {
cleanup(); cleanup();
throw error; throw error;
} }
@ -213,9 +213,9 @@ export function pageBindingInitString(type: string, name: string): string {
const seq = (me.lastSeq || 0) + 1; const seq = (me.lastSeq || 0) + 1;
me.lastSeq = seq; me.lastSeq = seq;
const promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
return callbacks.set(seq, { resolve, reject }); return callbacks.set(seq, {resolve, reject});
}); });
binding(JSON.stringify({ type, name: bindingName, seq, args })); binding(JSON.stringify({type, name: bindingName, seq, args}));
return promise; return promise;
}; };
} }
@ -381,7 +381,7 @@ export async function getReadableFromProtocolStream(
throw new Error('Cannot create a stream outside of Node.js environment.'); throw new Error('Cannot create a stream outside of Node.js environment.');
} }
const { Readable } = await import('stream'); const {Readable} = await import('stream');
let eof = false; let eof = false;
return new Readable({ return new Readable({
@ -390,11 +390,11 @@ export async function getReadableFromProtocolStream(
return; return;
} }
const response = await client.send('IO.read', { handle, size }); const response = await client.send('IO.read', {handle, size});
this.push(response.data, response.base64Encoded ? 'base64' : undefined); this.push(response.data, response.base64Encoded ? 'base64' : undefined);
if (response.eof) { if (response.eof) {
eof = true; eof = true;
await client.send('IO.close', { handle }); await client.send('IO.close', {handle});
this.push(null); this.push(null);
} }
}, },

2
src/compat.d.ts vendored
View File

@ -1,3 +1,3 @@
declare const puppeteerDirname: string; declare const puppeteerDirname: string;
export { puppeteerDirname }; export {puppeteerDirname};

View File

@ -1,4 +1,4 @@
import { dirname } from 'path'; import {dirname} from 'path';
import { puppeteerDirname } from './compat.js'; import {puppeteerDirname} from './compat.js';
export const rootDirname = dirname(dirname(dirname(puppeteerDirname))); export const rootDirname = dirname(dirname(dirname(puppeteerDirname)));

View File

@ -14,11 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { sync } from 'pkg-dir'; import {sync} from 'pkg-dir';
import { Product } from './common/Product.js'; import {Product} from './common/Product.js';
import { rootDirname } from './constants.js'; import {rootDirname} from './constants.js';
import { PuppeteerNode } from './node/Puppeteer.js'; import {PuppeteerNode} from './node/Puppeteer.js';
import { PUPPETEER_REVISIONS } from './revisions.js'; import {PUPPETEER_REVISIONS} from './revisions.js';
export const initializePuppeteer = (packageName: string): PuppeteerNode => { export const initializePuppeteer = (packageName: string): PuppeteerNode => {
const isPuppeteerCore = packageName === 'puppeteer-core'; const isPuppeteerCore = packageName === 'puppeteer-core';

View File

@ -22,23 +22,23 @@ import * as childProcess from 'child_process';
import * as https from 'https'; import * as https from 'https';
import * as http from 'http'; import * as http from 'http';
import { Product } from '../common/Product.js'; import {Product} from '../common/Product.js';
import extractZip from 'extract-zip'; import extractZip from 'extract-zip';
import { debug } from '../common/Debug.js'; import {debug} from '../common/Debug.js';
import { promisify } from 'util'; import {promisify} from 'util';
import removeRecursive from 'rimraf'; import removeRecursive from 'rimraf';
import * as URL from 'url'; import * as URL from 'url';
import createHttpsProxyAgent, { import createHttpsProxyAgent, {
HttpsProxyAgent, HttpsProxyAgent,
HttpsProxyAgentOptions, HttpsProxyAgentOptions,
} from 'https-proxy-agent'; } from 'https-proxy-agent';
import { getProxyForUrl } from 'proxy-from-env'; import {getProxyForUrl} from 'proxy-from-env';
import { assert } from '../common/assert.js'; import {assert} from '../common/assert.js';
import tar from 'tar-fs'; import tar from 'tar-fs';
import bzip from 'unbzip2-stream'; import bzip from 'unbzip2-stream';
const { PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM } = process.env; const {PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM} = process.env;
const debugFetcher = debug('puppeteer:fetcher'); const debugFetcher = debug('puppeteer:fetcher');
@ -142,8 +142,8 @@ const unlinkAsync = promisify(fs.unlink.bind(fs));
const chmodAsync = promisify(fs.chmod.bind(fs)); const chmodAsync = promisify(fs.chmod.bind(fs));
function existsAsync(filePath: string): Promise<boolean> { function existsAsync(filePath: string): Promise<boolean> {
return new Promise((resolve) => { return new Promise(resolve => {
fs.access(filePath, (err) => { fs.access(filePath, err => {
return resolve(!err); return resolve(!err);
}); });
}); });
@ -288,16 +288,16 @@ export class BrowserFetcher {
this.#downloadHost, this.#downloadHost,
revision revision
); );
return new Promise((resolve) => { return new Promise(resolve => {
const request = httpRequest( const request = httpRequest(
url, url,
'HEAD', 'HEAD',
(response) => { response => {
resolve(response.statusCode === 200); resolve(response.statusCode === 200);
}, },
false false
); );
request.on('error', (error) => { request.on('error', error => {
console.error(error); console.error(error);
resolve(false); resolve(false);
}); });
@ -367,17 +367,17 @@ export class BrowserFetcher {
} }
const fileNames = await readdirAsync(this.#downloadsFolder); const fileNames = await readdirAsync(this.#downloadsFolder);
return fileNames return fileNames
.map((fileName) => { .map(fileName => {
return parseFolderPath(this.#product, fileName); return parseFolderPath(this.#product, fileName);
}) })
.filter( .filter(
( (
entry entry
): entry is { product: string; platform: string; revision: string } => { ): entry is {product: string; platform: string; revision: string} => {
return (entry && entry.platform === this.#platform) ?? false; return (entry && entry.platform === this.#platform) ?? false;
} }
) )
.map((entry) => { .map(entry => {
return entry.revision; return entry.revision;
}); });
} }
@ -395,7 +395,7 @@ export class BrowserFetcher {
await existsAsync(folderPath), await existsAsync(folderPath),
`Failed to remove: revision ${revision} is not downloaded` `Failed to remove: revision ${revision} is not downloaded`
); );
await new Promise((fulfill) => { await new Promise(fulfill => {
return removeRecursive(folderPath, fulfill); return removeRecursive(folderPath, fulfill);
}); });
} }
@ -484,7 +484,7 @@ export class BrowserFetcher {
function parseFolderPath( function parseFolderPath(
product: Product, product: Product,
folderPath: string folderPath: string
): { product: string; platform: string; revision: string } | undefined { ): {product: string; platform: string; revision: string} | undefined {
const name = path.basename(folderPath); const name = path.basename(folderPath);
const splits = name.split('-'); const splits = name.split('-');
if (splits.length !== 2) { if (splits.length !== 2) {
@ -494,7 +494,7 @@ function parseFolderPath(
if (!revision || !platform || !(platform in downloadURLs[product])) { if (!revision || !platform || !(platform in downloadURLs[product])) {
return; return;
} }
return { product, platform, revision }; return {product, platform, revision};
} }
/** /**
@ -516,7 +516,7 @@ function _downloadFile(
let downloadedBytes = 0; let downloadedBytes = 0;
let totalBytes = 0; let totalBytes = 0;
const request = httpRequest(url, 'GET', (response) => { const request = httpRequest(url, 'GET', response => {
if (response.statusCode !== 200) { if (response.statusCode !== 200) {
const error = new Error( const error = new Error(
`Download failed: server returned code ${response.statusCode}. URL: ${url}` `Download failed: server returned code ${response.statusCode}. URL: ${url}`
@ -530,7 +530,7 @@ function _downloadFile(
file.on('finish', () => { file.on('finish', () => {
return fulfill(); return fulfill();
}); });
file.on('error', (error) => { file.on('error', error => {
return reject(error); return reject(error);
}); });
response.pipe(file); response.pipe(file);
@ -539,7 +539,7 @@ function _downloadFile(
response.on('data', onData); response.on('data', onData);
} }
}); });
request.on('error', (error) => { request.on('error', error => {
return reject(error); return reject(error);
}); });
return promise; return promise;
@ -553,7 +553,7 @@ function _downloadFile(
function install(archivePath: string, folderPath: string): Promise<unknown> { function install(archivePath: string, folderPath: string): Promise<unknown> {
debugFetcher(`Installing ${archivePath} to ${folderPath}`); debugFetcher(`Installing ${archivePath} to ${folderPath}`);
if (archivePath.endsWith('.zip')) { if (archivePath.endsWith('.zip')) {
return extractZip(archivePath, { dir: folderPath }); return extractZip(archivePath, {dir: folderPath});
} else if (archivePath.endsWith('.tar.bz2')) { } else if (archivePath.endsWith('.tar.bz2')) {
return _extractTar(archivePath, folderPath); return _extractTar(archivePath, folderPath);
} else if (archivePath.endsWith('.dmg')) { } else if (archivePath.endsWith('.dmg')) {
@ -596,8 +596,8 @@ function _installDMG(dmgPath: string, folderPath: string): Promise<void> {
} }
mountPath = volumes[0]!; mountPath = volumes[0]!;
readdirAsync(mountPath) readdirAsync(mountPath)
.then((fileNames) => { .then(fileNames => {
const appName = fileNames.find((item) => { const appName = fileNames.find(item => {
return typeof item === 'string' && item.endsWith('.app'); return typeof item === 'string' && item.endsWith('.app');
}); });
if (!appName) { if (!appName) {
@ -605,7 +605,7 @@ function _installDMG(dmgPath: string, folderPath: string): Promise<void> {
} }
const copyPath = path.join(mountPath!, appName); const copyPath = path.join(mountPath!, appName);
debugFetcher(`Copying ${copyPath} to ${folderPath}`); debugFetcher(`Copying ${copyPath} to ${folderPath}`);
childProcess.exec(`cp -R "${copyPath}" "${folderPath}"`, (err) => { childProcess.exec(`cp -R "${copyPath}" "${folderPath}"`, err => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
@ -616,7 +616,7 @@ function _installDMG(dmgPath: string, folderPath: string): Promise<void> {
.catch(reject); .catch(reject);
}); });
}) })
.catch((error) => { .catch(error => {
console.error(error); console.error(error);
}) })
.finally((): void => { .finally((): void => {
@ -625,7 +625,7 @@ function _installDMG(dmgPath: string, folderPath: string): Promise<void> {
} }
const unmountCommand = `hdiutil detach "${mountPath}" -quiet`; const unmountCommand = `hdiutil detach "${mountPath}" -quiet`;
debugFetcher(`Unmounting ${mountPath}`); debugFetcher(`Unmounting ${mountPath}`);
childProcess.exec(unmountCommand, (err) => { childProcess.exec(unmountCommand, err => {
if (err) { if (err) {
console.error(`Error unmounting dmg: ${err}`); console.error(`Error unmounting dmg: ${err}`);
} }

View File

@ -19,11 +19,11 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as readline from 'readline'; import * as readline from 'readline';
import removeFolder from 'rimraf'; import removeFolder from 'rimraf';
import { promisify } from 'util'; import {promisify} from 'util';
import { assert } from '../common/assert.js'; import {assert} from '../common/assert.js';
import { Connection } from '../common/Connection.js'; import {Connection} from '../common/Connection.js';
import { debug } from '../common/Debug.js'; import {debug} from '../common/Debug.js';
import { TimeoutError } from '../common/Errors.js'; import {TimeoutError} from '../common/Errors.js';
import { import {
debugError, debugError,
addEventListener, addEventListener,
@ -32,10 +32,10 @@ import {
PuppeteerEventListener, PuppeteerEventListener,
removeEventListeners, removeEventListeners,
} from '../common/util.js'; } from '../common/util.js';
import { Product } from '../common/Product.js'; import {Product} from '../common/Product.js';
import { NodeWebSocketTransport as WebSocketTransport } from '../node/NodeWebSocketTransport.js'; import {NodeWebSocketTransport as WebSocketTransport} from '../node/NodeWebSocketTransport.js';
import { LaunchOptions } from './LaunchOptions.js'; import {LaunchOptions} from './LaunchOptions.js';
import { PipeTransport } from './PipeTransport.js'; import {PipeTransport} from './PipeTransport.js';
const removeFolderAsync = promisify(removeFolder); const removeFolderAsync = promisify(removeFolder);
const renameAsync = promisify(fs.rename); const renameAsync = promisify(fs.rename);
@ -76,7 +76,7 @@ export class BrowserRunner {
} }
start(options: LaunchOptions): void { start(options: LaunchOptions): void {
const { handleSIGINT, handleSIGTERM, handleSIGHUP, dumpio, env, pipe } = const {handleSIGINT, handleSIGTERM, handleSIGHUP, dumpio, env, pipe} =
options; options;
let stdio: Array<'ignore' | 'pipe'>; let stdio: Array<'ignore' | 'pipe'>;
if (pipe) { if (pipe) {
@ -181,7 +181,7 @@ export class BrowserRunner {
this.kill(); this.kill();
} else if (this.connection) { } else if (this.connection) {
// Attempt to close the browser gracefully // Attempt to close the browser gracefully
this.connection.send('Browser.close').catch((error) => { this.connection.send('Browser.close').catch(error => {
debugError(error); debugError(error);
this.kill(); this.kill();
}); });
@ -200,7 +200,7 @@ export class BrowserRunner {
const proc = this.proc; const proc = this.proc;
try { try {
if (process.platform === 'win32') { if (process.platform === 'win32') {
childProcess.exec(`taskkill /pid ${this.proc.pid} /T /F`, (error) => { childProcess.exec(`taskkill /pid ${this.proc.pid} /T /F`, error => {
if (error) { if (error) {
// taskkill can fail to kill the process e.g. due to missing permissions. // taskkill can fail to kill the process e.g. due to missing permissions.
// Let's kill the process via Node API. This delays killing of all child // Let's kill the process via Node API. This delays killing of all child
@ -251,7 +251,7 @@ export class BrowserRunner {
}): Promise<Connection> { }): Promise<Connection> {
assert(this.proc, 'BrowserRunner not started.'); assert(this.proc, 'BrowserRunner not started.');
const { usePipe, timeout, slowMo, preferredRevision } = options; const {usePipe, timeout, slowMo, preferredRevision} = options;
if (!usePipe) { if (!usePipe) {
const browserWSEndpoint = await waitForWSEndpoint( const browserWSEndpoint = await waitForWSEndpoint(
this.proc, this.proc,
@ -263,7 +263,7 @@ export class BrowserRunner {
} else { } else {
// stdio was assigned during start(), and the 'pipe' option there adds the // stdio was assigned during start(), and the 'pipe' option there adds the
// 4th and 5th items to stdio array // 4th and 5th items to stdio array
const { 3: pipeWrite, 4: pipeRead } = this.proc.stdio; const {3: pipeWrite, 4: pipeRead} = this.proc.stdio;
const transport = new PipeTransport( const transport = new PipeTransport(
pipeWrite as NodeJS.WritableStream, pipeWrite as NodeJS.WritableStream,
pipeRead as NodeJS.ReadableStream pipeRead as NodeJS.ReadableStream
@ -292,7 +292,7 @@ function waitForWSEndpoint(
addEventListener(browserProcess, 'exit', () => { addEventListener(browserProcess, 'exit', () => {
return onClose(); return onClose();
}), }),
addEventListener(browserProcess, 'error', (error) => { addEventListener(browserProcess, 'error', error => {
return onClose(error); return onClose(error);
}), }),
]; ];

View File

@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { BrowserConnectOptions } from '../common/BrowserConnector.js'; import {BrowserConnectOptions} from '../common/BrowserConnector.js';
import { Product } from '../common/Product.js'; import {Product} from '../common/Product.js';
/** /**
* Launcher options that only apply to Chrome. * Launcher options that only apply to Chrome.

View File

@ -17,11 +17,11 @@ import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
import { assert } from '../common/assert.js'; import {assert} from '../common/assert.js';
import { BrowserFetcher } from './BrowserFetcher.js'; import {BrowserFetcher} from './BrowserFetcher.js';
import { Browser } from '../common/Browser.js'; import {Browser} from '../common/Browser.js';
import { BrowserRunner } from './BrowserRunner.js'; import {BrowserRunner} from './BrowserRunner.js';
import { promisify } from 'util'; import {promisify} from 'util';
const copyFileAsync = promisify(fs.copyFile); const copyFileAsync = promisify(fs.copyFile);
const mkdtempAsync = promisify(fs.mkdtemp); const mkdtempAsync = promisify(fs.mkdtemp);
@ -33,7 +33,7 @@ import {
PuppeteerNodeLaunchOptions, PuppeteerNodeLaunchOptions,
} from './LaunchOptions.js'; } from './LaunchOptions.js';
import { Product } from '../common/Product.js'; import {Product} from '../common/Product.js';
const tmpDir = () => { const tmpDir = () => {
return process.env['PUPPETEER_TMP_DIR'] || os.tmpdir(); return process.env['PUPPETEER_TMP_DIR'] || os.tmpdir();
@ -90,7 +90,7 @@ class ChromeLauncher implements ProductLauncher {
handleSIGTERM = true, handleSIGTERM = true,
handleSIGHUP = true, handleSIGHUP = true,
ignoreHTTPSErrors = false, ignoreHTTPSErrors = false,
defaultViewport = { width: 800, height: 600 }, defaultViewport = {width: 800, height: 600},
slowMo = 0, slowMo = 0,
timeout = 30000, timeout = 30000,
waitForInitialPage = true, waitForInitialPage = true,
@ -102,7 +102,7 @@ class ChromeLauncher implements ProductLauncher {
chromeArguments.push(...this.defaultArgs(options)); chromeArguments.push(...this.defaultArgs(options));
} else if (Array.isArray(ignoreDefaultArgs)) { } else if (Array.isArray(ignoreDefaultArgs)) {
chromeArguments.push( chromeArguments.push(
...this.defaultArgs(options).filter((arg) => { ...this.defaultArgs(options).filter(arg => {
return !ignoreDefaultArgs.includes(arg); return !ignoreDefaultArgs.includes(arg);
}) })
); );
@ -111,7 +111,7 @@ class ChromeLauncher implements ProductLauncher {
} }
if ( if (
!chromeArguments.some((argument) => { !chromeArguments.some(argument => {
return argument.startsWith('--remote-debugging-'); return argument.startsWith('--remote-debugging-');
}) })
) { ) {
@ -130,7 +130,7 @@ class ChromeLauncher implements ProductLauncher {
// Check for the user data dir argument, which will always be set even // Check for the user data dir argument, which will always be set even
// with a custom directory specified via the userDataDir option. // with a custom directory specified via the userDataDir option.
let userDataDirIndex = chromeArguments.findIndex((arg) => { let userDataDirIndex = chromeArguments.findIndex(arg => {
return arg.startsWith('--user-data-dir'); return arg.startsWith('--user-data-dir');
}); });
if (userDataDirIndex < 0) { if (userDataDirIndex < 0) {
@ -157,7 +157,7 @@ class ChromeLauncher implements ProductLauncher {
chromeExecutable = executablePathForChannel(channel); chromeExecutable = executablePathForChannel(channel);
} else if (!chromeExecutable) { } else if (!chromeExecutable) {
const { missingText, executablePath } = resolveExecutablePath(this); const {missingText, executablePath} = resolveExecutablePath(this);
if (missingText) { if (missingText) {
throw new Error(missingText); throw new Error(missingText);
} }
@ -205,10 +205,10 @@ class ChromeLauncher implements ProductLauncher {
if (waitForInitialPage) { if (waitForInitialPage) {
try { try {
await browser.waitForTarget( await browser.waitForTarget(
(t) => { t => {
return t.type() === 'page'; return t.type() === 'page';
}, },
{ timeout } {timeout}
); );
} catch (error) { } catch (error) {
await browser.close(); await browser.close();
@ -272,7 +272,7 @@ class ChromeLauncher implements ProductLauncher {
); );
} }
if ( if (
args.every((arg) => { args.every(arg => {
return arg.startsWith('-'); return arg.startsWith('-');
}) })
) { ) {
@ -335,7 +335,7 @@ class FirefoxLauncher implements ProductLauncher {
handleSIGTERM = true, handleSIGTERM = true,
handleSIGHUP = true, handleSIGHUP = true,
ignoreHTTPSErrors = false, ignoreHTTPSErrors = false,
defaultViewport = { width: 800, height: 600 }, defaultViewport = {width: 800, height: 600},
slowMo = 0, slowMo = 0,
timeout = 30000, timeout = 30000,
extraPrefsFirefox = {}, extraPrefsFirefox = {},
@ -348,7 +348,7 @@ class FirefoxLauncher implements ProductLauncher {
firefoxArguments.push(...this.defaultArgs(options)); firefoxArguments.push(...this.defaultArgs(options));
} else if (Array.isArray(ignoreDefaultArgs)) { } else if (Array.isArray(ignoreDefaultArgs)) {
firefoxArguments.push( firefoxArguments.push(
...this.defaultArgs(options).filter((arg) => { ...this.defaultArgs(options).filter(arg => {
return !ignoreDefaultArgs.includes(arg); return !ignoreDefaultArgs.includes(arg);
}) })
); );
@ -357,7 +357,7 @@ class FirefoxLauncher implements ProductLauncher {
} }
if ( if (
!firefoxArguments.some((argument) => { !firefoxArguments.some(argument => {
return argument.startsWith('--remote-debugging-'); return argument.startsWith('--remote-debugging-');
}) })
) { ) {
@ -375,7 +375,7 @@ class FirefoxLauncher implements ProductLauncher {
// Check for the profile argument, which will always be set even // Check for the profile argument, which will always be set even
// with a custom directory specified via the userDataDir option. // with a custom directory specified via the userDataDir option.
const profileArgIndex = firefoxArguments.findIndex((arg) => { const profileArgIndex = firefoxArguments.findIndex(arg => {
return ['-profile', '--profile'].includes(arg); return ['-profile', '--profile'].includes(arg);
}); });
@ -399,7 +399,7 @@ class FirefoxLauncher implements ProductLauncher {
await this._updateRevision(); await this._updateRevision();
let firefoxExecutable = executablePath; let firefoxExecutable = executablePath;
if (!executablePath) { if (!executablePath) {
const { missingText, executablePath } = resolveExecutablePath(this); const {missingText, executablePath} = resolveExecutablePath(this);
if (missingText) { if (missingText) {
throw new Error(missingText); throw new Error(missingText);
} }
@ -450,10 +450,10 @@ class FirefoxLauncher implements ProductLauncher {
if (waitForInitialPage) { if (waitForInitialPage) {
try { try {
await browser.waitForTarget( await browser.waitForTarget(
(t) => { t => {
return t.type() === 'page'; return t.type() === 'page';
}, },
{ timeout } {timeout}
); );
} catch (error) { } catch (error) {
await browser.close(); await browser.close();
@ -516,7 +516,7 @@ class FirefoxLauncher implements ProductLauncher {
firefoxArguments.push('--devtools'); firefoxArguments.push('--devtools');
} }
if ( if (
args.every((arg) => { args.every(arg => {
return arg.startsWith('-'); return arg.startsWith('-');
}) })
) { ) {
@ -526,7 +526,7 @@ class FirefoxLauncher implements ProductLauncher {
return firefoxArguments; return firefoxArguments;
} }
defaultPreferences(extraPrefs: { [x: string]: unknown }): { defaultPreferences(extraPrefs: {[x: string]: unknown}): {
[x: string]: unknown; [x: string]: unknown;
} { } {
const server = 'dummy.test'; const server = 'dummy.test';
@ -747,7 +747,7 @@ class FirefoxLauncher implements ProductLauncher {
* @param profilePath - Firefox profile to write the preferences to. * @param profilePath - Firefox profile to write the preferences to.
*/ */
async writePreferences( async writePreferences(
prefs: { [x: string]: unknown }, prefs: {[x: string]: unknown},
profilePath: string profilePath: string
): Promise<void> { ): Promise<void> {
const lines = Object.entries(prefs).map(([key, value]) => { const lines = Object.entries(prefs).map(([key, value]) => {
@ -764,7 +764,7 @@ class FirefoxLauncher implements ProductLauncher {
} }
} }
async _createProfile(extraPrefs: { [x: string]: unknown }): Promise<string> { async _createProfile(extraPrefs: {[x: string]: unknown}): Promise<string> {
const temporaryProfilePath = await mkdtempAsync( const temporaryProfilePath = await mkdtempAsync(
path.join(tmpDir(), 'puppeteer_dev_firefox_profile-') path.join(tmpDir(), 'puppeteer_dev_firefox_profile-')
); );
@ -854,7 +854,7 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
executablePath: string; executablePath: string;
missingText?: string; missingText?: string;
} { } {
const { product, _isPuppeteerCore, _projectRoot, _preferredRevision } = const {product, _isPuppeteerCore, _projectRoot, _preferredRevision} =
launcher; launcher;
let downloadPath: string | undefined; let downloadPath: string | undefined;
// puppeteer-core doesn't take into account PUPPETEER_* env variables. // puppeteer-core doesn't take into account PUPPETEER_* env variables.
@ -868,7 +868,7 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' + ? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' +
executablePath executablePath
: undefined; : undefined;
return { executablePath, missingText }; return {executablePath, missingText};
} }
const ubuntuChromiumPath = '/usr/bin/chromium-browser'; const ubuntuChromiumPath = '/usr/bin/chromium-browser';
if ( if (
@ -877,7 +877,7 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
os.arch() === 'arm64' && os.arch() === 'arm64' &&
fs.existsSync(ubuntuChromiumPath) fs.existsSync(ubuntuChromiumPath)
) { ) {
return { executablePath: ubuntuChromiumPath, missingText: undefined }; return {executablePath: ubuntuChromiumPath, missingText: undefined};
} }
downloadPath = downloadPath =
process.env['PUPPETEER_DOWNLOAD_PATH'] || process.env['PUPPETEER_DOWNLOAD_PATH'] ||
@ -902,7 +902,7 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
? 'Tried to use PUPPETEER_CHROMIUM_REVISION env variable to launch browser but did not find executable at: ' + ? 'Tried to use PUPPETEER_CHROMIUM_REVISION env variable to launch browser but did not find executable at: ' +
revisionInfo.executablePath revisionInfo.executablePath
: undefined; : undefined;
return { executablePath: revisionInfo.executablePath, missingText }; return {executablePath: revisionInfo.executablePath, missingText};
} }
} }
const revisionInfo = browserFetcher.revisionInfo(_preferredRevision); const revisionInfo = browserFetcher.revisionInfo(_preferredRevision);
@ -914,7 +914,7 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
product === 'chrome' ? chromeHelp : firefoxHelp product === 'chrome' ? chromeHelp : firefoxHelp
}` }`
: undefined; : undefined;
return { executablePath: revisionInfo.executablePath, missingText }; return {executablePath: revisionInfo.executablePath, missingText};
} }
/** /**

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
import NodeWebSocket from 'ws'; import NodeWebSocket from 'ws';
import { ConnectionTransport } from '../common/ConnectionTransport.js'; import {ConnectionTransport} from '../common/ConnectionTransport.js';
import { packageVersion } from '../generated/version.js'; import {packageVersion} from '../generated/version.js';
import { promises as dns } from 'dns'; import {promises as dns} from 'dns';
export class NodeWebSocketTransport implements ConnectionTransport { export class NodeWebSocketTransport implements ConnectionTransport {
static async create(urlString: string): Promise<NodeWebSocketTransport> { static async create(urlString: string): Promise<NodeWebSocketTransport> {
@ -29,7 +29,7 @@ export class NodeWebSocketTransport implements ConnectionTransport {
// because of https://bugzilla.mozilla.org/show_bug.cgi?id=1769994. // because of https://bugzilla.mozilla.org/show_bug.cgi?id=1769994.
const url = new URL(urlString); const url = new URL(urlString);
if (url.hostname === 'localhost') { if (url.hostname === 'localhost') {
const { address } = await dns.lookup(url.hostname, { verbatim: false }); const {address} = await dns.lookup(url.hostname, {verbatim: false});
url.hostname = address; url.hostname = address;
} }
@ -56,7 +56,7 @@ export class NodeWebSocketTransport implements ConnectionTransport {
constructor(ws: NodeWebSocket) { constructor(ws: NodeWebSocket) {
this.#ws = ws; this.#ws = ws;
this.#ws.addEventListener('message', (event) => { this.#ws.addEventListener('message', event => {
if (this.onmessage) { if (this.onmessage) {
this.onmessage.call(null, event.data); this.onmessage.call(null, event.data);
} }

View File

@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { assert } from '../common/assert.js'; import {assert} from '../common/assert.js';
import { ConnectionTransport } from '../common/ConnectionTransport.js'; import {ConnectionTransport} from '../common/ConnectionTransport.js';
import { import {
addEventListener, addEventListener,
debugError, debugError,
@ -38,7 +38,7 @@ export class PipeTransport implements ConnectionTransport {
) { ) {
this.#pipeWrite = pipeWrite; this.#pipeWrite = pipeWrite;
this.#eventListeners = [ this.#eventListeners = [
addEventListener(pipeRead, 'data', (buffer) => { addEventListener(pipeRead, 'data', buffer => {
return this.#dispatch(buffer); return this.#dispatch(buffer);
}), }),
addEventListener(pipeRead, 'close', () => { addEventListener(pipeRead, 'close', () => {

View File

@ -19,16 +19,13 @@ import {
CommonPuppeteerSettings, CommonPuppeteerSettings,
ConnectOptions, ConnectOptions,
} from '../common/Puppeteer.js'; } from '../common/Puppeteer.js';
import { BrowserFetcher, BrowserFetcherOptions } from './BrowserFetcher.js'; import {BrowserFetcher, BrowserFetcherOptions} from './BrowserFetcher.js';
import { import {LaunchOptions, BrowserLaunchArgumentOptions} from './LaunchOptions.js';
LaunchOptions, import {BrowserConnectOptions} from '../common/BrowserConnector.js';
BrowserLaunchArgumentOptions, import {Browser} from '../common/Browser.js';
} from './LaunchOptions.js'; import Launcher, {ProductLauncher} from './Launcher.js';
import { BrowserConnectOptions } from '../common/BrowserConnector.js'; import {PUPPETEER_REVISIONS} from '../revisions.js';
import { Browser } from '../common/Browser.js'; import {Product} from '../common/Product.js';
import Launcher, { ProductLauncher } from './Launcher.js';
import { PUPPETEER_REVISIONS } from '../revisions.js';
import { Product } from '../common/Product.js';
/** /**
* @public * @public
@ -93,7 +90,7 @@ export class PuppeteerNode extends Puppeteer {
productName?: Product; productName?: Product;
} & CommonPuppeteerSettings } & CommonPuppeteerSettings
) { ) {
const { projectRoot, preferredRevision, productName, ...commonSettings } = const {projectRoot, preferredRevision, productName, ...commonSettings} =
settings; settings;
super(commonSettings); super(commonSettings);
this.#projectRoot = projectRoot; this.#projectRoot = projectRoot;

View File

@ -14,16 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
import https, { RequestOptions } from 'https'; import https, {RequestOptions} from 'https';
import ProgressBar from 'progress'; import ProgressBar from 'progress';
import URL from 'url'; import URL from 'url';
import puppeteer from '../puppeteer.js'; import puppeteer from '../puppeteer.js';
import { PUPPETEER_REVISIONS } from '../revisions.js'; import {PUPPETEER_REVISIONS} from '../revisions.js';
import { PuppeteerNode } from './Puppeteer.js'; import {PuppeteerNode} from './Puppeteer.js';
import createHttpsProxyAgent, { import createHttpsProxyAgent, {HttpsProxyAgentOptions} from 'https-proxy-agent';
HttpsProxyAgentOptions, import {getProxyForUrl} from 'proxy-from-env';
} from 'https-proxy-agent';
import { getProxyForUrl } from 'proxy-from-env';
const supportedProducts = { const supportedProducts = {
chrome: 'Chromium', chrome: 'Chromium',
@ -70,7 +68,7 @@ export async function downloadBrowser(): Promise<void> {
} else if (product === 'firefox') { } else if (product === 'firefox') {
(puppeteer as PuppeteerNode)._preferredRevision = (puppeteer as PuppeteerNode)._preferredRevision =
PUPPETEER_REVISIONS.firefox; PUPPETEER_REVISIONS.firefox;
return getFirefoxNightlyVersion().catch((error) => { return getFirefoxNightlyVersion().catch(error => {
console.error(error); console.error(error);
process.exit(1); process.exit(1);
}); });
@ -111,10 +109,10 @@ export async function downloadBrowser(): Promise<void> {
logPolitely( logPolitely(
`${supportedProducts[product]} (${revisionInfo.revision}) downloaded to ${revisionInfo.folderPath}` `${supportedProducts[product]} (${revisionInfo.revision}) downloaded to ${revisionInfo.folderPath}`
); );
localRevisions = localRevisions.filter((revision) => { localRevisions = localRevisions.filter(revision => {
return revision !== revisionInfo.revision; return revision !== revisionInfo.revision;
}); });
const cleanupOldVersions = localRevisions.map((revision) => { const cleanupOldVersions = localRevisions.map(revision => {
return browserFetcher.remove(revision); return browserFetcher.remove(revision);
}); });
Promise.all([...cleanupOldVersions]); Promise.all([...cleanupOldVersions]);
@ -189,11 +187,11 @@ export async function downloadBrowser(): Promise<void> {
`Requesting latest Firefox Nightly version from ${firefoxVersionsUrl}` `Requesting latest Firefox Nightly version from ${firefoxVersionsUrl}`
); );
https https
.get(firefoxVersionsUrl, requestOptions, (r) => { .get(firefoxVersionsUrl, requestOptions, r => {
if (r.statusCode && r.statusCode >= 400) { if (r.statusCode && r.statusCode >= 400) {
return reject(new Error(`Got status code ${r.statusCode}`)); return reject(new Error(`Got status code ${r.statusCode}`));
} }
r.on('data', (chunk) => { r.on('data', chunk => {
data += chunk; data += chunk;
}); });
r.on('end', () => { r.on('end', () => {

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { initializePuppeteer } from './initializePuppeteer.js'; import {initializePuppeteer} from './initializePuppeteer.js';
const puppeteer = initializePuppeteer('puppeteer-core'); const puppeteer = initializePuppeteer('puppeteer-core');

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { initializePuppeteer } from './initializePuppeteer.js'; import {initializePuppeteer} from './initializePuppeteer.js';
const puppeteer = initializePuppeteer('puppeteer'); const puppeteer = initializePuppeteer('puppeteer');

View File

@ -6,7 +6,7 @@
"module": "CommonJS" "module": "CommonJS"
}, },
"references": [ "references": [
{ "path": "../vendor/tsconfig.cjs.json" }, {"path": "../vendor/tsconfig.cjs.json"},
{ "path": "../compat/cjs/tsconfig.json" } {"path": "../compat/cjs/tsconfig.json"}
] ]
} }

View File

@ -6,7 +6,7 @@
"module": "esnext" "module": "esnext"
}, },
"references": [ "references": [
{ "path": "../vendor/tsconfig.esm.json" }, {"path": "../vendor/tsconfig.esm.json"},
{ "path": "../compat/esm/tsconfig.json" } {"path": "../compat/esm/tsconfig.json"}
] ]
} }

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { waitEvent } from './utils.js'; import {waitEvent} from './utils.js';
import expect from 'expect'; import expect from 'expect';
import { import {
getTestState, getTestState,
@ -22,20 +22,20 @@ import {
setupTestPageAndContextHooks, setupTestPageAndContextHooks,
describeChromeOnly, describeChromeOnly,
} from './mocha-utils.js'; } from './mocha-utils.js';
import { isErrorLike } from '../../lib/cjs/puppeteer/common/util.js'; import {isErrorLike} from '../../lib/cjs/puppeteer/common/util.js';
describeChromeOnly('Target.createCDPSession', function () { describeChromeOnly('Target.createCDPSession', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const client = await page.target().createCDPSession(); const client = await page.target().createCDPSession();
await Promise.all([ await Promise.all([
client.send('Runtime.enable'), client.send('Runtime.enable'),
client.send('Runtime.evaluate', { expression: 'window.foo = "bar"' }), client.send('Runtime.evaluate', {expression: 'window.foo = "bar"'}),
]); ]);
const foo = await page.evaluate(() => { const foo = await page.evaluate(() => {
return (globalThis as any).foo; return (globalThis as any).foo;
@ -43,19 +43,19 @@ describeChromeOnly('Target.createCDPSession', function () {
expect(foo).toBe('bar'); expect(foo).toBe('bar');
}); });
it('should send events', async () => { it('should send events', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const client = await page.target().createCDPSession(); const client = await page.target().createCDPSession();
await client.send('Network.enable'); await client.send('Network.enable');
const events = []; const events = [];
client.on('Network.requestWillBeSent', (event) => { client.on('Network.requestWillBeSent', event => {
return events.push(event); return events.push(event);
}); });
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
expect(events.length).toBe(1); expect(events.length).toBe(1);
}); });
it('should enable and disable domains independently', async () => { it('should enable and disable domains independently', async () => {
const { page } = getTestState(); const {page} = getTestState();
const client = await page.target().createCDPSession(); const client = await page.target().createCDPSession();
await client.send('Runtime.enable'); await client.send('Runtime.enable');
@ -72,7 +72,7 @@ describeChromeOnly('Target.createCDPSession', function () {
expect(event.url).toBe('foo.js'); expect(event.url).toBe('foo.js');
}); });
it('should be able to detach session', async () => { it('should be able to detach session', async () => {
const { page } = getTestState(); const {page} = getTestState();
const client = await page.target().createCDPSession(); const client = await page.target().createCDPSession();
await client.send('Runtime.enable'); await client.send('Runtime.enable');
@ -96,10 +96,10 @@ describeChromeOnly('Target.createCDPSession', function () {
expect(error.message).toContain('Session closed.'); expect(error.message).toContain('Session closed.');
}); });
it('should throw nice errors', async () => { it('should throw nice errors', async () => {
const { page } = getTestState(); const {page} = getTestState();
const client = await page.target().createCDPSession(); const client = await page.target().createCDPSession();
const error = await theSourceOfTheProblems().catch((error) => { const error = await theSourceOfTheProblems().catch(error => {
return error; return error;
}); });
expect(error.stack).toContain('theSourceOfTheProblems'); expect(error.stack).toContain('theSourceOfTheProblems');
@ -114,7 +114,7 @@ describeChromeOnly('Target.createCDPSession', function () {
}); });
it('should expose the underlying connection', async () => { it('should expose the underlying connection', async () => {
const { page } = getTestState(); const {page} = getTestState();
const client = await page.target().createCDPSession(); const client = await page.target().createCDPSession();
expect(client.connection()).toBeTruthy(); expect(client.connection()).toBeTruthy();

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { EventEmitter } from '../../lib/cjs/puppeteer/common/EventEmitter.js'; import {EventEmitter} from '../../lib/cjs/puppeteer/common/EventEmitter.js';
import sinon from 'sinon'; import sinon from 'sinon';
import expect from 'expect'; import expect from 'expect';

View File

@ -14,16 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
import { describeChromeOnly } from './mocha-utils.js'; import {describeChromeOnly} from './mocha-utils.js';
import expect from 'expect'; import expect from 'expect';
import { import {
NetworkManager, NetworkManager,
NetworkManagerEmittedEvents, NetworkManagerEmittedEvents,
} from '../../lib/cjs/puppeteer/common/NetworkManager.js'; } from '../../lib/cjs/puppeteer/common/NetworkManager.js';
import { HTTPRequest } from '../../lib/cjs/puppeteer/common/HTTPRequest.js'; import {HTTPRequest} from '../../lib/cjs/puppeteer/common/HTTPRequest.js';
import { EventEmitter } from '../../lib/cjs/puppeteer/common/EventEmitter.js'; import {EventEmitter} from '../../lib/cjs/puppeteer/common/EventEmitter.js';
import { Frame } from '../../lib/cjs/puppeteer/common/FrameManager.js'; import {Frame} from '../../lib/cjs/puppeteer/common/FrameManager.js';
class MockCDPSession extends EventEmitter { class MockCDPSession extends EventEmitter {
async send(): Promise<any> {} async send(): Promise<any> {}
@ -56,7 +56,7 @@ describeChromeOnly('NetworkManager', () => {
}, },
timestamp: 2111.55635, timestamp: 2111.55635,
wallTime: 1637315638.473634, wallTime: 1637315638.473634,
initiator: { type: 'other' }, initiator: {type: 'other'},
redirectHasExtraInfo: false, redirectHasExtraInfo: false,
type: 'Document', type: 'Document',
frameId: '099A5216AF03AAFEC988F214B024DF08', frameId: '099A5216AF03AAFEC988F214B024DF08',
@ -80,7 +80,7 @@ describeChromeOnly('NetworkManager', () => {
'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Dest': 'document',
'Accept-Encoding': 'gzip, deflate, br', 'Accept-Encoding': 'gzip, deflate, br',
}, },
connectTiming: { requestTime: 2111.557593 }, connectTiming: {requestTime: 2111.557593},
}); });
mockCDPSession.emit('Network.responseReceivedExtraInfo', { mockCDPSession.emit('Network.responseReceivedExtraInfo', {
requestId: '7760711DEFCFA23132D98ABA6B4E175C', requestId: '7760711DEFCFA23132D98ABA6B4E175C',
@ -116,7 +116,7 @@ describeChromeOnly('NetworkManager', () => {
}, },
timestamp: 2111.559124, timestamp: 2111.559124,
wallTime: 1637315638.47642, wallTime: 1637315638.47642,
initiator: { type: 'other' }, initiator: {type: 'other'},
redirectHasExtraInfo: true, redirectHasExtraInfo: true,
redirectResponse: { redirectResponse: {
url: 'http://localhost:8907/redirect/1.html', url: 'http://localhost:8907/redirect/1.html',
@ -183,7 +183,7 @@ describeChromeOnly('NetworkManager', () => {
'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Dest': 'document',
'Accept-Encoding': 'gzip, deflate, br', 'Accept-Encoding': 'gzip, deflate, br',
}, },
connectTiming: { requestTime: 2111.559346 }, connectTiming: {requestTime: 2111.559346},
}); });
mockCDPSession.emit('Network.requestWillBeSent', { mockCDPSession.emit('Network.requestWillBeSent', {
requestId: '7760711DEFCFA23132D98ABA6B4E175C', requestId: '7760711DEFCFA23132D98ABA6B4E175C',
@ -204,7 +204,7 @@ describeChromeOnly('NetworkManager', () => {
}, },
timestamp: 2111.560249, timestamp: 2111.560249,
wallTime: 1637315638.477543, wallTime: 1637315638.477543,
initiator: { type: 'other' }, initiator: {type: 'other'},
redirectHasExtraInfo: true, redirectHasExtraInfo: true,
redirectResponse: { redirectResponse: {
url: 'http://localhost:8907/redirect/2.html', url: 'http://localhost:8907/redirect/2.html',
@ -286,7 +286,7 @@ describeChromeOnly('NetworkManager', () => {
'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Dest': 'document',
'Accept-Encoding': 'gzip, deflate, br', 'Accept-Encoding': 'gzip, deflate, br',
}, },
connectTiming: { requestTime: 2111.560482 }, connectTiming: {requestTime: 2111.560482},
}); });
mockCDPSession.emit('Network.requestWillBeSent', { mockCDPSession.emit('Network.requestWillBeSent', {
requestId: '7760711DEFCFA23132D98ABA6B4E175C', requestId: '7760711DEFCFA23132D98ABA6B4E175C',
@ -307,7 +307,7 @@ describeChromeOnly('NetworkManager', () => {
}, },
timestamp: 2111.561542, timestamp: 2111.561542,
wallTime: 1637315638.478837, wallTime: 1637315638.478837,
initiator: { type: 'other' }, initiator: {type: 'other'},
redirectHasExtraInfo: true, redirectHasExtraInfo: true,
redirectResponse: { redirectResponse: {
url: 'http://localhost:8907/redirect/3.html', url: 'http://localhost:8907/redirect/3.html',
@ -389,7 +389,7 @@ describeChromeOnly('NetworkManager', () => {
'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Dest': 'document',
'Accept-Encoding': 'gzip, deflate, br', 'Accept-Encoding': 'gzip, deflate, br',
}, },
connectTiming: { requestTime: 2111.561759 }, connectTiming: {requestTime: 2111.561759},
}); });
mockCDPSession.emit('Network.responseReceivedExtraInfo', { mockCDPSession.emit('Network.responseReceivedExtraInfo', {
requestId: '7760711DEFCFA23132D98ABA6B4E175C', requestId: '7760711DEFCFA23132D98ABA6B4E175C',
@ -508,7 +508,7 @@ describeChromeOnly('NetworkManager', () => {
}, },
timestamp: 224604.980827, timestamp: 224604.980827,
wallTime: 1637955746.786191, wallTime: 1637955746.786191,
initiator: { type: 'other' }, initiator: {type: 'other'},
redirectHasExtraInfo: false, redirectHasExtraInfo: false,
type: 'Document', type: 'Document',
frameId: '84AC261A351B86932B775B76D1DD79F8', frameId: '84AC261A351B86932B775B76D1DD79F8',

View File

@ -16,7 +16,7 @@
import assert from 'assert'; import assert from 'assert';
import expect from 'expect'; import expect from 'expect';
import { SerializedAXNode } from '../../lib/cjs/puppeteer/common/Accessibility.js'; import {SerializedAXNode} from '../../lib/cjs/puppeteer/common/Accessibility.js';
import { import {
getTestState, getTestState,
setupTestBrowserHooks, setupTestBrowserHooks,
@ -29,7 +29,7 @@ describeFailsFirefox('Accessibility', function () {
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should work', async () => { it('should work', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(` await page.setContent(`
<head> <head>
@ -58,14 +58,14 @@ describeFailsFirefox('Accessibility', function () {
role: 'document', role: 'document',
name: 'Accessibility Test', name: 'Accessibility Test',
children: [ children: [
{ role: 'text leaf', name: 'Hello World' }, {role: 'text leaf', name: 'Hello World'},
{ role: 'heading', name: 'Inputs', level: 1 }, {role: 'heading', name: 'Inputs', level: 1},
{ role: 'entry', name: 'Empty input', focused: true }, {role: 'entry', name: 'Empty input', focused: true},
{ role: 'entry', name: 'readonly input', readonly: true }, {role: 'entry', name: 'readonly input', readonly: true},
{ role: 'entry', name: 'disabled input', disabled: true }, {role: 'entry', name: 'disabled input', disabled: true},
{ role: 'entry', name: 'Input with whitespace', value: ' ' }, {role: 'entry', name: 'Input with whitespace', value: ' '},
{ role: 'entry', name: '', value: 'value only' }, {role: 'entry', name: '', value: 'value only'},
{ role: 'entry', name: '', value: 'and a value' }, // firefox doesn't use aria-placeholder for the name {role: 'entry', name: '', value: 'and a value'}, // firefox doesn't use aria-placeholder for the name
{ {
role: 'entry', role: 'entry',
name: '', name: '',
@ -83,7 +83,7 @@ describeFailsFirefox('Accessibility', function () {
name: 'First Option', name: 'First Option',
selected: true, selected: true,
}, },
{ role: 'combobox option', name: 'Second Option' }, {role: 'combobox option', name: 'Second Option'},
], ],
}, },
], ],
@ -92,14 +92,14 @@ describeFailsFirefox('Accessibility', function () {
role: 'RootWebArea', role: 'RootWebArea',
name: 'Accessibility Test', name: 'Accessibility Test',
children: [ children: [
{ role: 'StaticText', name: 'Hello World' }, {role: 'StaticText', name: 'Hello World'},
{ role: 'heading', name: 'Inputs', level: 1 }, {role: 'heading', name: 'Inputs', level: 1},
{ role: 'textbox', name: 'Empty input', focused: true }, {role: 'textbox', name: 'Empty input', focused: true},
{ role: 'textbox', name: 'readonly input', readonly: true }, {role: 'textbox', name: 'readonly input', readonly: true},
{ role: 'textbox', name: 'disabled input', disabled: true }, {role: 'textbox', name: 'disabled input', disabled: true},
{ role: 'textbox', name: 'Input with whitespace', value: ' ' }, {role: 'textbox', name: 'Input with whitespace', value: ' '},
{ role: 'textbox', name: '', value: 'value only' }, {role: 'textbox', name: '', value: 'value only'},
{ role: 'textbox', name: 'placeholder', value: 'and a value' }, {role: 'textbox', name: 'placeholder', value: 'and a value'},
{ {
role: 'textbox', role: 'textbox',
name: 'placeholder', name: 'placeholder',
@ -112,8 +112,8 @@ describeFailsFirefox('Accessibility', function () {
value: 'First Option', value: 'First Option',
haspopup: 'menu', haspopup: 'menu',
children: [ children: [
{ role: 'menuitem', name: 'First Option', selected: true }, {role: 'menuitem', name: 'First Option', selected: true},
{ role: 'menuitem', name: 'Second Option' }, {role: 'menuitem', name: 'Second Option'},
], ],
}, },
], ],
@ -121,7 +121,7 @@ describeFailsFirefox('Accessibility', function () {
expect(await page.accessibility.snapshot()).toEqual(golden); expect(await page.accessibility.snapshot()).toEqual(golden);
}); });
it('should report uninteresting nodes', async () => { it('should report uninteresting nodes', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(`<textarea>hi</textarea>`); await page.setContent(`<textarea>hi</textarea>`);
await page.focus('textarea'); await page.focus('textarea');
@ -160,12 +160,12 @@ describeFailsFirefox('Accessibility', function () {
}; };
expect( expect(
findFocusedNode( findFocusedNode(
await page.accessibility.snapshot({ interestingOnly: false }) await page.accessibility.snapshot({interestingOnly: false})
) )
).toEqual(golden); ).toEqual(golden);
}); });
it('roledescription', async () => { it('roledescription', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
'<div tabIndex=-1 aria-roledescription="foo">Hi</div>' '<div tabIndex=-1 aria-roledescription="foo">Hi</div>'
@ -178,7 +178,7 @@ describeFailsFirefox('Accessibility', function () {
expect(snapshot.children[0]!.roledescription).toBeUndefined(); expect(snapshot.children[0]!.roledescription).toBeUndefined();
}); });
it('orientation', async () => { it('orientation', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
'<a href="" role="slider" aria-orientation="vertical">11</a>' '<a href="" role="slider" aria-orientation="vertical">11</a>'
@ -190,7 +190,7 @@ describeFailsFirefox('Accessibility', function () {
expect(snapshot.children[0]!.orientation).toEqual('vertical'); expect(snapshot.children[0]!.orientation).toEqual('vertical');
}); });
it('autocomplete', async () => { it('autocomplete', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent('<input type="number" aria-autocomplete="list" />'); await page.setContent('<input type="number" aria-autocomplete="list" />');
const snapshot = await page.accessibility.snapshot(); const snapshot = await page.accessibility.snapshot();
@ -200,7 +200,7 @@ describeFailsFirefox('Accessibility', function () {
expect(snapshot.children[0]!.autocomplete).toEqual('list'); expect(snapshot.children[0]!.autocomplete).toEqual('list');
}); });
it('multiselectable', async () => { it('multiselectable', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
'<div role="grid" tabIndex=-1 aria-multiselectable=true>hey</div>' '<div role="grid" tabIndex=-1 aria-multiselectable=true>hey</div>'
@ -212,7 +212,7 @@ describeFailsFirefox('Accessibility', function () {
expect(snapshot.children[0]!.multiselectable).toEqual(true); expect(snapshot.children[0]!.multiselectable).toEqual(true);
}); });
it('keyshortcuts', async () => { it('keyshortcuts', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
'<div role="grid" tabIndex=-1 aria-keyshortcuts="foo">hey</div>' '<div role="grid" tabIndex=-1 aria-keyshortcuts="foo">hey</div>'
@ -225,7 +225,7 @@ describeFailsFirefox('Accessibility', function () {
}); });
describe('filtering children of leaf nodes', function () { describe('filtering children of leaf nodes', function () {
it('should not report text nodes inside controls', async () => { it('should not report text nodes inside controls', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(` await page.setContent(`
<div role="tablist"> <div role="tablist">
@ -266,7 +266,7 @@ describeFailsFirefox('Accessibility', function () {
expect(await page.accessibility.snapshot()).toEqual(golden); expect(await page.accessibility.snapshot()).toEqual(golden);
}); });
it('rich text editable fields should have children', async () => { it('rich text editable fields should have children', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(` await page.setContent(`
<div contenteditable="true"> <div contenteditable="true">
@ -308,7 +308,7 @@ describeFailsFirefox('Accessibility', function () {
expect(snapshot.children[0]!).toEqual(golden); expect(snapshot.children[0]!).toEqual(golden);
}); });
it('rich text editable fields with role should have children', async () => { it('rich text editable fields with role should have children', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(` await page.setContent(`
<div contenteditable="true" role='textbox'> <div contenteditable="true" role='textbox'>
@ -351,7 +351,7 @@ describeFailsFirefox('Accessibility', function () {
// Firefox does not support contenteditable="plaintext-only". // Firefox does not support contenteditable="plaintext-only".
describeFailsFirefox('plaintext contenteditable', function () { describeFailsFirefox('plaintext contenteditable', function () {
it('plain text field with role should not have children', async () => { it('plain text field with role should not have children', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(` await page.setContent(`
<div contenteditable="plaintext-only" role='textbox'>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`); <div contenteditable="plaintext-only" role='textbox'>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`);
@ -367,7 +367,7 @@ describeFailsFirefox('Accessibility', function () {
}); });
}); });
it('non editable textbox with role and tabIndex and label should not have children', async () => { it('non editable textbox with role and tabIndex and label should not have children', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(` await page.setContent(`
<div role="textbox" tabIndex=0 aria-checked="true" aria-label="my favorite textbox"> <div role="textbox" tabIndex=0 aria-checked="true" aria-label="my favorite textbox">
@ -391,7 +391,7 @@ describeFailsFirefox('Accessibility', function () {
expect(snapshot.children[0]!).toEqual(golden); expect(snapshot.children[0]!).toEqual(golden);
}); });
it('checkbox with and tabIndex and label should not have children', async () => { it('checkbox with and tabIndex and label should not have children', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(` await page.setContent(`
<div role="checkbox" tabIndex=0 aria-checked="true" aria-label="my favorite checkbox"> <div role="checkbox" tabIndex=0 aria-checked="true" aria-label="my favorite checkbox">
@ -415,7 +415,7 @@ describeFailsFirefox('Accessibility', function () {
expect(snapshot.children[0]!).toEqual(golden); expect(snapshot.children[0]!).toEqual(golden);
}); });
it('checkbox without label should not have children', async () => { it('checkbox without label should not have children', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.setContent(` await page.setContent(`
<div role="checkbox" aria-checked="true"> <div role="checkbox" aria-checked="true">
@ -441,30 +441,30 @@ describeFailsFirefox('Accessibility', function () {
describe('root option', function () { describe('root option', function () {
it('should work a button', async () => { it('should work a button', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<button>My Button</button>`); await page.setContent(`<button>My Button</button>`);
const button = (await page.$('button'))!; const button = (await page.$('button'))!;
expect(await page.accessibility.snapshot({ root: button })).toEqual({ expect(await page.accessibility.snapshot({root: button})).toEqual({
role: 'button', role: 'button',
name: 'My Button', name: 'My Button',
}); });
}); });
it('should work an input', async () => { it('should work an input', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input title="My Input" value="My Value">`); await page.setContent(`<input title="My Input" value="My Value">`);
const input = (await page.$('input'))!; const input = (await page.$('input'))!;
expect(await page.accessibility.snapshot({ root: input })).toEqual({ expect(await page.accessibility.snapshot({root: input})).toEqual({
role: 'textbox', role: 'textbox',
name: 'My Input', name: 'My Input',
value: 'My Value', value: 'My Value',
}); });
}); });
it('should work a menu', async () => { it('should work a menu', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(` await page.setContent(`
<div role="menu" title="My Menu"> <div role="menu" title="My Menu">
@ -475,35 +475,33 @@ describeFailsFirefox('Accessibility', function () {
`); `);
const menu = (await page.$('div[role="menu"]'))!; const menu = (await page.$('div[role="menu"]'))!;
expect(await page.accessibility.snapshot({ root: menu })).toEqual({ expect(await page.accessibility.snapshot({root: menu})).toEqual({
role: 'menu', role: 'menu',
name: 'My Menu', name: 'My Menu',
children: [ children: [
{ role: 'menuitem', name: 'First Item' }, {role: 'menuitem', name: 'First Item'},
{ role: 'menuitem', name: 'Second Item' }, {role: 'menuitem', name: 'Second Item'},
{ role: 'menuitem', name: 'Third Item' }, {role: 'menuitem', name: 'Third Item'},
], ],
orientation: 'vertical', orientation: 'vertical',
}); });
}); });
it('should return null when the element is no longer in DOM', async () => { it('should return null when the element is no longer in DOM', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<button>My Button</button>`); await page.setContent(`<button>My Button</button>`);
const button = (await page.$('button'))!; const button = (await page.$('button'))!;
await page.$eval('button', (button) => { await page.$eval('button', button => {
return button.remove(); return button.remove();
}); });
expect(await page.accessibility.snapshot({ root: button })).toEqual( expect(await page.accessibility.snapshot({root: button})).toEqual(null);
null
);
}); });
it('should support the interestingOnly option', async () => { it('should support the interestingOnly option', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<div><button>My Button</button></div>`); await page.setContent(`<div><button>My Button</button></div>`);
const div = (await page.$('div'))!; const div = (await page.$('div'))!;
expect(await page.accessibility.snapshot({ root: div })).toEqual(null); expect(await page.accessibility.snapshot({root: div})).toEqual(null);
expect( expect(
await page.accessibility.snapshot({ await page.accessibility.snapshot({
root: div, root: div,
@ -516,7 +514,7 @@ describeFailsFirefox('Accessibility', function () {
{ {
role: 'button', role: 'button',
name: 'My Button', name: 'My Button',
children: [{ role: 'StaticText', name: 'My Button' }], children: [{role: 'StaticText', name: 'My Button'}],
}, },
], ],
}); });

View File

@ -22,7 +22,7 @@ import {
describeChromeOnly, describeChromeOnly,
} from './mocha-utils.js'; } from './mocha-utils.js';
import { ElementHandle } from '../../lib/cjs/puppeteer/common/JSHandle.js'; import {ElementHandle} from '../../lib/cjs/puppeteer/common/JSHandle.js';
import utils from './utils.js'; import utils from './utils.js';
import assert from 'assert'; import assert from 'assert';
@ -32,13 +32,13 @@ describeChromeOnly('AriaQueryHandler', () => {
describe('parseAriaSelector', () => { describe('parseAriaSelector', () => {
beforeEach(async () => { beforeEach(async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
'<button id="btn" role="button"> Submit button and some spaces </button>' '<button id="btn" role="button"> Submit button and some spaces </button>'
); );
}); });
it('should find button', async () => { it('should find button', async () => {
const { page } = getTestState(); const {page} = getTestState();
const expectFound = async (button: ElementHandle | null) => { const expectFound = async (button: ElementHandle | null) => {
assert(button); assert(button);
const id = await button.evaluate((button: Element) => { const id = await button.evaluate((button: Element) => {
@ -94,7 +94,7 @@ describeChromeOnly('AriaQueryHandler', () => {
describe('queryOne', () => { describe('queryOne', () => {
it('should find button by role', async () => { it('should find button by role', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
'<div id="div"><button id="btn" role="button">Submit</button></div>' '<div id="div"><button id="btn" role="button">Submit</button></div>'
); );
@ -106,7 +106,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should find button by name and role', async () => { it('should find button by name and role', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
'<div id="div"><button id="btn" role="button">Submit</button></div>' '<div id="div"><button id="btn" role="button">Submit</button></div>'
); );
@ -118,7 +118,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should find first matching element', async () => { it('should find first matching element', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
` `
<div role="menu" id="mnu1" aria-label="menu div"></div> <div role="menu" id="mnu1" aria-label="menu div"></div>
@ -133,7 +133,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should find by name', async () => { it('should find by name', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
` `
<div role="menu" id="mnu1" aria-label="menu-label1">menu div</div> <div role="menu" id="mnu1" aria-label="menu-label1">menu div</div>
@ -148,7 +148,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should find by name', async () => { it('should find by name', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
` `
<div role="menu" id="mnu1" aria-label="menu-label1">menu div</div> <div role="menu" id="mnu1" aria-label="menu-label1">menu div</div>
@ -165,7 +165,7 @@ describeChromeOnly('AriaQueryHandler', () => {
describe('queryAll', () => { describe('queryAll', () => {
it('should find menu by name', async () => { it('should find menu by name', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
` `
<div role="menu" id="mnu1" aria-label="menu div"></div> <div role="menu" id="mnu1" aria-label="menu div"></div>
@ -174,7 +174,7 @@ describeChromeOnly('AriaQueryHandler', () => {
); );
const divs = await page.$$('aria/menu div'); const divs = await page.$$('aria/menu div');
const ids = await Promise.all( const ids = await Promise.all(
divs.map((n) => { divs.map(n => {
return n.evaluate((div: Element) => { return n.evaluate((div: Element) => {
return div.id; return div.id;
}); });
@ -185,7 +185,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
describe('queryAllArray', () => { describe('queryAllArray', () => {
it('$$eval should handle many elements', async () => { it('$$eval should handle many elements', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(''); await page.setContent('');
await page.evaluate( await page.evaluate(
` `
@ -196,7 +196,7 @@ describeChromeOnly('AriaQueryHandler', () => {
} }
` `
); );
const sum = await page.$$eval('aria/[role="button"]', (buttons) => { const sum = await page.$$eval('aria/[role="button"]', buttons => {
return buttons.reduce((acc, button) => { return buttons.reduce((acc, button) => {
return acc + Number(button.textContent); return acc + Number(button.textContent);
}, 0); }, 0);
@ -211,14 +211,14 @@ describeChromeOnly('AriaQueryHandler', () => {
}; };
it('should immediately resolve promise if node exists', async () => { it('should immediately resolve promise if node exists', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(addElement, 'button'); await page.evaluate(addElement, 'button');
await page.waitForSelector('aria/[role="button"]'); await page.waitForSelector('aria/[role="button"]');
}); });
it('should work for ElementHandler.waitForSelector', async () => { it('should work for ElementHandler.waitForSelector', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {
return (document.body.innerHTML = `<div><button>test</button></div>`); return (document.body.innerHTML = `<div><button>test</button></div>`);
@ -228,7 +228,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should persist query handler bindings across reloads', async () => { it('should persist query handler bindings across reloads', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(addElement, 'button'); await page.evaluate(addElement, 'button');
await page.waitForSelector('aria/[role="button"]'); await page.waitForSelector('aria/[role="button"]');
@ -238,7 +238,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should persist query handler bindings across navigations', async () => { it('should persist query handler bindings across navigations', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
// Reset page but make sure that execution context ids start with 1. // Reset page but make sure that execution context ids start with 1.
await page.goto('data:text/html,'); await page.goto('data:text/html,');
@ -254,7 +254,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should work independently of `exposeFunction`', async () => { it('should work independently of `exposeFunction`', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.exposeFunction('ariaQuerySelector', (a: number, b: number) => { await page.exposeFunction('ariaQuerySelector', (a: number, b: number) => {
return a + b; return a + b;
@ -266,7 +266,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should work with removed MutationObserver', async () => { it('should work with removed MutationObserver', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
// @ts-expect-error This is the point of the test. // @ts-expect-error This is the point of the test.
@ -284,7 +284,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should resolve promise when node is added', async () => { it('should resolve promise when node is added', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const frame = page.mainFrame(); const frame = page.mainFrame();
@ -299,7 +299,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should work when node is added through innerHTML', async () => { it('should work when node is added through innerHTML', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const watchdog = page.waitForSelector('aria/name'); const watchdog = page.waitForSelector('aria/name');
@ -312,7 +312,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('Page.waitForSelector is shortcut for main frame', async () => { it('Page.waitForSelector is shortcut for main frame', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
@ -325,7 +325,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should run in specified frame', async () => { it('should run in specified frame', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE);
@ -341,14 +341,14 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should throw when frame is detached', async () => { it('should throw when frame is detached', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
const frame = page.frames()[1]; const frame = page.frames()[1];
let waitError!: Error; let waitError!: Error;
const waitPromise = frame! const waitPromise = frame!
.waitForSelector('aria/does-not-exist') .waitForSelector('aria/does-not-exist')
.catch((error) => { .catch(error => {
return (waitError = error); return (waitError = error);
}); });
await utils.detachFrame(page, 'frame1'); await utils.detachFrame(page, 'frame1');
@ -360,7 +360,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should survive cross-process navigation', async () => { it('should survive cross-process navigation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let imgFound = false; let imgFound = false;
const waitForSelector = page const waitForSelector = page
@ -378,11 +378,11 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should wait for visible', async () => { it('should wait for visible', async () => {
const { page } = getTestState(); const {page} = getTestState();
let divFound = false; let divFound = false;
const waitForSelector = page const waitForSelector = page
.waitForSelector('aria/name', { visible: true }) .waitForSelector('aria/name', {visible: true})
.then(() => { .then(() => {
return (divFound = true); return (divFound = true);
}); });
@ -404,11 +404,11 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should wait for visible recursively', async () => { it('should wait for visible recursively', async () => {
const { page } = getTestState(); const {page} = getTestState();
let divVisible = false; let divVisible = false;
const waitForSelector = page const waitForSelector = page
.waitForSelector('aria/inner', { visible: true }) .waitForSelector('aria/inner', {visible: true})
.then(() => { .then(() => {
return (divVisible = true); return (divVisible = true);
}); });
@ -430,14 +430,14 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('hidden should wait for visibility: hidden', async () => { it('hidden should wait for visibility: hidden', async () => {
const { page } = getTestState(); const {page} = getTestState();
let divHidden = false; let divHidden = false;
await page.setContent( await page.setContent(
`<div role='button' style='display: block;'></div>` `<div role='button' style='display: block;'></div>`
); );
const waitForSelector = page const waitForSelector = page
.waitForSelector('aria/[role="button"]', { hidden: true }) .waitForSelector('aria/[role="button"]', {hidden: true})
.then(() => { .then(() => {
return (divHidden = true); return (divHidden = true);
}); });
@ -453,12 +453,12 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('hidden should wait for display: none', async () => { it('hidden should wait for display: none', async () => {
const { page } = getTestState(); const {page} = getTestState();
let divHidden = false; let divHidden = false;
await page.setContent(`<div role='main' style='display: block;'></div>`); await page.setContent(`<div role='main' style='display: block;'></div>`);
const waitForSelector = page const waitForSelector = page
.waitForSelector('aria/[role="main"]', { hidden: true }) .waitForSelector('aria/[role="main"]', {hidden: true})
.then(() => { .then(() => {
return (divHidden = true); return (divHidden = true);
}); });
@ -474,12 +474,12 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('hidden should wait for removal', async () => { it('hidden should wait for removal', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<div role='main'></div>`); await page.setContent(`<div role='main'></div>`);
let divRemoved = false; let divRemoved = false;
const waitForSelector = page const waitForSelector = page
.waitForSelector('aria/[role="main"]', { hidden: true }) .waitForSelector('aria/[role="main"]', {hidden: true})
.then(() => { .then(() => {
return (divRemoved = true); return (divRemoved = true);
}); });
@ -493,7 +493,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should return null if waiting to hide non-existing element', async () => { it('should return null if waiting to hide non-existing element', async () => {
const { page } = getTestState(); const {page} = getTestState();
const handle = await page.waitForSelector('aria/non-existing', { const handle = await page.waitForSelector('aria/non-existing', {
hidden: true, hidden: true,
@ -502,12 +502,12 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should respect timeout', async () => { it('should respect timeout', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
let error!: Error; let error!: Error;
await page await page
.waitForSelector('aria/[role="button"]', { timeout: 10 }) .waitForSelector('aria/[role="button"]', {timeout: 10})
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeTruthy(); expect(error).toBeTruthy();
@ -518,13 +518,13 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should have an error message specifically for awaiting an element to be hidden', async () => { it('should have an error message specifically for awaiting an element to be hidden', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<div role='main'></div>`); await page.setContent(`<div role='main'></div>`);
let error!: Error; let error!: Error;
await page await page
.waitForSelector('aria/[role="main"]', { hidden: true, timeout: 10 }) .waitForSelector('aria/[role="main"]', {hidden: true, timeout: 10})
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeTruthy(); expect(error).toBeTruthy();
@ -534,7 +534,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should respond to node attribute mutation', async () => { it('should respond to node attribute mutation', async () => {
const { page } = getTestState(); const {page} = getTestState();
let divFound = false; let divFound = false;
const waitForSelector = page.waitForSelector('aria/zombo').then(() => { const waitForSelector = page.waitForSelector('aria/zombo').then(() => {
@ -551,7 +551,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should return the element handle', async () => { it('should return the element handle', async () => {
const { page } = getTestState(); const {page} = getTestState();
const waitForSelector = page.waitForSelector('aria/zombo'); const waitForSelector = page.waitForSelector('aria/zombo');
await page.setContent(`<div aria-label='zombo'>anything</div>`); await page.setContent(`<div aria-label='zombo'>anything</div>`);
@ -563,21 +563,19 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
it('should have correct stack trace for timeout', async () => { it('should have correct stack trace for timeout', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page.waitForSelector('aria/zombo', {timeout: 10}).catch(error_ => {
.waitForSelector('aria/zombo', { timeout: 10 }) return (error = error_);
.catch((error_) => { });
return (error = error_);
});
expect(error!.stack).toContain('waiting for selector `zombo` failed'); expect(error!.stack).toContain('waiting for selector `zombo` failed');
}); });
}); });
describe('queryOne (Chromium web test)', async () => { describe('queryOne (Chromium web test)', async () => {
beforeEach(async () => { beforeEach(async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
` `
<h2 id="shown">title</h2> <h2 id="shown">title</h2>
@ -626,7 +624,7 @@ describeChromeOnly('AriaQueryHandler', () => {
}); });
const getIds = async (elements: ElementHandle[]) => { const getIds = async (elements: ElementHandle[]) => {
return Promise.all( return Promise.all(
elements.map((element) => { elements.map(element => {
return element.evaluate((element: Element) => { return element.evaluate((element: Element) => {
return element.id; return element.id;
}); });
@ -634,25 +632,25 @@ describeChromeOnly('AriaQueryHandler', () => {
); );
}; };
it('should find by name "foo"', async () => { it('should find by name "foo"', async () => {
const { page } = getTestState(); const {page} = getTestState();
const found = await page.$$('aria/foo'); const found = await page.$$('aria/foo');
const ids = await getIds(found); const ids = await getIds(found);
expect(ids).toEqual(['node3', 'node5', 'node6']); expect(ids).toEqual(['node3', 'node5', 'node6']);
}); });
it('should find by name "bar"', async () => { it('should find by name "bar"', async () => {
const { page } = getTestState(); const {page} = getTestState();
const found = await page.$$('aria/bar'); const found = await page.$$('aria/bar');
const ids = await getIds(found); const ids = await getIds(found);
expect(ids).toEqual(['node1', 'node2', 'node8']); expect(ids).toEqual(['node1', 'node2', 'node8']);
}); });
it('should find treeitem by name', async () => { it('should find treeitem by name', async () => {
const { page } = getTestState(); const {page} = getTestState();
const found = await page.$$('aria/item1 item2 item3'); const found = await page.$$('aria/item1 item2 item3');
const ids = await getIds(found); const ids = await getIds(found);
expect(ids).toEqual(['node30']); expect(ids).toEqual(['node30']);
}); });
it('should find by role "button"', async () => { it('should find by role "button"', async () => {
const { page } = getTestState(); const {page} = getTestState();
const found = await page.$$<HTMLButtonElement>('aria/[role="button"]'); const found = await page.$$<HTMLButtonElement>('aria/[role="button"]');
const ids = await getIds(found); const ids = await getIds(found);
expect(ids).toEqual([ expect(ids).toEqual([
@ -665,13 +663,13 @@ describeChromeOnly('AriaQueryHandler', () => {
]); ]);
}); });
it('should find by role "heading"', async () => { it('should find by role "heading"', async () => {
const { page } = getTestState(); const {page} = getTestState();
const found = await page.$$('aria/[role="heading"]'); const found = await page.$$('aria/[role="heading"]');
const ids = await getIds(found); const ids = await getIds(found);
expect(ids).toEqual(['shown', 'hidden', 'node11', 'node13']); expect(ids).toEqual(['shown', 'hidden', 'node11', 'node13']);
}); });
it('should find both ignored and unignored', async () => { it('should find both ignored and unignored', async () => {
const { page } = getTestState(); const {page} = getTestState();
const found = await page.$$('aria/title'); const found = await page.$$('aria/title');
const ids = await getIds(found); const ids = await getIds(found);
expect(ids).toEqual(['shown', 'hidden']); expect(ids).toEqual(['shown', 'hidden']);

View File

@ -15,14 +15,14 @@
*/ */
import expect from 'expect'; import expect from 'expect';
import { getTestState, setupTestBrowserHooks } from './mocha-utils.js'; import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Browser specs', function () { describe('Browser specs', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
describe('Browser.version', function () { describe('Browser.version', function () {
it('should return whether we are in headless', async () => { it('should return whether we are in headless', async () => {
const { browser, isHeadless, headless } = getTestState(); const {browser, isHeadless, headless} = getTestState();
const version = await browser.version(); const version = await browser.version();
expect(version.length).toBeGreaterThan(0); expect(version.length).toBeGreaterThan(0);
@ -34,7 +34,7 @@ describe('Browser specs', function () {
describe('Browser.userAgent', function () { describe('Browser.userAgent', function () {
it('should include WebKit', async () => { it('should include WebKit', async () => {
const { browser, isChrome } = getTestState(); const {browser, isChrome} = getTestState();
const userAgent = await browser.userAgent(); const userAgent = await browser.userAgent();
expect(userAgent.length).toBeGreaterThan(0); expect(userAgent.length).toBeGreaterThan(0);
@ -48,7 +48,7 @@ describe('Browser specs', function () {
describe('Browser.target', function () { describe('Browser.target', function () {
it('should return browser target', async () => { it('should return browser target', async () => {
const { browser } = getTestState(); const {browser} = getTestState();
const target = browser.target(); const target = browser.target();
expect(target.type()).toBe('browser'); expect(target.type()).toBe('browser');
@ -57,16 +57,16 @@ describe('Browser specs', function () {
describe('Browser.process', function () { describe('Browser.process', function () {
it('should return child_process instance', async () => { it('should return child_process instance', async () => {
const { browser } = getTestState(); const {browser} = getTestState();
const process = await browser.process(); const process = await browser.process();
expect(process!.pid).toBeGreaterThan(0); expect(process!.pid).toBeGreaterThan(0);
}); });
it('should not return child_process for remote browser', async () => { it('should not return child_process for remote browser', async () => {
const { browser, puppeteer } = getTestState(); const {browser, puppeteer} = getTestState();
const browserWSEndpoint = browser.wsEndpoint(); const browserWSEndpoint = browser.wsEndpoint();
const remoteBrowser = await puppeteer.connect({ browserWSEndpoint }); const remoteBrowser = await puppeteer.connect({browserWSEndpoint});
expect(remoteBrowser.process()).toBe(null); expect(remoteBrowser.process()).toBe(null);
remoteBrowser.disconnect(); remoteBrowser.disconnect();
}); });
@ -74,10 +74,10 @@ describe('Browser specs', function () {
describe('Browser.isConnected', () => { describe('Browser.isConnected', () => {
it('should set the browser connected state', async () => { it('should set the browser connected state', async () => {
const { browser, puppeteer } = getTestState(); const {browser, puppeteer} = getTestState();
const browserWSEndpoint = browser.wsEndpoint(); const browserWSEndpoint = browser.wsEndpoint();
const newBrowser = await puppeteer.connect({ browserWSEndpoint }); const newBrowser = await puppeteer.connect({browserWSEndpoint});
expect(newBrowser.isConnected()).toBe(true); expect(newBrowser.isConnected()).toBe(true);
newBrowser.disconnect(); newBrowser.disconnect();
expect(newBrowser.isConnected()).toBe(false); expect(newBrowser.isConnected()).toBe(false);

View File

@ -25,19 +25,19 @@ import utils from './utils.js';
describe('BrowserContext', function () { describe('BrowserContext', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
it('should have default context', async () => { it('should have default context', async () => {
const { browser } = getTestState(); const {browser} = getTestState();
expect(browser.browserContexts().length).toEqual(1); expect(browser.browserContexts().length).toEqual(1);
const defaultContext = browser.browserContexts()[0]!; const defaultContext = browser.browserContexts()[0]!;
expect(defaultContext!.isIncognito()).toBe(false); expect(defaultContext!.isIncognito()).toBe(false);
let error!: Error; let error!: Error;
await defaultContext!.close().catch((error_) => { await defaultContext!.close().catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(browser.defaultBrowserContext()).toBe(defaultContext); expect(browser.defaultBrowserContext()).toBe(defaultContext);
expect(error.message).toContain('cannot be closed'); expect(error.message).toContain('cannot be closed');
}); });
it('should create new incognito context', async () => { it('should create new incognito context', async () => {
const { browser } = getTestState(); const {browser} = getTestState();
expect(browser.browserContexts().length).toBe(1); expect(browser.browserContexts().length).toBe(1);
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();
@ -48,7 +48,7 @@ describe('BrowserContext', function () {
expect(browser.browserContexts().length).toBe(1); expect(browser.browserContexts().length).toBe(1);
}); });
it('should close all belonging targets once closing context', async () => { it('should close all belonging targets once closing context', async () => {
const { browser } = getTestState(); const {browser} = getTestState();
expect((await browser.pages()).length).toBe(1); expect((await browser.pages()).length).toBe(1);
@ -61,14 +61,14 @@ describe('BrowserContext', function () {
expect((await browser.pages()).length).toBe(1); expect((await browser.pages()).length).toBe(1);
}); });
itFailsFirefox('window.open should use parent tab context', async () => { itFailsFirefox('window.open should use parent tab context', async () => {
const { browser, server } = getTestState(); const {browser, server} = getTestState();
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const [popupTarget] = await Promise.all([ const [popupTarget] = await Promise.all([
utils.waitEvent(browser, 'targetcreated'), utils.waitEvent(browser, 'targetcreated'),
page.evaluate<(url: string) => void>((url) => { page.evaluate<(url: string) => void>(url => {
return window.open(url); return window.open(url);
}, server.EMPTY_PAGE), }, server.EMPTY_PAGE),
]); ]);
@ -76,17 +76,17 @@ describe('BrowserContext', function () {
await context.close(); await context.close();
}); });
itFailsFirefox('should fire target events', async () => { itFailsFirefox('should fire target events', async () => {
const { browser, server } = getTestState(); const {browser, server} = getTestState();
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();
const events: any[] = []; const events: any[] = [];
context.on('targetcreated', (target) => { context.on('targetcreated', target => {
return events.push('CREATED: ' + target.url()); return events.push('CREATED: ' + target.url());
}); });
context.on('targetchanged', (target) => { context.on('targetchanged', target => {
return events.push('CHANGED: ' + target.url()); return events.push('CHANGED: ' + target.url());
}); });
context.on('targetdestroyed', (target) => { context.on('targetdestroyed', target => {
return events.push('DESTROYED: ' + target.url()); return events.push('DESTROYED: ' + target.url());
}); });
const page = await context.newPage(); const page = await context.newPage();
@ -100,19 +100,19 @@ describe('BrowserContext', function () {
await context.close(); await context.close();
}); });
itFailsFirefox('should wait for a target', async () => { itFailsFirefox('should wait for a target', async () => {
const { browser, puppeteer, server } = getTestState(); const {browser, puppeteer, server} = getTestState();
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();
let resolved = false; let resolved = false;
const targetPromise = context.waitForTarget((target) => { const targetPromise = context.waitForTarget(target => {
return target.url() === server.EMPTY_PAGE; return target.url() === server.EMPTY_PAGE;
}); });
targetPromise targetPromise
.then(() => { .then(() => {
return (resolved = true); return (resolved = true);
}) })
.catch((error) => { .catch(error => {
resolved = true; resolved = true;
if (error instanceof puppeteer.errors.TimeoutError) { if (error instanceof puppeteer.errors.TimeoutError) {
console.error(error); console.error(error);
@ -137,19 +137,19 @@ describe('BrowserContext', function () {
}); });
it('should timeout waiting for a non-existent target', async () => { it('should timeout waiting for a non-existent target', async () => {
const { browser, puppeteer, server } = getTestState(); const {browser, puppeteer, server} = getTestState();
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();
const error = await context const error = await context
.waitForTarget( .waitForTarget(
(target) => { target => {
return target.url() === server.EMPTY_PAGE; return target.url() === server.EMPTY_PAGE;
}, },
{ {
timeout: 1, timeout: 1,
} }
) )
.catch((error_) => { .catch(error_ => {
return error_; return error_;
}); });
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
@ -157,7 +157,7 @@ describe('BrowserContext', function () {
}); });
itFailsFirefox('should isolate localStorage and cookies', async () => { itFailsFirefox('should isolate localStorage and cookies', async () => {
const { browser, server } = getTestState(); const {browser, server} = getTestState();
// Create two incognito contexts. // Create two incognito contexts.
const context1 = await browser.createIncognitoBrowserContext(); const context1 = await browser.createIncognitoBrowserContext();
@ -217,7 +217,7 @@ describe('BrowserContext', function () {
}); });
itFailsFirefox('should work across sessions', async () => { itFailsFirefox('should work across sessions', async () => {
const { browser, puppeteer } = getTestState(); const {browser, puppeteer} = getTestState();
expect(browser.browserContexts().length).toBe(1); expect(browser.browserContexts().length).toBe(1);
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import expect from 'expect'; import expect from 'expect';
import { IncomingMessage } from 'http'; import {IncomingMessage} from 'http';
import { import {
getTestState, getTestState,
setupTestBrowserHooks, setupTestBrowserHooks,
@ -25,7 +25,7 @@ import {
describeChromeOnly('Chromium-Specific Launcher tests', function () { describeChromeOnly('Chromium-Specific Launcher tests', function () {
describe('Puppeteer.launch |browserURL| option', function () { describe('Puppeteer.launch |browserURL| option', function () {
it('should be able to connect using browserUrl, with and without trailing slash', async () => { it('should be able to connect using browserUrl, with and without trailing slash', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const originalBrowser = await puppeteer.launch( const originalBrowser = await puppeteer.launch(
Object.assign({}, defaultBrowserOptions, { Object.assign({}, defaultBrowserOptions, {
@ -34,7 +34,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
); );
const browserURL = 'http://127.0.0.1:21222'; const browserURL = 'http://127.0.0.1:21222';
const browser1 = await puppeteer.connect({ browserURL }); const browser1 = await puppeteer.connect({browserURL});
const page1 = await browser1.newPage(); const page1 = await browser1.newPage();
expect( expect(
await page1.evaluate(() => { await page1.evaluate(() => {
@ -56,7 +56,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
originalBrowser.close(); originalBrowser.close();
}); });
it('should throw when using both browserWSEndpoint and browserURL', async () => { it('should throw when using both browserWSEndpoint and browserURL', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const originalBrowser = await puppeteer.launch( const originalBrowser = await puppeteer.launch(
Object.assign({}, defaultBrowserOptions, { Object.assign({}, defaultBrowserOptions, {
@ -71,7 +71,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
browserURL, browserURL,
browserWSEndpoint: originalBrowser.wsEndpoint(), browserWSEndpoint: originalBrowser.wsEndpoint(),
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain( expect(error.message).toContain(
@ -81,7 +81,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
originalBrowser.close(); originalBrowser.close();
}); });
it('should throw when trying to connect to non-existing browser', async () => { it('should throw when trying to connect to non-existing browser', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const originalBrowser = await puppeteer.launch( const originalBrowser = await puppeteer.launch(
Object.assign({}, defaultBrowserOptions, { Object.assign({}, defaultBrowserOptions, {
@ -91,7 +91,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
const browserURL = 'http://127.0.0.1:32333'; const browserURL = 'http://127.0.0.1:32333';
let error!: Error; let error!: Error;
await puppeteer.connect({ browserURL }).catch((error_) => { await puppeteer.connect({browserURL}).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain( expect(error.message).toContain(
@ -103,8 +103,8 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
describe('Puppeteer.launch |pipe| option', function () { describe('Puppeteer.launch |pipe| option', function () {
it('should support the pipe option', async () => { it('should support the pipe option', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const options = Object.assign({ pipe: true }, defaultBrowserOptions); const options = Object.assign({pipe: true}, defaultBrowserOptions);
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
expect((await browser.pages()).length).toBe(1); expect((await browser.pages()).length).toBe(1);
expect(browser.wsEndpoint()).toBe(''); expect(browser.wsEndpoint()).toBe('');
@ -114,7 +114,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
await browser.close(); await browser.close();
}); });
it('should support the pipe argument', async () => { it('should support the pipe argument', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, defaultBrowserOptions);
options.args = ['--remote-debugging-pipe'].concat(options.args || []); options.args = ['--remote-debugging-pipe'].concat(options.args || []);
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
@ -125,10 +125,10 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
await browser.close(); await browser.close();
}); });
it('should fire "disconnected" when closing with pipe', async () => { it('should fire "disconnected" when closing with pipe', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const options = Object.assign({ pipe: true }, defaultBrowserOptions); const options = Object.assign({pipe: true}, defaultBrowserOptions);
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
const disconnectedEventPromise = new Promise((resolve) => { const disconnectedEventPromise = new Promise(resolve => {
return browser.once('disconnected', resolve); return browser.once('disconnected', resolve);
}); });
// Emulate user exiting browser. // Emulate user exiting browser.
@ -142,7 +142,7 @@ describeChromeOnly('Chromium-Specific Page Tests', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('Page.setRequestInterception should work with intervention headers', async () => { it('Page.setRequestInterception should work with intervention headers', async () => {
const { server, page } = getTestState(); const {server, page} = getTestState();
server.setRoute('/intervention', (_req, res) => { server.setRoute('/intervention', (_req, res) => {
return res.end(` return res.end(`
@ -159,7 +159,7 @@ describeChromeOnly('Chromium-Specific Page Tests', function () {
}); });
await page.setRequestInterception(true); await page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
return request.continue(); return request.continue();
}); });
await page.goto(server.PREFIX + '/intervention'); await page.goto(server.PREFIX + '/intervention');

View File

@ -27,7 +27,7 @@ describe('Page.click', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should click the button', async () => { it('should click the button', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.click('button'); await page.click('button');
@ -38,7 +38,7 @@ describe('Page.click', function () {
).toBe('Clicked'); ).toBe('Clicked');
}); });
it('should click svg', async () => { it('should click svg', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(` await page.setContent(`
<svg height="100" width="100"> <svg height="100" width="100">
@ -55,7 +55,7 @@ describe('Page.click', function () {
itFailsFirefox( itFailsFirefox(
'should click the button if window.Node is removed', 'should click the button if window.Node is removed',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => { await page.evaluate(() => {
@ -72,7 +72,7 @@ describe('Page.click', function () {
); );
// @see https://github.com/puppeteer/puppeteer/issues/4281 // @see https://github.com/puppeteer/puppeteer/issues/4281
it('should click on a span with an inline element inside', async () => { it('should click on a span with an inline element inside', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(` await page.setContent(`
<style> <style>
@ -90,7 +90,7 @@ describe('Page.click', function () {
).toBe(42); ).toBe(42);
}); });
it('should not throw UnhandledPromiseRejection when page closes', async () => { it('should not throw UnhandledPromiseRejection when page closes', async () => {
const { page } = getTestState(); const {page} = getTestState();
const newPage = await page.browser().newPage(); const newPage = await page.browser().newPage();
await Promise.all([newPage.close(), newPage.mouse.click(1, 2)]).catch( await Promise.all([newPage.close(), newPage.mouse.click(1, 2)]).catch(
@ -98,7 +98,7 @@ describe('Page.click', function () {
); );
}); });
it('should click the button after navigation ', async () => { it('should click the button after navigation ', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.click('button'); await page.click('button');
@ -111,7 +111,7 @@ describe('Page.click', function () {
).toBe('Clicked'); ).toBe('Clicked');
}); });
itFailsFirefox('should click with disabled javascript', async () => { itFailsFirefox('should click with disabled javascript', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.setJavaScriptEnabled(false); await page.setJavaScriptEnabled(false);
await page.goto(server.PREFIX + '/wrappedlink.html'); await page.goto(server.PREFIX + '/wrappedlink.html');
@ -119,7 +119,7 @@ describe('Page.click', function () {
expect(page.url()).toBe(server.PREFIX + '/wrappedlink.html#clicked'); expect(page.url()).toBe(server.PREFIX + '/wrappedlink.html#clicked');
}); });
it('should click when one of inline box children is outside of viewport', async () => { it('should click when one of inline box children is outside of viewport', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(` await page.setContent(`
<style> <style>
@ -138,7 +138,7 @@ describe('Page.click', function () {
).toBe(42); ).toBe(42);
}); });
it('should select the text by triple clicking', async () => { it('should select the text by triple clicking', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
@ -146,8 +146,8 @@ describe('Page.click', function () {
"This is the text that we are going to try to select. Let's see how it goes."; "This is the text that we are going to try to select. Let's see how it goes.";
await page.keyboard.type(text); await page.keyboard.type(text);
await page.click('textarea'); await page.click('textarea');
await page.click('textarea', { clickCount: 2 }); await page.click('textarea', {clickCount: 2});
await page.click('textarea', { clickCount: 3 }); await page.click('textarea', {clickCount: 3});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
const textarea = document.querySelector('textarea'); const textarea = document.querySelector('textarea');
@ -159,11 +159,11 @@ describe('Page.click', function () {
).toBe(text); ).toBe(text);
}); });
it('should click offscreen buttons', async () => { it('should click offscreen buttons', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/offscreenbuttons.html'); await page.goto(server.PREFIX + '/offscreenbuttons.html');
const messages: any[] = []; const messages: any[] = [];
page.on('console', (msg) => { page.on('console', msg => {
return messages.push(msg.text()); return messages.push(msg.text());
}); });
for (let i = 0; i < 11; ++i) { for (let i = 0; i < 11; ++i) {
@ -189,7 +189,7 @@ describe('Page.click', function () {
}); });
it('should click wrapped links', async () => { it('should click wrapped links', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/wrappedlink.html'); await page.goto(server.PREFIX + '/wrappedlink.html');
await page.click('a'); await page.click('a');
@ -201,7 +201,7 @@ describe('Page.click', function () {
}); });
it('should click on checkbox input and toggle', async () => { it('should click on checkbox input and toggle', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/checkbox.html'); await page.goto(server.PREFIX + '/input/checkbox.html');
expect( expect(
@ -238,7 +238,7 @@ describe('Page.click', function () {
}); });
itFailsFirefox('should click on checkbox label and toggle', async () => { itFailsFirefox('should click on checkbox label and toggle', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/checkbox.html'); await page.goto(server.PREFIX + '/input/checkbox.html');
expect( expect(
@ -266,11 +266,11 @@ describe('Page.click', function () {
}); });
it('should fail to click a missing button', async () => { it('should fail to click a missing button', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
let error!: Error; let error!: Error;
await page.click('button.does-not-exist').catch((error_) => { await page.click('button.does-not-exist').catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe( expect(error.message).toBe(
@ -279,7 +279,7 @@ describe('Page.click', function () {
}); });
// @see https://github.com/puppeteer/puppeteer/issues/161 // @see https://github.com/puppeteer/puppeteer/issues/161
it('should not hang with touch-enabled viewports', async () => { it('should not hang with touch-enabled viewports', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
await page.setViewport(puppeteer.devices['iPhone 6']!.viewport); await page.setViewport(puppeteer.devices['iPhone 6']!.viewport);
await page.mouse.down(); await page.mouse.down();
@ -287,7 +287,7 @@ describe('Page.click', function () {
await page.mouse.up(); await page.mouse.up();
}); });
it('should scroll and click the button', async () => { it('should scroll and click the button', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.click('#button-5'); await page.click('#button-5');
@ -304,7 +304,7 @@ describe('Page.click', function () {
).toBe('clicked'); ).toBe('clicked');
}); });
it('should double click the button', async () => { it('should double click the button', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => { await page.evaluate(() => {
@ -315,12 +315,12 @@ describe('Page.click', function () {
}); });
}); });
const button = (await page.$('button'))!; const button = (await page.$('button'))!;
await button!.click({ clickCount: 2 }); await button!.click({clickCount: 2});
expect(await page.evaluate('double')).toBe(true); expect(await page.evaluate('double')).toBe(true);
expect(await page.evaluate('result')).toBe('Clicked'); expect(await page.evaluate('result')).toBe('Clicked');
}); });
it('should click a partially obscured button', async () => { it('should click a partially obscured button', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => { await page.evaluate(() => {
@ -337,7 +337,7 @@ describe('Page.click', function () {
).toBe('Clicked'); ).toBe('Clicked');
}); });
it('should click a rotated button', async () => { it('should click a rotated button', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/rotatedButton.html'); await page.goto(server.PREFIX + '/input/rotatedButton.html');
await page.click('button'); await page.click('button');
@ -348,10 +348,10 @@ describe('Page.click', function () {
).toBe('Clicked'); ).toBe('Clicked');
}); });
it('should fire contextmenu event on right click', async () => { it('should fire contextmenu event on right click', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.click('#button-8', { button: 'right' }); await page.click('#button-8', {button: 'right'});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return document.querySelector('#button-8')!.textContent; return document.querySelector('#button-8')!.textContent;
@ -359,10 +359,10 @@ describe('Page.click', function () {
).toBe('context menu'); ).toBe('context menu');
}); });
it('should fire aux event on middle click', async () => { it('should fire aux event on middle click', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.click('#button-8', { button: 'middle' }); await page.click('#button-8', {button: 'middle'});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return document.querySelector('#button-8')!.textContent; return document.querySelector('#button-8')!.textContent;
@ -370,10 +370,10 @@ describe('Page.click', function () {
).toBe('aux click'); ).toBe('aux click');
}); });
it('should fire back click', async () => { it('should fire back click', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.click('#button-8', { button: 'back' }); await page.click('#button-8', {button: 'back'});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return document.querySelector('#button-8')!.textContent; return document.querySelector('#button-8')!.textContent;
@ -381,10 +381,10 @@ describe('Page.click', function () {
).toBe('back click'); ).toBe('back click');
}); });
it('should fire forward click', async () => { it('should fire forward click', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.click('#button-8', { button: 'forward' }); await page.click('#button-8', {button: 'forward'});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return document.querySelector('#button-8')!.textContent; return document.querySelector('#button-8')!.textContent;
@ -393,14 +393,14 @@ describe('Page.click', function () {
}); });
// @see https://github.com/puppeteer/puppeteer/issues/206 // @see https://github.com/puppeteer/puppeteer/issues/206
it('should click links which cause navigation', async () => { it('should click links which cause navigation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.setContent(`<a href="${server.EMPTY_PAGE}">empty.html</a>`); await page.setContent(`<a href="${server.EMPTY_PAGE}">empty.html</a>`);
// This await should not hang. // This await should not hang.
await page.click('a'); await page.click('a');
}); });
it('should click the button inside an iframe', async () => { it('should click the button inside an iframe', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setContent('<div style="width:100px;height:100px">spacer</div>'); await page.setContent('<div style="width:100px;height:100px">spacer</div>');
@ -420,10 +420,10 @@ describe('Page.click', function () {
}); });
// @see https://github.com/puppeteer/puppeteer/issues/4110 // @see https://github.com/puppeteer/puppeteer/issues/4110
xit('should click the button with fixed position inside an iframe', async () => { xit('should click the button with fixed position inside an iframe', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setViewport({ width: 500, height: 500 }); await page.setViewport({width: 500, height: 500});
await page.setContent( await page.setContent(
'<div style="width:100px;height:2000px">spacer</div>' '<div style="width:100px;height:2000px">spacer</div>'
); );
@ -444,9 +444,9 @@ describe('Page.click', function () {
).toBe('Clicked'); ).toBe('Clicked');
}); });
it('should click the button with deviceScaleFactor set', async () => { it('should click the button with deviceScaleFactor set', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.setViewport({ width: 400, height: 400, deviceScaleFactor: 5 }); await page.setViewport({width: 400, height: 400, deviceScaleFactor: 5});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return window.devicePixelRatio; return window.devicePixelRatio;

View File

@ -28,12 +28,12 @@ describe('Cookie specs', () => {
describe('Page.cookies', function () { describe('Page.cookies', function () {
it('should return no cookies in pristine browser context', async () => { it('should return no cookies in pristine browser context', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
expectCookieEquals(await page.cookies(), []); expectCookieEquals(await page.cookies(), []);
}); });
it('should get a cookie', async () => { it('should get a cookie', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {
document.cookie = 'username=John Doe'; document.cookie = 'username=John Doe';
@ -57,7 +57,7 @@ describe('Cookie specs', () => {
]); ]);
}); });
it('should properly report httpOnly cookie', async () => { it('should properly report httpOnly cookie', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setRoute('/empty.html', (_req, res) => { server.setRoute('/empty.html', (_req, res) => {
res.setHeader('Set-Cookie', 'a=b; HttpOnly; Path=/'); res.setHeader('Set-Cookie', 'a=b; HttpOnly; Path=/');
res.end(); res.end();
@ -68,7 +68,7 @@ describe('Cookie specs', () => {
expect(cookies[0]!.httpOnly).toBe(true); expect(cookies[0]!.httpOnly).toBe(true);
}); });
it('should properly report "Strict" sameSite cookie', async () => { it('should properly report "Strict" sameSite cookie', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setRoute('/empty.html', (_req, res) => { server.setRoute('/empty.html', (_req, res) => {
res.setHeader('Set-Cookie', 'a=b; SameSite=Strict'); res.setHeader('Set-Cookie', 'a=b; SameSite=Strict');
res.end(); res.end();
@ -79,7 +79,7 @@ describe('Cookie specs', () => {
expect(cookies[0]!.sameSite).toBe('Strict'); expect(cookies[0]!.sameSite).toBe('Strict');
}); });
it('should properly report "Lax" sameSite cookie', async () => { it('should properly report "Lax" sameSite cookie', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setRoute('/empty.html', (_req, res) => { server.setRoute('/empty.html', (_req, res) => {
res.setHeader('Set-Cookie', 'a=b; SameSite=Lax'); res.setHeader('Set-Cookie', 'a=b; SameSite=Lax');
res.end(); res.end();
@ -90,7 +90,7 @@ describe('Cookie specs', () => {
expect(cookies[0]!.sameSite).toBe('Lax'); expect(cookies[0]!.sameSite).toBe('Lax');
}); });
it('should get multiple cookies', async () => { it('should get multiple cookies', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {
document.cookie = 'username=John Doe'; document.cookie = 'username=John Doe';
@ -132,7 +132,7 @@ describe('Cookie specs', () => {
]); ]);
}); });
itFailsFirefox('should get cookies from multiple urls', async () => { itFailsFirefox('should get cookies from multiple urls', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setCookie( await page.setCookie(
{ {
url: 'https://foo.com', url: 'https://foo.com',
@ -188,7 +188,7 @@ describe('Cookie specs', () => {
}); });
describe('Page.setCookie', function () { describe('Page.setCookie', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie({ await page.setCookie({
@ -202,7 +202,7 @@ describe('Cookie specs', () => {
).toEqual('password=123456'); ).toEqual('password=123456');
}); });
itFailsFirefox('should isolate cookies in browser contexts', async () => { itFailsFirefox('should isolate cookies in browser contexts', async () => {
const { page, server, browser } = getTestState(); const {page, server, browser} = getTestState();
const anotherContext = await browser.createIncognitoBrowserContext(); const anotherContext = await browser.createIncognitoBrowserContext();
const anotherPage = await anotherContext.newPage(); const anotherPage = await anotherContext.newPage();
@ -210,8 +210,8 @@ describe('Cookie specs', () => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await anotherPage.goto(server.EMPTY_PAGE); await anotherPage.goto(server.EMPTY_PAGE);
await page.setCookie({ name: 'page1cookie', value: 'page1value' }); await page.setCookie({name: 'page1cookie', value: 'page1value'});
await anotherPage.setCookie({ name: 'page2cookie', value: 'page2value' }); await anotherPage.setCookie({name: 'page2cookie', value: 'page2value'});
const cookies1 = await page.cookies(); const cookies1 = await page.cookies();
const cookies2 = await anotherPage.cookies(); const cookies2 = await anotherPage.cookies();
@ -224,7 +224,7 @@ describe('Cookie specs', () => {
await anotherContext.close(); await anotherContext.close();
}); });
itFailsFirefox('should set multiple cookies', async () => { itFailsFirefox('should set multiple cookies', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie( await page.setCookie(
@ -240,7 +240,7 @@ describe('Cookie specs', () => {
const cookieStrings = await page.evaluate(() => { const cookieStrings = await page.evaluate(() => {
const cookies = document.cookie.split(';'); const cookies = document.cookie.split(';');
return cookies return cookies
.map((cookie) => { .map(cookie => {
return cookie.trim(); return cookie.trim();
}) })
.sort(); .sort();
@ -249,7 +249,7 @@ describe('Cookie specs', () => {
expect(cookieStrings).toEqual(['foo=bar', 'password=123456']); expect(cookieStrings).toEqual(['foo=bar', 'password=123456']);
}); });
it('should have |expires| set to |-1| for session cookies', async () => { it('should have |expires| set to |-1| for session cookies', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie({ await page.setCookie({
@ -261,7 +261,7 @@ describe('Cookie specs', () => {
expect(cookies[0]!.expires).toBe(-1); expect(cookies[0]!.expires).toBe(-1);
}); });
itFailsFirefox('should set cookie with reasonable defaults', async () => { itFailsFirefox('should set cookie with reasonable defaults', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie({ await page.setCookie({
@ -292,7 +292,7 @@ describe('Cookie specs', () => {
); );
}); });
itFailsFirefox('should set a cookie with a path', async () => { itFailsFirefox('should set a cookie with a path', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
await page.setCookie({ await page.setCookie({
@ -324,12 +324,12 @@ describe('Cookie specs', () => {
expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID'); expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID');
}); });
it('should not set a cookie on a blank page', async () => { it('should not set a cookie on a blank page', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.goto('about:blank'); await page.goto('about:blank');
let error!: Error; let error!: Error;
try { try {
await page.setCookie({ name: 'example-cookie', value: 'best' }); await page.setCookie({name: 'example-cookie', value: 'best'});
} catch (error_) { } catch (error_) {
error = error_ as Error; error = error_ as Error;
} }
@ -338,14 +338,14 @@ describe('Cookie specs', () => {
); );
}); });
it('should not set a cookie with blank page URL', async () => { it('should not set a cookie with blank page URL', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let error!: Error; let error!: Error;
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
try { try {
await page.setCookie( await page.setCookie(
{ name: 'example-cookie', value: 'best' }, {name: 'example-cookie', value: 'best'},
{ url: 'about:blank', name: 'example-cookie-blank', value: 'best' } {url: 'about:blank', name: 'example-cookie-blank', value: 'best'}
); );
} catch (error_) { } catch (error_) {
error = error_ as Error; error = error_ as Error;
@ -355,12 +355,12 @@ describe('Cookie specs', () => {
); );
}); });
it('should not set a cookie on a data URL page', async () => { it('should not set a cookie on a data URL page', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page.goto('data:,Hello%2C%20World!'); await page.goto('data:,Hello%2C%20World!');
try { try {
await page.setCookie({ name: 'example-cookie', value: 'best' }); await page.setCookie({name: 'example-cookie', value: 'best'});
} catch (error_) { } catch (error_) {
error = error_ as Error; error = error_ as Error;
} }
@ -371,7 +371,7 @@ describe('Cookie specs', () => {
itFailsFirefox( itFailsFirefox(
'should default to setting secure cookie for HTTPS websites', 'should default to setting secure cookie for HTTPS websites',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const SECURE_URL = 'https://example.com'; const SECURE_URL = 'https://example.com';
@ -385,7 +385,7 @@ describe('Cookie specs', () => {
} }
); );
it('should be able to set unsecure cookie for HTTP website', async () => { it('should be able to set unsecure cookie for HTTP website', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const HTTP_URL = 'http://example.com'; const HTTP_URL = 'http://example.com';
@ -398,7 +398,7 @@ describe('Cookie specs', () => {
expect(cookie!.secure).toBe(false); expect(cookie!.secure).toBe(false);
}); });
itFailsFirefox('should set a cookie on a different domain', async () => { itFailsFirefox('should set a cookie on a different domain', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie({ await page.setCookie({
@ -426,13 +426,13 @@ describe('Cookie specs', () => {
]); ]);
}); });
itFailsFirefox('should set cookies from a frame', async () => { itFailsFirefox('should set cookies from a frame', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
await page.setCookie({ name: 'localhost-cookie', value: 'best' }); await page.setCookie({name: 'localhost-cookie', value: 'best'});
await page.evaluate<(src: string) => Promise<void>>((src) => { await page.evaluate<(src: string) => Promise<void>>(src => {
let fulfill!: () => void; let fulfill!: () => void;
const promise = new Promise<void>((x) => { const promise = new Promise<void>(x => {
return (fulfill = x); return (fulfill = x);
}); });
const iframe = document.createElement('iframe') as HTMLIFrameElement; const iframe = document.createElement('iframe') as HTMLIFrameElement;
@ -488,8 +488,7 @@ describe('Cookie specs', () => {
itFailsFirefox( itFailsFirefox(
'should set secure same-site cookies from a frame', 'should set secure same-site cookies from a frame',
async () => { async () => {
const { httpsServer, puppeteer, defaultBrowserOptions } = const {httpsServer, puppeteer, defaultBrowserOptions} = getTestState();
getTestState();
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
...defaultBrowserOptions, ...defaultBrowserOptions,
@ -500,9 +499,9 @@ describe('Cookie specs', () => {
try { try {
await page.goto(httpsServer.PREFIX + '/grid.html'); await page.goto(httpsServer.PREFIX + '/grid.html');
await page.evaluate<(src: string) => Promise<void>>((src) => { await page.evaluate<(src: string) => Promise<void>>(src => {
let fulfill!: () => void; let fulfill!: () => void;
const promise = new Promise<void>((x) => { const promise = new Promise<void>(x => {
return (fulfill = x); return (fulfill = x);
}); });
const iframe = document.createElement('iframe'); const iframe = document.createElement('iframe');
@ -551,7 +550,7 @@ describe('Cookie specs', () => {
describe('Page.deleteCookie', function () { describe('Page.deleteCookie', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie( await page.setCookie(
@ -571,7 +570,7 @@ describe('Cookie specs', () => {
expect(await page.evaluate('document.cookie')).toBe( expect(await page.evaluate('document.cookie')).toBe(
'cookie1=1; cookie2=2; cookie3=3' 'cookie1=1; cookie2=2; cookie3=3'
); );
await page.deleteCookie({ name: 'cookie2' }); await page.deleteCookie({name: 'cookie2'});
expect(await page.evaluate('document.cookie')).toBe( expect(await page.evaluate('document.cookie')).toBe(
'cookie1=1; cookie3=3' 'cookie1=1; cookie3=3'
); );

View File

@ -28,7 +28,7 @@ describe('Coverage specs', function () {
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/simple.html', { await page.goto(server.PREFIX + '/jscoverage/simple.html', {
waitUntil: 'networkidle0', waitUntil: 'networkidle0',
@ -37,12 +37,12 @@ describe('Coverage specs', function () {
expect(coverage.length).toBe(1); expect(coverage.length).toBe(1);
expect(coverage[0]!.url).toContain('/jscoverage/simple.html'); expect(coverage[0]!.url).toContain('/jscoverage/simple.html');
expect(coverage[0]!.ranges).toEqual([ expect(coverage[0]!.ranges).toEqual([
{ start: 0, end: 17 }, {start: 0, end: 17},
{ start: 35, end: 61 }, {start: 35, end: 61},
]); ]);
}); });
it('should report sourceURLs', async () => { it('should report sourceURLs', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/sourceurl.html'); await page.goto(server.PREFIX + '/jscoverage/sourceurl.html');
@ -51,7 +51,7 @@ describe('Coverage specs', function () {
expect(coverage[0]!.url).toBe('nicename.js'); expect(coverage[0]!.url).toBe('nicename.js');
}); });
it('should ignore eval() scripts by default', async () => { it('should ignore eval() scripts by default', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/eval.html'); await page.goto(server.PREFIX + '/jscoverage/eval.html');
@ -59,22 +59,22 @@ describe('Coverage specs', function () {
expect(coverage.length).toBe(1); expect(coverage.length).toBe(1);
}); });
it("shouldn't ignore eval() scripts if reportAnonymousScripts is true", async () => { it("shouldn't ignore eval() scripts if reportAnonymousScripts is true", async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage({ reportAnonymousScripts: true }); await page.coverage.startJSCoverage({reportAnonymousScripts: true});
await page.goto(server.PREFIX + '/jscoverage/eval.html'); await page.goto(server.PREFIX + '/jscoverage/eval.html');
const coverage = await page.coverage.stopJSCoverage(); const coverage = await page.coverage.stopJSCoverage();
expect( expect(
coverage.find((entry) => { coverage.find(entry => {
return entry.url.startsWith('debugger://'); return entry.url.startsWith('debugger://');
}) })
).not.toBe(null); ).not.toBe(null);
expect(coverage.length).toBe(2); expect(coverage.length).toBe(2);
}); });
it('should ignore pptr internal scripts if reportAnonymousScripts is true', async () => { it('should ignore pptr internal scripts if reportAnonymousScripts is true', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage({ reportAnonymousScripts: true }); await page.coverage.startJSCoverage({reportAnonymousScripts: true});
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate('console.log("foo")'); await page.evaluate('console.log("foo")');
await page.evaluate(() => { await page.evaluate(() => {
@ -84,7 +84,7 @@ describe('Coverage specs', function () {
expect(coverage.length).toBe(0); expect(coverage.length).toBe(0);
}); });
it('should report multiple scripts', async () => { it('should report multiple scripts', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/multiple.html'); await page.goto(server.PREFIX + '/jscoverage/multiple.html');
@ -97,7 +97,7 @@ describe('Coverage specs', function () {
expect(coverage[1]!.url).toContain('/jscoverage/script2.js'); expect(coverage[1]!.url).toContain('/jscoverage/script2.js');
}); });
it('should report right ranges', async () => { it('should report right ranges', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/ranges.html'); await page.goto(server.PREFIX + '/jscoverage/ranges.html');
@ -111,7 +111,7 @@ describe('Coverage specs', function () {
); );
}); });
it('should report scripts that have no coverage', async () => { it('should report scripts that have no coverage', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/unused.html'); await page.goto(server.PREFIX + '/jscoverage/unused.html');
@ -122,7 +122,7 @@ describe('Coverage specs', function () {
expect(entry.ranges.length).toBe(0); expect(entry.ranges.length).toBe(0);
}); });
it('should work with conditionals', async () => { it('should work with conditionals', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/involved.html'); await page.goto(server.PREFIX + '/jscoverage/involved.html');
@ -133,7 +133,7 @@ describe('Coverage specs', function () {
}); });
// @see https://crbug.com/990945 // @see https://crbug.com/990945
xit('should not hang when there is a debugger statement', async () => { xit('should not hang when there is a debugger statement', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -144,9 +144,9 @@ describe('Coverage specs', function () {
}); });
describe('resetOnNavigation', function () { describe('resetOnNavigation', function () {
it('should report scripts across navigations when disabled', async () => { it('should report scripts across navigations when disabled', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage({ resetOnNavigation: false }); await page.coverage.startJSCoverage({resetOnNavigation: false});
await page.goto(server.PREFIX + '/jscoverage/multiple.html'); await page.goto(server.PREFIX + '/jscoverage/multiple.html');
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const coverage = await page.coverage.stopJSCoverage(); const coverage = await page.coverage.stopJSCoverage();
@ -154,7 +154,7 @@ describe('Coverage specs', function () {
}); });
it('should NOT report scripts across navigations when enabled', async () => { it('should NOT report scripts across navigations when enabled', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); // Enabled by default. await page.coverage.startJSCoverage(); // Enabled by default.
await page.goto(server.PREFIX + '/jscoverage/multiple.html'); await page.goto(server.PREFIX + '/jscoverage/multiple.html');
@ -165,7 +165,7 @@ describe('Coverage specs', function () {
}); });
describe('includeRawScriptCoverage', function () { describe('includeRawScriptCoverage', function () {
it('should not include rawScriptCoverage field when disabled', async () => { it('should not include rawScriptCoverage field when disabled', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/simple.html', { await page.goto(server.PREFIX + '/jscoverage/simple.html', {
waitUntil: 'networkidle0', waitUntil: 'networkidle0',
@ -175,7 +175,7 @@ describe('Coverage specs', function () {
expect(coverage[0]!.rawScriptCoverage).toBeUndefined(); expect(coverage[0]!.rawScriptCoverage).toBeUndefined();
}); });
it('should include rawScriptCoverage field when enabled', async () => { it('should include rawScriptCoverage field when enabled', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage({ await page.coverage.startJSCoverage({
includeRawScriptCoverage: true, includeRawScriptCoverage: true,
}); });
@ -189,7 +189,7 @@ describe('Coverage specs', function () {
}); });
// @see https://crbug.com/990945 // @see https://crbug.com/990945
xit('should not hang when there is a debugger statement', async () => { xit('should not hang when there is a debugger statement', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -205,21 +205,21 @@ describe('Coverage specs', function () {
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.goto(server.PREFIX + '/csscoverage/simple.html'); await page.goto(server.PREFIX + '/csscoverage/simple.html');
const coverage = await page.coverage.stopCSSCoverage(); const coverage = await page.coverage.stopCSSCoverage();
expect(coverage.length).toBe(1); expect(coverage.length).toBe(1);
expect(coverage[0]!.url).toContain('/csscoverage/simple.html'); expect(coverage[0]!.url).toContain('/csscoverage/simple.html');
expect(coverage[0]!.ranges).toEqual([{ start: 1, end: 22 }]); expect(coverage[0]!.ranges).toEqual([{start: 1, end: 22}]);
const range = coverage[0]!.ranges[0]!; const range = coverage[0]!.ranges[0]!;
expect(coverage[0]!.text.substring(range.start, range.end)).toBe( expect(coverage[0]!.text.substring(range.start, range.end)).toBe(
'div { color: green; }' 'div { color: green; }'
); );
}); });
it('should report sourceURLs', async () => { it('should report sourceURLs', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.goto(server.PREFIX + '/csscoverage/sourceurl.html'); await page.goto(server.PREFIX + '/csscoverage/sourceurl.html');
@ -228,7 +228,7 @@ describe('Coverage specs', function () {
expect(coverage[0]!.url).toBe('nicename.css'); expect(coverage[0]!.url).toBe('nicename.css');
}); });
it('should report multiple stylesheets', async () => { it('should report multiple stylesheets', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.goto(server.PREFIX + '/csscoverage/multiple.html'); await page.goto(server.PREFIX + '/csscoverage/multiple.html');
@ -241,7 +241,7 @@ describe('Coverage specs', function () {
expect(coverage[1]!.url).toContain('/csscoverage/stylesheet2.css'); expect(coverage[1]!.url).toContain('/csscoverage/stylesheet2.css');
}); });
it('should report stylesheets that have no coverage', async () => { it('should report stylesheets that have no coverage', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.goto(server.PREFIX + '/csscoverage/unused.html'); await page.goto(server.PREFIX + '/csscoverage/unused.html');
@ -251,17 +251,17 @@ describe('Coverage specs', function () {
expect(coverage[0]!.ranges.length).toBe(0); expect(coverage[0]!.ranges.length).toBe(0);
}); });
it('should work with media queries', async () => { it('should work with media queries', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.goto(server.PREFIX + '/csscoverage/media.html'); await page.goto(server.PREFIX + '/csscoverage/media.html');
const coverage = await page.coverage.stopCSSCoverage(); const coverage = await page.coverage.stopCSSCoverage();
expect(coverage.length).toBe(1); expect(coverage.length).toBe(1);
expect(coverage[0]!.url).toContain('/csscoverage/media.html'); expect(coverage[0]!.url).toContain('/csscoverage/media.html');
expect(coverage[0]!.ranges).toEqual([{ start: 17, end: 38 }]); expect(coverage[0]!.ranges).toEqual([{start: 17, end: 38}]);
}); });
it('should work with complicated usecases', async () => { it('should work with complicated usecases', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.goto(server.PREFIX + '/csscoverage/involved.html'); await page.goto(server.PREFIX + '/csscoverage/involved.html');
@ -271,10 +271,10 @@ describe('Coverage specs', function () {
).toBeGolden('csscoverage-involved.txt'); ).toBeGolden('csscoverage-involved.txt');
}); });
it('should ignore injected stylesheets', async () => { it('should ignore injected stylesheets', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.addStyleTag({ content: 'body { margin: 10px;}' }); await page.addStyleTag({content: 'body { margin: 10px;}'});
// trigger style recalc // trigger style recalc
const margin = await page.evaluate(() => { const margin = await page.evaluate(() => {
return window.getComputedStyle(document.body).margin; return window.getComputedStyle(document.body).margin;
@ -284,17 +284,17 @@ describe('Coverage specs', function () {
expect(coverage.length).toBe(0); expect(coverage.length).toBe(0);
}); });
it('should work with a recently loaded stylesheet', async () => { it('should work with a recently loaded stylesheet', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();
await page.evaluate<(url: string) => Promise<void>>(async (url) => { await page.evaluate<(url: string) => Promise<void>>(async url => {
document.body.textContent = 'hello, world'; document.body.textContent = 'hello, world';
const link = document.createElement('link'); const link = document.createElement('link');
link.rel = 'stylesheet'; link.rel = 'stylesheet';
link.href = url; link.href = url;
document.head.appendChild(link); document.head.appendChild(link);
await new Promise((x) => { await new Promise(x => {
return (link.onload = x); return (link.onload = x);
}); });
}, server.PREFIX + '/csscoverage/stylesheet1.css'); }, server.PREFIX + '/csscoverage/stylesheet1.css');
@ -303,16 +303,16 @@ describe('Coverage specs', function () {
}); });
describe('resetOnNavigation', function () { describe('resetOnNavigation', function () {
it('should report stylesheets across navigations', async () => { it('should report stylesheets across navigations', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage({ resetOnNavigation: false }); await page.coverage.startCSSCoverage({resetOnNavigation: false});
await page.goto(server.PREFIX + '/csscoverage/multiple.html'); await page.goto(server.PREFIX + '/csscoverage/multiple.html');
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const coverage = await page.coverage.stopCSSCoverage(); const coverage = await page.coverage.stopCSSCoverage();
expect(coverage.length).toBe(2); expect(coverage.length).toBe(2);
}); });
it('should NOT report scripts across navigations', async () => { it('should NOT report scripts across navigations', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.coverage.startCSSCoverage(); // Enabled by default. await page.coverage.startCSSCoverage(); // Enabled by default.
await page.goto(server.PREFIX + '/csscoverage/multiple.html'); await page.goto(server.PREFIX + '/csscoverage/multiple.html');

View File

@ -26,7 +26,7 @@ describe('DefaultBrowserContext', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('page.cookies() should work', async () => { it('page.cookies() should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {
@ -50,7 +50,7 @@ describe('DefaultBrowserContext', function () {
]); ]);
}); });
itFailsFirefox('page.setCookie() should work', async () => { itFailsFirefox('page.setCookie() should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie({ await page.setCookie({
@ -80,7 +80,7 @@ describe('DefaultBrowserContext', function () {
]); ]);
}); });
itFailsFirefox('page.deleteCookie() should work', async () => { itFailsFirefox('page.deleteCookie() should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setCookie( await page.setCookie(
@ -94,7 +94,7 @@ describe('DefaultBrowserContext', function () {
} }
); );
expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie2=2'); expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie2=2');
await page.deleteCookie({ name: 'cookie2' }); await page.deleteCookie({name: 'cookie2'});
expect(await page.evaluate('document.cookie')).toBe('cookie1=1'); expect(await page.evaluate('document.cookie')).toBe('cookie1=1');
expectCookieEquals(await page.cookies(), [ expectCookieEquals(await page.cookies(), [
{ {

View File

@ -28,9 +28,9 @@ describe('Page.Events.Dialog', function () {
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should fire', async () => { it('should fire', async () => {
const { page } = getTestState(); const {page} = getTestState();
const onDialog = sinon.stub().callsFake((dialog) => { const onDialog = sinon.stub().callsFake(dialog => {
dialog.accept(); dialog.accept();
}); });
page.on('dialog', onDialog); page.on('dialog', onDialog);
@ -47,9 +47,9 @@ describe('Page.Events.Dialog', function () {
}); });
itFailsFirefox('should allow accepting prompts', async () => { itFailsFirefox('should allow accepting prompts', async () => {
const { page } = getTestState(); const {page} = getTestState();
const onDialog = sinon.stub().callsFake((dialog) => { const onDialog = sinon.stub().callsFake(dialog => {
dialog.accept('answer!'); dialog.accept('answer!');
}); });
page.on('dialog', onDialog); page.on('dialog', onDialog);
@ -67,9 +67,9 @@ describe('Page.Events.Dialog', function () {
expect(result).toBe('answer!'); expect(result).toBe('answer!');
}); });
it('should dismiss the prompt', async () => { it('should dismiss the prompt', async () => {
const { page } = getTestState(); const {page} = getTestState();
page.on('dialog', (dialog) => { page.on('dialog', dialog => {
dialog.dismiss(); dialog.dismiss();
}); });
const result = await page.evaluate(() => { const result = await page.evaluate(() => {

View File

@ -26,13 +26,13 @@ describeChromeOnly('Input.drag', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should throw an exception if not enabled before usage', async () => { it('should throw an exception if not enabled before usage', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
const draggable = (await page.$('#drag'))!; const draggable = (await page.$('#drag'))!;
try { try {
await draggable!.drag({ x: 1, y: 1 }); await draggable!.drag({x: 1, y: 1});
} catch (error) { } catch (error) {
expect((error as Error).message).toContain( expect((error as Error).message).toContain(
'Drag Interception is not enabled!' 'Drag Interception is not enabled!'
@ -40,14 +40,14 @@ describeChromeOnly('Input.drag', function () {
} }
}); });
it('should emit a dragIntercepted event when dragged', async () => { it('should emit a dragIntercepted event when dragged', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
expect(page.isDragInterceptionEnabled()).toBe(false); expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true); await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true); expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!; const draggable = (await page.$('#drag'))!;
const data = await draggable.drag({ x: 1, y: 1 }); const data = await draggable.drag({x: 1, y: 1});
expect(data.items.length).toBe(1); expect(data.items.length).toBe(1);
expect( expect(
@ -57,14 +57,14 @@ describeChromeOnly('Input.drag', function () {
).toBe(true); ).toBe(true);
}); });
it('should emit a dragEnter', async () => { it('should emit a dragEnter', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
expect(page.isDragInterceptionEnabled()).toBe(false); expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true); await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true); expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!; const draggable = (await page.$('#drag'))!;
const data = await draggable.drag({ x: 1, y: 1 }); const data = await draggable.drag({x: 1, y: 1});
const dropzone = (await page.$('#drop'))!; const dropzone = (await page.$('#drop'))!;
await dropzone.dragEnter(data); await dropzone.dragEnter(data);
@ -80,14 +80,14 @@ describeChromeOnly('Input.drag', function () {
).toBe(true); ).toBe(true);
}); });
it('should emit a dragOver event', async () => { it('should emit a dragOver event', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
expect(page.isDragInterceptionEnabled()).toBe(false); expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true); await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true); expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!; const draggable = (await page.$('#drag'))!;
const data = await draggable.drag({ x: 1, y: 1 }); const data = await draggable.drag({x: 1, y: 1});
const dropzone = (await page.$('#drop'))!; const dropzone = (await page.$('#drop'))!;
await dropzone.dragEnter(data); await dropzone.dragEnter(data);
await dropzone.dragOver(data); await dropzone.dragOver(data);
@ -109,7 +109,7 @@ describeChromeOnly('Input.drag', function () {
).toBe(true); ).toBe(true);
}); });
it('can be dropped', async () => { it('can be dropped', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
expect(page.isDragInterceptionEnabled()).toBe(false); expect(page.isDragInterceptionEnabled()).toBe(false);
@ -117,7 +117,7 @@ describeChromeOnly('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(true); expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!; const draggable = (await page.$('#drag'))!;
const dropzone = (await page.$('#drop'))!; const dropzone = (await page.$('#drop'))!;
const data = await draggable.drag({ x: 1, y: 1 }); const data = await draggable.drag({x: 1, y: 1});
await dropzone.dragEnter(data); await dropzone.dragEnter(data);
await dropzone.dragOver(data); await dropzone.dragOver(data);
await dropzone.drop(data); await dropzone.drop(data);
@ -144,7 +144,7 @@ describeChromeOnly('Input.drag', function () {
).toBe(true); ).toBe(true);
}); });
it('can be dragged and dropped with a single function', async () => { it('can be dragged and dropped with a single function', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
expect(page.isDragInterceptionEnabled()).toBe(false); expect(page.isDragInterceptionEnabled()).toBe(false);
@ -176,18 +176,18 @@ describeChromeOnly('Input.drag', function () {
).toBe(true); ).toBe(true);
}); });
it('can be disabled', async () => { it('can be disabled', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
expect(page.isDragInterceptionEnabled()).toBe(false); expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true); await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true); expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!; const draggable = (await page.$('#drag'))!;
await draggable.drag({ x: 1, y: 1 }); await draggable.drag({x: 1, y: 1});
await page.setDragInterception(false); await page.setDragInterception(false);
try { try {
await draggable.drag({ x: 1, y: 1 }); await draggable.drag({x: 1, y: 1});
} catch (error) { } catch (error) {
expect((error as Error).message).toContain( expect((error as Error).message).toContain(
'Drag Interception is not enabled!' 'Drag Interception is not enabled!'

View File

@ -25,7 +25,7 @@ import {
} from './mocha-utils.js'; } from './mocha-utils.js';
import utils from './utils.js'; import utils from './utils.js';
import { ElementHandle } from '../../lib/cjs/puppeteer/common/JSHandle.js'; import {ElementHandle} from '../../lib/cjs/puppeteer/common/JSHandle.js';
describe('ElementHandle specs', function () { describe('ElementHandle specs', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
@ -33,39 +33,39 @@ describe('ElementHandle specs', function () {
describeFailsFirefox('ElementHandle.boundingBox', function () { describeFailsFirefox('ElementHandle.boundingBox', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.setViewport({ width: 500, height: 500 }); await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
const elementHandle = (await page.$('.box:nth-of-type(13)'))!; const elementHandle = (await page.$('.box:nth-of-type(13)'))!;
const box = await elementHandle.boundingBox(); const box = await elementHandle.boundingBox();
expect(box).toEqual({ x: 100, y: 50, width: 50, height: 50 }); expect(box).toEqual({x: 100, y: 50, width: 50, height: 50});
}); });
it('should handle nested frames', async () => { it('should handle nested frames', async () => {
const { page, server, isChrome } = getTestState(); const {page, server, isChrome} = getTestState();
await page.setViewport({ width: 500, height: 500 }); await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/frames/nested-frames.html'); await page.goto(server.PREFIX + '/frames/nested-frames.html');
const nestedFrame = page.frames()[1]!.childFrames()[1]!; const nestedFrame = page.frames()[1]!.childFrames()[1]!;
const elementHandle = (await nestedFrame.$('div'))!; const elementHandle = (await nestedFrame.$('div'))!;
const box = await elementHandle.boundingBox(); const box = await elementHandle.boundingBox();
if (isChrome) { if (isChrome) {
expect(box).toEqual({ x: 28, y: 182, width: 264, height: 18 }); expect(box).toEqual({x: 28, y: 182, width: 264, height: 18});
} else { } else {
expect(box).toEqual({ x: 28, y: 182, width: 254, height: 18 }); expect(box).toEqual({x: 28, y: 182, width: 254, height: 18});
} }
}); });
it('should return null for invisible elements', async () => { it('should return null for invisible elements', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent('<div style="display:none">hi</div>'); await page.setContent('<div style="display:none">hi</div>');
const element = (await page.$('div'))!; const element = (await page.$('div'))!;
expect(await element.boundingBox()).toBe(null); expect(await element.boundingBox()).toBe(null);
}); });
it('should force a layout', async () => { it('should force a layout', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setViewport({ width: 500, height: 500 }); await page.setViewport({width: 500, height: 500});
await page.setContent( await page.setContent(
'<div style="width: 100px; height: 100px">hello</div>' '<div style="width: 100px; height: 100px">hello</div>'
); );
@ -74,10 +74,10 @@ describe('ElementHandle specs', function () {
return (element.style.height = '200px'); return (element.style.height = '200px');
}, elementHandle); }, elementHandle);
const box = await elementHandle.boundingBox(); const box = await elementHandle.boundingBox();
expect(box).toEqual({ x: 8, y: 8, width: 100, height: 200 }); expect(box).toEqual({x: 8, y: 8, width: 100, height: 200});
}); });
it('should work with SVG nodes', async () => { it('should work with SVG nodes', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(` await page.setContent(`
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"> <svg xmlns="http://www.w3.org/2000/svg" width="500" height="500">
@ -88,7 +88,7 @@ describe('ElementHandle specs', function () {
const pptrBoundingBox = await element.boundingBox(); const pptrBoundingBox = await element.boundingBox();
const webBoundingBox = await page.evaluate((e: HTMLElement) => { const webBoundingBox = await page.evaluate((e: HTMLElement) => {
const rect = e.getBoundingClientRect(); const rect = e.getBoundingClientRect();
return { x: rect.x, y: rect.y, width: rect.width, height: rect.height }; return {x: rect.x, y: rect.y, width: rect.width, height: rect.height};
}, element); }, element);
expect(pptrBoundingBox).toEqual(webBoundingBox); expect(pptrBoundingBox).toEqual(webBoundingBox);
}); });
@ -96,7 +96,7 @@ describe('ElementHandle specs', function () {
describeFailsFirefox('ElementHandle.boxModel', function () { describeFailsFirefox('ElementHandle.boxModel', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/resetcss.html'); await page.goto(server.PREFIX + '/resetcss.html');
@ -151,7 +151,7 @@ describe('ElementHandle specs', function () {
}); });
it('should return null for invisible elements', async () => { it('should return null for invisible elements', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent('<div style="display:none">hi</div>'); await page.setContent('<div style="display:none">hi</div>');
const element = (await page.$('div'))!; const element = (await page.$('div'))!;
@ -161,7 +161,7 @@ describe('ElementHandle specs', function () {
describe('ElementHandle.contentFrame', function () { describe('ElementHandle.contentFrame', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
@ -174,7 +174,7 @@ describe('ElementHandle specs', function () {
describe('ElementHandle.click', function () { describe('ElementHandle.click', function () {
// See https://github.com/puppeteer/puppeteer/issues/7175 // See https://github.com/puppeteer/puppeteer/issues/7175
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!; const button = (await page.$('button'))!;
@ -186,7 +186,7 @@ describe('ElementHandle specs', function () {
).toBe('Clicked'); ).toBe('Clicked');
}); });
it('should work for Shadow DOM v1', async () => { it('should work for Shadow DOM v1', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/shadow.html'); await page.goto(server.PREFIX + '/shadow.html');
const buttonHandle = await page.evaluateHandle<ElementHandle>(() => { const buttonHandle = await page.evaluateHandle<ElementHandle>(() => {
@ -202,20 +202,20 @@ describe('ElementHandle specs', function () {
).toBe(true); ).toBe(true);
}); });
it('should work for TextNodes', async () => { it('should work for TextNodes', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const buttonTextNode = await page.evaluateHandle<ElementHandle>(() => { const buttonTextNode = await page.evaluateHandle<ElementHandle>(() => {
return document.querySelector('button')!.firstChild; return document.querySelector('button')!.firstChild;
}); });
let error!: Error; let error!: Error;
await buttonTextNode.click().catch((error_) => { await buttonTextNode.click().catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe('Node is not of type HTMLElement'); expect(error.message).toBe('Node is not of type HTMLElement');
}); });
it('should throw for detached nodes', async () => { it('should throw for detached nodes', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!; const button = (await page.$('button'))!;
@ -223,20 +223,20 @@ describe('ElementHandle specs', function () {
return button.remove(); return button.remove();
}, button); }, button);
let error!: Error; let error!: Error;
await button.click().catch((error_) => { await button.click().catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe('Node is detached from document'); expect(error.message).toBe('Node is detached from document');
}); });
it('should throw for hidden nodes', async () => { it('should throw for hidden nodes', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!; const button = (await page.$('button'))!;
await page.evaluate((button: HTMLElement) => { await page.evaluate((button: HTMLElement) => {
return (button.style.display = 'none'); return (button.style.display = 'none');
}, button); }, button);
const error = await button.click().catch((error_) => { const error = await button.click().catch(error_ => {
return error_; return error_;
}); });
expect(error.message).toBe( expect(error.message).toBe(
@ -244,14 +244,14 @@ describe('ElementHandle specs', function () {
); );
}); });
it('should throw for recursively hidden nodes', async () => { it('should throw for recursively hidden nodes', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!; const button = (await page.$('button'))!;
await page.evaluate((button: HTMLElement) => { await page.evaluate((button: HTMLElement) => {
return (button.parentElement!.style.display = 'none'); return (button.parentElement!.style.display = 'none');
}, button); }, button);
const error = await button.click().catch((error_) => { const error = await button.click().catch(error_ => {
return error_; return error_;
}); });
expect(error.message).toBe( expect(error.message).toBe(
@ -259,11 +259,11 @@ describe('ElementHandle specs', function () {
); );
}); });
it('should throw for <br> elements', async () => { it('should throw for <br> elements', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent('hello<br>goodbye'); await page.setContent('hello<br>goodbye');
const br = (await page.$('br'))!; const br = (await page.$('br'))!;
const error = await br.click().catch((error_) => { const error = await br.click().catch(error_ => {
return error_; return error_;
}); });
expect(error.message).toBe( expect(error.message).toBe(
@ -274,7 +274,7 @@ describe('ElementHandle specs', function () {
describe('Element.waitForSelector', () => { describe('Element.waitForSelector', () => {
it('should wait correctly with waitForSelector on an element', async () => { it('should wait correctly with waitForSelector on an element', async () => {
const { page } = getTestState(); const {page} = getTestState();
const waitFor = page.waitForSelector('.foo'); const waitFor = page.waitForSelector('.foo');
// Set the page content after the waitFor has been started. // Set the page content after the waitFor has been started.
await page.setContent( await page.setContent(
@ -284,13 +284,13 @@ describe('ElementHandle specs', function () {
expect(element).toBeDefined(); expect(element).toBeDefined();
const innerWaitFor = element.waitForSelector('.bar'); const innerWaitFor = element.waitForSelector('.bar');
await element.evaluate((el) => { await element.evaluate(el => {
el.innerHTML = '<div class="bar">bar1</div>'; el.innerHTML = '<div class="bar">bar1</div>';
}); });
element = (await innerWaitFor)!; element = (await innerWaitFor)!;
expect(element).toBeDefined(); expect(element).toBeDefined();
expect( expect(
await element.evaluate((el) => { await element.evaluate(el => {
return (el as HTMLElement).innerText; return (el as HTMLElement).innerText;
}) })
).toStrictEqual('bar1'); ).toStrictEqual('bar1');
@ -299,7 +299,7 @@ describe('ElementHandle specs', function () {
describe('Element.waitForXPath', () => { describe('Element.waitForXPath', () => {
it('should wait correctly with waitForXPath on an element', async () => { it('should wait correctly with waitForXPath on an element', async () => {
const { page } = getTestState(); const {page} = getTestState();
// Set the page content after the waitFor has been started. // Set the page content after the waitFor has been started.
await page.setContent( await page.setContent(
`<div id=el1> `<div id=el1>
@ -316,13 +316,13 @@ describe('ElementHandle specs', function () {
const el2 = (await page.waitForSelector('#el1'))!; const el2 = (await page.waitForSelector('#el1'))!;
expect( expect(
await (await el2.waitForXPath('//div'))!.evaluate((el) => { await (await el2.waitForXPath('//div'))!.evaluate(el => {
return el.id; return el.id;
}) })
).toStrictEqual('el2'); ).toStrictEqual('el2');
expect( expect(
await (await el2.waitForXPath('.//div'))!.evaluate((el) => { await (await el2.waitForXPath('.//div'))!.evaluate(el => {
return el.id; return el.id;
}) })
).toStrictEqual('el2'); ).toStrictEqual('el2');
@ -331,7 +331,7 @@ describe('ElementHandle specs', function () {
describe('ElementHandle.hover', function () { describe('ElementHandle.hover', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
const button = (await page.$('#button-6'))!; const button = (await page.$('#button-6'))!;
@ -346,7 +346,7 @@ describe('ElementHandle specs', function () {
describe('ElementHandle.isIntersectingViewport', function () { describe('ElementHandle.isIntersectingViewport', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/offscreenbuttons.html'); await page.goto(server.PREFIX + '/offscreenbuttons.html');
for (let i = 0; i < 11; ++i) { for (let i = 0; i < 11; ++i) {
@ -357,7 +357,7 @@ describe('ElementHandle specs', function () {
} }
}); });
it('should work with threshold', async () => { it('should work with threshold', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/offscreenbuttons.html'); await page.goto(server.PREFIX + '/offscreenbuttons.html');
// a button almost cannot be seen // a button almost cannot be seen
@ -370,7 +370,7 @@ describe('ElementHandle specs', function () {
).toBe(false); ).toBe(false);
}); });
it('should work with threshold of 1', async () => { it('should work with threshold of 1', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/offscreenbuttons.html'); await page.goto(server.PREFIX + '/offscreenbuttons.html');
// a button almost cannot be seen // a button almost cannot be seen
@ -386,11 +386,11 @@ describe('ElementHandle specs', function () {
describe('Custom queries', function () { describe('Custom queries', function () {
this.afterEach(() => { this.afterEach(() => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
puppeteer.clearCustomQueryHandlers(); puppeteer.clearCustomQueryHandlers();
}); });
it('should register and unregister', async () => { it('should register and unregister', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
await page.setContent('<div id="not-foo"></div><div id="foo"></div>'); await page.setContent('<div id="not-foo"></div><div id="foo"></div>');
// Register. // Register.
@ -401,7 +401,7 @@ describe('ElementHandle specs', function () {
}); });
const element = (await page.$('getById/foo'))!; const element = (await page.$('getById/foo'))!;
expect( expect(
await page.evaluate<(element: HTMLElement) => string>((element) => { await page.evaluate<(element: HTMLElement) => string>(element => {
return element.id; return element.id;
}, element) }, element)
).toBe('foo'); ).toBe('foo');
@ -426,7 +426,7 @@ describe('ElementHandle specs', function () {
}); });
it('should throw with invalid query names', () => { it('should throw with invalid query names', () => {
try { try {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
puppeteer.registerCustomQueryHandler('1/2/3', { puppeteer.registerCustomQueryHandler('1/2/3', {
queryOne: () => { queryOne: () => {
return document.querySelector('foo'); return document.querySelector('foo');
@ -442,7 +442,7 @@ describe('ElementHandle specs', function () {
} }
}); });
it('should work for multiple elements', async () => { it('should work for multiple elements', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
await page.setContent( await page.setContent(
'<div id="not-foo"></div><div class="foo">Foo1</div><div class="foo baz">Foo2</div>' '<div id="not-foo"></div><div class="foo">Foo1</div><div class="foo baz">Foo2</div>'
); );
@ -453,9 +453,9 @@ describe('ElementHandle specs', function () {
}); });
const elements = await page.$$('getByClass/foo'); const elements = await page.$$('getByClass/foo');
const classNames = await Promise.all( const classNames = await Promise.all(
elements.map(async (element) => { elements.map(async element => {
return await page.evaluate<(element: HTMLElement) => string>( return await page.evaluate<(element: HTMLElement) => string>(
(element) => { element => {
return element.className; return element.className;
}, },
element element
@ -466,7 +466,7 @@ describe('ElementHandle specs', function () {
expect(classNames).toStrictEqual(['foo', 'foo baz']); expect(classNames).toStrictEqual(['foo', 'foo baz']);
}); });
it('should eval correctly', async () => { it('should eval correctly', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
await page.setContent( await page.setContent(
'<div id="not-foo"></div><div class="foo">Foo1</div><div class="foo baz">Foo2</div>' '<div id="not-foo"></div><div class="foo">Foo1</div><div class="foo baz">Foo2</div>'
); );
@ -475,14 +475,14 @@ describe('ElementHandle specs', function () {
return document.querySelectorAll(`.${selector}`); return document.querySelectorAll(`.${selector}`);
}, },
}); });
const elements = await page.$$eval('getByClass/foo', (divs) => { const elements = await page.$$eval('getByClass/foo', divs => {
return divs.length; return divs.length;
}); });
expect(elements).toBe(2); expect(elements).toBe(2);
}); });
it('should wait correctly with waitForSelector', async () => { it('should wait correctly with waitForSelector', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
puppeteer.registerCustomQueryHandler('getByClass', { puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => { queryOne: (element, selector) => {
return element.querySelector(`.${selector}`); return element.querySelector(`.${selector}`);
@ -500,7 +500,7 @@ describe('ElementHandle specs', function () {
}); });
it('should wait correctly with waitForSelector on an element', async () => { it('should wait correctly with waitForSelector on an element', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
puppeteer.registerCustomQueryHandler('getByClass', { puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => { queryOne: (element, selector) => {
return element.querySelector(`.${selector}`); return element.querySelector(`.${selector}`);
@ -517,14 +517,14 @@ describe('ElementHandle specs', function () {
const innerWaitFor = element.waitForSelector('getByClass/bar'); const innerWaitFor = element.waitForSelector('getByClass/bar');
await element.evaluate((el) => { await element.evaluate(el => {
el.innerHTML = '<div class="bar">bar1</div>'; el.innerHTML = '<div class="bar">bar1</div>';
}); });
element = (await innerWaitFor)!; element = (await innerWaitFor)!;
expect(element).toBeDefined(); expect(element).toBeDefined();
expect( expect(
await element.evaluate((el) => { await element.evaluate(el => {
return (el as HTMLElement).innerText; return (el as HTMLElement).innerText;
}) })
).toStrictEqual('bar1'); ).toStrictEqual('bar1');
@ -533,7 +533,7 @@ describe('ElementHandle specs', function () {
it('should wait correctly with waitFor', async () => { it('should wait correctly with waitFor', async () => {
/* page.waitFor is deprecated so we silence the warning to avoid test noise */ /* page.waitFor is deprecated so we silence the warning to avoid test noise */
sinon.stub(console, 'warn').callsFake(() => {}); sinon.stub(console, 'warn').callsFake(() => {});
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
puppeteer.registerCustomQueryHandler('getByClass', { puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => { queryOne: (element, selector) => {
return element.querySelector(`.${selector}`); return element.querySelector(`.${selector}`);
@ -550,7 +550,7 @@ describe('ElementHandle specs', function () {
expect(element).toBeDefined(); expect(element).toBeDefined();
}); });
it('should work when both queryOne and queryAll are registered', async () => { it('should work when both queryOne and queryAll are registered', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
await page.setContent( await page.setContent(
'<div id="not-foo"></div><div class="foo"><div id="nested-foo" class="foo"/></div><div class="foo baz">Foo2</div>' '<div id="not-foo"></div><div class="foo"><div id="nested-foo" class="foo"/></div><div class="foo baz">Foo2</div>'
); );
@ -570,7 +570,7 @@ describe('ElementHandle specs', function () {
expect(elements.length).toBe(3); expect(elements.length).toBe(3);
}); });
it('should eval when both queryOne and queryAll are registered', async () => { it('should eval when both queryOne and queryAll are registered', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
await page.setContent( await page.setContent(
'<div id="not-foo"></div><div class="foo">text</div><div class="foo baz">content</div>' '<div id="not-foo"></div><div class="foo">text</div><div class="foo baz">content</div>'
); );
@ -583,14 +583,14 @@ describe('ElementHandle specs', function () {
}, },
}); });
const txtContent = await page.$eval('getByClass/foo', (div) => { const txtContent = await page.$eval('getByClass/foo', div => {
return div.textContent; return div.textContent;
}); });
expect(txtContent).toBe('text'); expect(txtContent).toBe('text');
const txtContents = await page.$$eval('getByClass/foo', (divs) => { const txtContents = await page.$$eval('getByClass/foo', divs => {
return divs return divs
.map((d) => { .map(d => {
return d.textContent; return d.textContent;
}) })
.join(''); .join('');

View File

@ -15,7 +15,7 @@
*/ */
import expect from 'expect'; import expect from 'expect';
import { Device } from '../../lib/cjs/puppeteer/common/DeviceDescriptors.js'; import {Device} from '../../lib/cjs/puppeteer/common/DeviceDescriptors.js';
import { import {
getTestState, getTestState,
setupTestBrowserHooks, setupTestBrowserHooks,
@ -31,21 +31,21 @@ describe('Emulation', () => {
let iPhoneLandscape!: Device; let iPhoneLandscape!: Device;
before(() => { before(() => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
iPhone = puppeteer.devices['iPhone 6']!; iPhone = puppeteer.devices['iPhone 6']!;
iPhoneLandscape = puppeteer.devices['iPhone 6 landscape']!; iPhoneLandscape = puppeteer.devices['iPhone 6 landscape']!;
}); });
describe('Page.viewport', function () { describe('Page.viewport', function () {
it('should get the proper viewport size', async () => { it('should get the proper viewport size', async () => {
const { page } = getTestState(); const {page} = getTestState();
expect(page.viewport()).toEqual({ width: 800, height: 600 }); expect(page.viewport()).toEqual({width: 800, height: 600});
await page.setViewport({ width: 123, height: 456 }); await page.setViewport({width: 123, height: 456});
expect(page.viewport()).toEqual({ width: 123, height: 456 }); expect(page.viewport()).toEqual({width: 123, height: 456});
}); });
it('should support mobile emulation', async () => { it('should support mobile emulation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/mobile.html'); await page.goto(server.PREFIX + '/mobile.html');
expect( expect(
@ -59,7 +59,7 @@ describe('Emulation', () => {
return window.innerWidth; return window.innerWidth;
}) })
).toBe(375); ).toBe(375);
await page.setViewport({ width: 400, height: 300 }); await page.setViewport({width: 400, height: 300});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return window.innerWidth; return window.innerWidth;
@ -67,7 +67,7 @@ describe('Emulation', () => {
).toBe(400); ).toBe(400);
}); });
it('should support touch emulation', async () => { it('should support touch emulation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/mobile.html'); await page.goto(server.PREFIX + '/mobile.html');
expect( expect(
@ -82,7 +82,7 @@ describe('Emulation', () => {
}) })
).toBe(true); ).toBe(true);
expect(await page.evaluate(dispatchTouch)).toBe('Received touch'); expect(await page.evaluate(dispatchTouch)).toBe('Received touch');
await page.setViewport({ width: 100, height: 100 }); await page.setViewport({width: 100, height: 100});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return 'ontouchstart' in window; return 'ontouchstart' in window;
@ -91,7 +91,7 @@ describe('Emulation', () => {
function dispatchTouch() { function dispatchTouch() {
let fulfill!: (value: string) => void; let fulfill!: (value: string) => void;
const promise = new Promise((x) => { const promise = new Promise(x => {
fulfill = x; fulfill = x;
}); });
window.ontouchstart = () => { window.ontouchstart = () => {
@ -105,7 +105,7 @@ describe('Emulation', () => {
} }
}); });
it('should be detectable by Modernizr', async () => { it('should be detectable by Modernizr', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/detect-touch.html'); await page.goto(server.PREFIX + '/detect-touch.html');
expect( expect(
@ -122,10 +122,10 @@ describe('Emulation', () => {
).toBe('YES'); ).toBe('YES');
}); });
it('should detect touch when applying viewport with touches', async () => { it('should detect touch when applying viewport with touches', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.setViewport({ width: 800, height: 600, hasTouch: true }); await page.setViewport({width: 800, height: 600, hasTouch: true});
await page.addScriptTag({ url: server.PREFIX + '/modernizr.js' }); await page.addScriptTag({url: server.PREFIX + '/modernizr.js'});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return (globalThis as any).Modernizr.touchevents; return (globalThis as any).Modernizr.touchevents;
@ -133,7 +133,7 @@ describe('Emulation', () => {
).toBe(true); ).toBe(true);
}); });
itFailsFirefox('should support landscape emulation', async () => { itFailsFirefox('should support landscape emulation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/mobile.html'); await page.goto(server.PREFIX + '/mobile.html');
expect( expect(
@ -147,7 +147,7 @@ describe('Emulation', () => {
return screen.orientation.type; return screen.orientation.type;
}) })
).toBe('landscape-primary'); ).toBe('landscape-primary');
await page.setViewport({ width: 100, height: 100 }); await page.setViewport({width: 100, height: 100});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return screen.orientation.type; return screen.orientation.type;
@ -158,7 +158,7 @@ describe('Emulation', () => {
describe('Page.emulate', function () { describe('Page.emulate', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/mobile.html'); await page.goto(server.PREFIX + '/mobile.html');
await page.emulate(iPhone); await page.emulate(iPhone);
@ -174,7 +174,7 @@ describe('Emulation', () => {
).toContain('iPhone'); ).toContain('iPhone');
}); });
itFailsFirefox('should support clicking', async () => { itFailsFirefox('should support clicking', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.emulate(iPhone); await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
@ -193,7 +193,7 @@ describe('Emulation', () => {
describe('Page.emulateMediaType', function () { describe('Page.emulateMediaType', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -229,10 +229,10 @@ describe('Emulation', () => {
).toBe(false); ).toBe(false);
}); });
it('should throw in case of bad argument', async () => { it('should throw in case of bad argument', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page.emulateMediaType('bad').catch((error_) => { await page.emulateMediaType('bad').catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe('Unsupported media type: bad'); expect(error.message).toBe('Unsupported media type: bad');
@ -241,10 +241,10 @@ describe('Emulation', () => {
describe('Page.emulateMediaFeatures', function () { describe('Page.emulateMediaFeatures', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'prefers-reduced-motion', value: 'reduce' }, {name: 'prefers-reduced-motion', value: 'reduce'},
]); ]);
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -257,7 +257,7 @@ describe('Emulation', () => {
}) })
).toBe(false); ).toBe(false);
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'prefers-color-scheme', value: 'light' }, {name: 'prefers-color-scheme', value: 'light'},
]); ]);
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -270,7 +270,7 @@ describe('Emulation', () => {
}) })
).toBe(false); ).toBe(false);
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'prefers-color-scheme', value: 'dark' }, {name: 'prefers-color-scheme', value: 'dark'},
]); ]);
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -283,8 +283,8 @@ describe('Emulation', () => {
}) })
).toBe(false); ).toBe(false);
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'prefers-reduced-motion', value: 'reduce' }, {name: 'prefers-reduced-motion', value: 'reduce'},
{ name: 'prefers-color-scheme', value: 'light' }, {name: 'prefers-color-scheme', value: 'light'},
]); ]);
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -306,7 +306,7 @@ describe('Emulation', () => {
return matchMedia('(prefers-color-scheme: dark)').matches; return matchMedia('(prefers-color-scheme: dark)').matches;
}) })
).toBe(false); ).toBe(false);
await page.emulateMediaFeatures([{ name: 'color-gamut', value: 'srgb' }]); await page.emulateMediaFeatures([{name: 'color-gamut', value: 'srgb'}]);
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return matchMedia('(color-gamut: p3)').matches; return matchMedia('(color-gamut: p3)').matches;
@ -322,7 +322,7 @@ describe('Emulation', () => {
return matchMedia('(color-gamut: rec2020)').matches; return matchMedia('(color-gamut: rec2020)').matches;
}) })
).toBe(false); ).toBe(false);
await page.emulateMediaFeatures([{ name: 'color-gamut', value: 'p3' }]); await page.emulateMediaFeatures([{name: 'color-gamut', value: 'p3'}]);
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return matchMedia('(color-gamut: p3)').matches; return matchMedia('(color-gamut: p3)').matches;
@ -339,7 +339,7 @@ describe('Emulation', () => {
}) })
).toBe(false); ).toBe(false);
await page.emulateMediaFeatures([ await page.emulateMediaFeatures([
{ name: 'color-gamut', value: 'rec2020' }, {name: 'color-gamut', value: 'rec2020'},
]); ]);
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -358,12 +358,12 @@ describe('Emulation', () => {
).toBe(true); ).toBe(true);
}); });
it('should throw in case of bad argument', async () => { it('should throw in case of bad argument', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page
.emulateMediaFeatures([{ name: 'bad', value: '' }]) .emulateMediaFeatures([{name: 'bad', value: ''}])
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe('Unsupported media feature: bad'); expect(error.message).toBe('Unsupported media feature: bad');
@ -372,7 +372,7 @@ describe('Emulation', () => {
describeFailsFirefox('Page.emulateTimezone', function () { describeFailsFirefox('Page.emulateTimezone', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
(globalThis as any).date = new Date(1479579154987); (globalThis as any).date = new Date(1479579154987);
@ -411,14 +411,14 @@ describe('Emulation', () => {
}); });
it('should throw for invalid timezone IDs', async () => { it('should throw for invalid timezone IDs', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page.emulateTimezone('Foo/Bar').catch((error_) => { await page.emulateTimezone('Foo/Bar').catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe('Invalid timezone ID: Foo/Bar'); expect(error.message).toBe('Invalid timezone ID: Foo/Bar');
await page.emulateTimezone('Baz/Qux').catch((error_) => { await page.emulateTimezone('Baz/Qux').catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe('Invalid timezone ID: Baz/Qux'); expect(error.message).toBe('Invalid timezone ID: Baz/Qux');
@ -427,9 +427,9 @@ describe('Emulation', () => {
describeFailsFirefox('Page.emulateVisionDeficiency', function () { describeFailsFirefox('Page.emulateVisionDeficiency', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.setViewport({ width: 500, height: 500 }); await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
{ {
@ -476,13 +476,13 @@ describe('Emulation', () => {
}); });
it('should throw for invalid vision deficiencies', async () => { it('should throw for invalid vision deficiencies', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page
// @ts-expect-error deliberately passign invalid deficiency // @ts-expect-error deliberately passign invalid deficiency
.emulateVisionDeficiency('invalid') .emulateVisionDeficiency('invalid')
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe('Unsupported vision deficiency: invalid'); expect(error.message).toBe('Unsupported vision deficiency: invalid');
@ -491,7 +491,7 @@ describe('Emulation', () => {
describeFailsFirefox('Page.emulateNetworkConditions', function () { describeFailsFirefox('Page.emulateNetworkConditions', function () {
it('should change navigator.connection.effectiveType', async () => { it('should change navigator.connection.effectiveType', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
const slow3G = puppeteer.networkConditions['Slow 3G']!; const slow3G = puppeteer.networkConditions['Slow 3G']!;
const fast3G = puppeteer.networkConditions['Fast 3G']!; const fast3G = puppeteer.networkConditions['Fast 3G']!;
@ -513,7 +513,7 @@ describe('Emulation', () => {
describeFailsFirefox('Page.emulateCPUThrottling', function () { describeFailsFirefox('Page.emulateCPUThrottling', function () {
it('should change the CPU throttling rate successfully', async () => { it('should change the CPU throttling rate successfully', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.emulateCPUThrottling(100); await page.emulateCPUThrottling(100);
await page.emulateCPUThrottling(null); await page.emulateCPUThrottling(null);

View File

@ -32,7 +32,7 @@ describe('Evaluation specs', function () {
describe('Page.evaluate', function () { describe('Page.evaluate', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
return 7 * 3; return 7 * 3;
@ -40,7 +40,7 @@ describe('Evaluation specs', function () {
expect(result).toBe(21); expect(result).toBe(21);
}); });
(bigint ? it : xit)('should transfer BigInt', async () => { (bigint ? it : xit)('should transfer BigInt', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate((a: bigint) => { const result = await page.evaluate((a: bigint) => {
return a; return a;
@ -48,42 +48,42 @@ describe('Evaluation specs', function () {
expect(result).toBe(BigInt(42)); expect(result).toBe(BigInt(42));
}); });
it('should transfer NaN', async () => { it('should transfer NaN', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate((a) => { const result = await page.evaluate(a => {
return a; return a;
}, NaN); }, NaN);
expect(Object.is(result, NaN)).toBe(true); expect(Object.is(result, NaN)).toBe(true);
}); });
it('should transfer -0', async () => { it('should transfer -0', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate((a) => { const result = await page.evaluate(a => {
return a; return a;
}, -0); }, -0);
expect(Object.is(result, -0)).toBe(true); expect(Object.is(result, -0)).toBe(true);
}); });
it('should transfer Infinity', async () => { it('should transfer Infinity', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate((a) => { const result = await page.evaluate(a => {
return a; return a;
}, Infinity); }, Infinity);
expect(Object.is(result, Infinity)).toBe(true); expect(Object.is(result, Infinity)).toBe(true);
}); });
it('should transfer -Infinity', async () => { it('should transfer -Infinity', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate((a) => { const result = await page.evaluate(a => {
return a; return a;
}, -Infinity); }, -Infinity);
expect(Object.is(result, -Infinity)).toBe(true); expect(Object.is(result, -Infinity)).toBe(true);
}); });
it('should transfer arrays', async () => { it('should transfer arrays', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate( const result = await page.evaluate(
(a) => { a => {
return a; return a;
}, },
[1, 2, 3] [1, 2, 3]
@ -91,10 +91,10 @@ describe('Evaluation specs', function () {
expect(result).toEqual([1, 2, 3]); expect(result).toEqual([1, 2, 3]);
}); });
it('should transfer arrays as arrays, not objects', async () => { it('should transfer arrays as arrays, not objects', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate( const result = await page.evaluate(
(a) => { a => {
return Array.isArray(a); return Array.isArray(a);
}, },
[1, 2, 3] [1, 2, 3]
@ -102,7 +102,7 @@ describe('Evaluation specs', function () {
expect(result).toBe(true); expect(result).toBe(true);
}); });
it('should modify global environment', async () => { it('should modify global environment', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
return ((globalThis as any).globalVar = 123); return ((globalThis as any).globalVar = 123);
@ -110,7 +110,7 @@ describe('Evaluation specs', function () {
expect(await page.evaluate('globalVar')).toBe(123); expect(await page.evaluate('globalVar')).toBe(123);
}); });
it('should evaluate in the page context', async () => { it('should evaluate in the page context', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/global-var.html'); await page.goto(server.PREFIX + '/global-var.html');
expect(await page.evaluate('globalVar')).toBe(123); expect(await page.evaluate('globalVar')).toBe(123);
@ -118,7 +118,7 @@ describe('Evaluation specs', function () {
itFailsFirefox( itFailsFirefox(
'should return undefined for objects with symbols', 'should return undefined for objects with symbols',
async () => { async () => {
const { page } = getTestState(); const {page} = getTestState();
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -128,7 +128,7 @@ describe('Evaluation specs', function () {
} }
); );
it('should work with function shorthands', async () => { it('should work with function shorthands', async () => {
const { page } = getTestState(); const {page} = getTestState();
const a = { const a = {
sum(a: number, b: number) { sum(a: number, b: number) {
@ -143,10 +143,10 @@ describe('Evaluation specs', function () {
expect(await page.evaluate(a.mult, 2, 4)).toBe(8); expect(await page.evaluate(a.mult, 2, 4)).toBe(8);
}); });
it('should work with unicode chars', async () => { it('should work with unicode chars', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate( const result = await page.evaluate(
(a) => { a => {
return a['中文字符']; return a['中文字符'];
}, },
{ {
@ -156,7 +156,7 @@ describe('Evaluation specs', function () {
expect(result).toBe(42); expect(result).toBe(42);
}); });
itFailsFirefox('should throw when evaluation triggers reload', async () => { itFailsFirefox('should throw when evaluation triggers reload', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page
@ -164,13 +164,13 @@ describe('Evaluation specs', function () {
location.reload(); location.reload();
return new Promise(() => {}); return new Promise(() => {});
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('Protocol error'); expect(error.message).toContain('Protocol error');
}); });
it('should await promise', async () => { it('should await promise', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
return Promise.resolve(8 * 7); return Promise.resolve(8 * 7);
@ -178,10 +178,10 @@ describe('Evaluation specs', function () {
expect(result).toBe(56); expect(result).toBe(56);
}); });
it('should work right after framenavigated', async () => { it('should work right after framenavigated', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let frameEvaluation = null; let frameEvaluation = null;
page.on('framenavigated', async (frame) => { page.on('framenavigated', async frame => {
frameEvaluation = frame.evaluate(() => { frameEvaluation = frame.evaluate(() => {
return 6 * 7; return 6 * 7;
}); });
@ -190,7 +190,7 @@ describe('Evaluation specs', function () {
expect(await frameEvaluation).toBe(42); expect(await frameEvaluation).toBe(42);
}); });
itFailsFirefox('should work from-inside an exposed function', async () => { itFailsFirefox('should work from-inside an exposed function', async () => {
const { page } = getTestState(); const {page} = getTestState();
// Setup inpage callback, which calls Page.evaluate // Setup inpage callback, which calls Page.evaluate
await page.exposeFunction( await page.exposeFunction(
@ -211,7 +211,7 @@ describe('Evaluation specs', function () {
expect(result).toBe(27); expect(result).toBe(27);
}); });
it('should reject promise with exception', async () => { it('should reject promise with exception', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page
@ -219,52 +219,52 @@ describe('Evaluation specs', function () {
// @ts-expect-error we know the object doesn't exist // @ts-expect-error we know the object doesn't exist
return notExistingObject.property; return notExistingObject.property;
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeTruthy(); expect(error).toBeTruthy();
expect(error.message).toContain('notExistingObject'); expect(error.message).toContain('notExistingObject');
}); });
it('should support thrown strings as error messages', async () => { it('should support thrown strings as error messages', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page
.evaluate(() => { .evaluate(() => {
throw 'qwerty'; throw 'qwerty';
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeTruthy(); expect(error).toBeTruthy();
expect(error.message).toContain('qwerty'); expect(error.message).toContain('qwerty');
}); });
it('should support thrown numbers as error messages', async () => { it('should support thrown numbers as error messages', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page
.evaluate(() => { .evaluate(() => {
throw 100500; throw 100500;
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeTruthy(); expect(error).toBeTruthy();
expect(error.message).toContain('100500'); expect(error.message).toContain('100500');
}); });
it('should return complex objects', async () => { it('should return complex objects', async () => {
const { page } = getTestState(); const {page} = getTestState();
const object = { foo: 'bar!' }; const object = {foo: 'bar!'};
const result = await page.evaluate((a) => { const result = await page.evaluate(a => {
return a; return a;
}, object); }, object);
expect(result).not.toBe(object); expect(result).not.toBe(object);
expect(result).toEqual(object); expect(result).toEqual(object);
}); });
(bigint ? it : xit)('should return BigInt', async () => { (bigint ? it : xit)('should return BigInt', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
return BigInt(42); return BigInt(42);
@ -272,7 +272,7 @@ describe('Evaluation specs', function () {
expect(result).toBe(BigInt(42)); expect(result).toBe(BigInt(42));
}); });
it('should return NaN', async () => { it('should return NaN', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
return NaN; return NaN;
@ -280,7 +280,7 @@ describe('Evaluation specs', function () {
expect(Object.is(result, NaN)).toBe(true); expect(Object.is(result, NaN)).toBe(true);
}); });
it('should return -0', async () => { it('should return -0', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
return -0; return -0;
@ -288,7 +288,7 @@ describe('Evaluation specs', function () {
expect(Object.is(result, -0)).toBe(true); expect(Object.is(result, -0)).toBe(true);
}); });
it('should return Infinity', async () => { it('should return Infinity', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
return Infinity; return Infinity;
@ -296,7 +296,7 @@ describe('Evaluation specs', function () {
expect(Object.is(result, Infinity)).toBe(true); expect(Object.is(result, Infinity)).toBe(true);
}); });
it('should return -Infinity', async () => { it('should return -Infinity', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
return -Infinity; return -Infinity;
@ -304,7 +304,7 @@ describe('Evaluation specs', function () {
expect(Object.is(result, -Infinity)).toBe(true); expect(Object.is(result, -Infinity)).toBe(true);
}); });
it('should accept "null" as one of multiple parameters', async () => { it('should accept "null" as one of multiple parameters', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate( const result = await page.evaluate(
(a, b) => { (a, b) => {
@ -316,18 +316,18 @@ describe('Evaluation specs', function () {
expect(result).toBe(true); expect(result).toBe(true);
}); });
it('should properly serialize null fields', async () => { it('should properly serialize null fields', async () => {
const { page } = getTestState(); const {page} = getTestState();
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return { a: undefined }; return {a: undefined};
}) })
).toEqual({}); ).toEqual({});
}); });
itFailsFirefox( itFailsFirefox(
'should return undefined for non-serializable objects', 'should return undefined for non-serializable objects',
async () => { async () => {
const { page } = getTestState(); const {page} = getTestState();
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
@ -337,66 +337,64 @@ describe('Evaluation specs', function () {
} }
); );
itFailsFirefox('should fail for circular object', async () => { itFailsFirefox('should fail for circular object', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
const a: { [x: string]: any } = {}; const a: {[x: string]: any} = {};
const b = { a }; const b = {a};
a['b'] = b; a['b'] = b;
return a; return a;
}); });
expect(result).toBe(undefined); expect(result).toBe(undefined);
}); });
itFailsFirefox('should be able to throw a tricky error', async () => { itFailsFirefox('should be able to throw a tricky error', async () => {
const { page } = getTestState(); const {page} = getTestState();
const windowHandle = await page.evaluateHandle(() => { const windowHandle = await page.evaluateHandle(() => {
return window; return window;
}); });
const errorText = await windowHandle const errorText = await windowHandle.jsonValue<string>().catch(error_ => {
.jsonValue<string>() return error_.message;
.catch((error_) => { });
return error_.message;
});
const error = await page const error = await page
.evaluate<(errorText: string) => Error>((errorText) => { .evaluate<(errorText: string) => Error>(errorText => {
throw new Error(errorText); throw new Error(errorText);
}, errorText) }, errorText)
.catch((error_) => { .catch(error_ => {
return error_; return error_;
}); });
expect(error.message).toContain(errorText); expect(error.message).toContain(errorText);
}); });
it('should accept a string', async () => { it('should accept a string', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate('1 + 2'); const result = await page.evaluate('1 + 2');
expect(result).toBe(3); expect(result).toBe(3);
}); });
it('should accept a string with semi colons', async () => { it('should accept a string with semi colons', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate('1 + 5;'); const result = await page.evaluate('1 + 5;');
expect(result).toBe(6); expect(result).toBe(6);
}); });
it('should accept a string with comments', async () => { it('should accept a string with comments', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate('2 + 5;\n// do some math!'); const result = await page.evaluate('2 + 5;\n// do some math!');
expect(result).toBe(7); expect(result).toBe(7);
}); });
it('should accept element handle as an argument', async () => { it('should accept element handle as an argument', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent('<section>42</section>'); await page.setContent('<section>42</section>');
const element = (await page.$('section'))!; const element = (await page.$('section'))!;
const text = await page.evaluate((e) => { const text = await page.evaluate(e => {
return e.textContent; return e.textContent;
}, element); }, element);
expect(text).toBe('42'); expect(text).toBe('42');
}); });
it('should throw if underlying element was disposed', async () => { it('should throw if underlying element was disposed', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent('<section>39</section>'); await page.setContent('<section>39</section>');
const element = (await page.$('section'))!; const element = (await page.$('section'))!;
@ -407,7 +405,7 @@ describe('Evaluation specs', function () {
.evaluate((e: HTMLElement) => { .evaluate((e: HTMLElement) => {
return e.textContent; return e.textContent;
}, element) }, element)
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('JSHandle is disposed'); expect(error.message).toContain('JSHandle is disposed');
@ -415,7 +413,7 @@ describe('Evaluation specs', function () {
itFailsFirefox( itFailsFirefox(
'should throw if elementHandles are from other frames', 'should throw if elementHandles are from other frames',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
const bodyHandle = await page.frames()[1]!.$('body'); const bodyHandle = await page.frames()[1]!.$('body');
@ -424,7 +422,7 @@ describe('Evaluation specs', function () {
.evaluate((body: HTMLElement) => { .evaluate((body: HTMLElement) => {
return body.innerHTML; return body.innerHTML;
}, bodyHandle) }, bodyHandle)
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeTruthy(); expect(error).toBeTruthy();
@ -434,7 +432,7 @@ describe('Evaluation specs', function () {
} }
); );
itFailsFirefox('should simulate a user gesture', async () => { itFailsFirefox('should simulate a user gesture', async () => {
const { page } = getTestState(); const {page} = getTestState();
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
document.body.appendChild(document.createTextNode('test')); document.body.appendChild(document.createTextNode('test'));
@ -444,7 +442,7 @@ describe('Evaluation specs', function () {
expect(result).toBe(true); expect(result).toBe(true);
}); });
itFailsFirefox('should throw a nice error after a navigation', async () => { itFailsFirefox('should throw a nice error after a navigation', async () => {
const { page } = getTestState(); const {page} = getTestState();
const executionContext = await page.mainFrame().executionContext(); const executionContext = await page.mainFrame().executionContext();
@ -458,7 +456,7 @@ describe('Evaluation specs', function () {
.evaluate(() => { .evaluate(() => {
return null; return null;
}) })
.catch((error_) => { .catch(error_ => {
return error_; return error_;
}); });
expect((error as Error).message).toContain('navigation'); expect((error as Error).message).toContain('navigation');
@ -466,7 +464,7 @@ describe('Evaluation specs', function () {
itFailsFirefox( itFailsFirefox(
'should not throw an error when evaluation does a navigation', 'should not throw an error when evaluation does a navigation',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/one-style.html'); await page.goto(server.PREFIX + '/one-style.html');
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
@ -477,7 +475,7 @@ describe('Evaluation specs', function () {
} }
); );
it('should transfer 100Mb of data from page to node.js', async function () { it('should transfer 100Mb of data from page to node.js', async function () {
const { page } = getTestState(); const {page} = getTestState();
const a = await page.evaluate<() => string>(() => { const a = await page.evaluate<() => string>(() => {
return Array(100 * 1024 * 1024 + 1).join('a'); return Array(100 * 1024 * 1024 + 1).join('a');
@ -485,7 +483,7 @@ describe('Evaluation specs', function () {
expect(a.length).toBe(100 * 1024 * 1024); expect(a.length).toBe(100 * 1024 * 1024);
}); });
it('should throw error with detailed information on exception inside promise ', async () => { it('should throw error with detailed information on exception inside promise ', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error!: Error; let error!: Error;
await page await page
@ -494,7 +492,7 @@ describe('Evaluation specs', function () {
throw new Error('Error in promise'); throw new Error('Error in promise');
}); });
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('Error in promise'); expect(error.message).toContain('Error in promise');
@ -503,7 +501,7 @@ describe('Evaluation specs', function () {
describeFailsFirefox('Page.evaluateOnNewDocument', function () { describeFailsFirefox('Page.evaluateOnNewDocument', function () {
it('should evaluate before anything else on the page', async () => { it('should evaluate before anything else on the page', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.evaluateOnNewDocument(function () { await page.evaluateOnNewDocument(function () {
(globalThis as any).injected = 123; (globalThis as any).injected = 123;
@ -516,7 +514,7 @@ describe('Evaluation specs', function () {
).toBe(123); ).toBe(123);
}); });
it('should work with CSP', async () => { it('should work with CSP', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setCSP('/empty.html', 'script-src ' + server.PREFIX); server.setCSP('/empty.html', 'script-src ' + server.PREFIX);
await page.evaluateOnNewDocument(function () { await page.evaluateOnNewDocument(function () {
@ -530,7 +528,7 @@ describe('Evaluation specs', function () {
).toBe(123); ).toBe(123);
// Make sure CSP works. // Make sure CSP works.
await page.addScriptTag({ content: 'window.e = 10;' }).catch((error) => { await page.addScriptTag({content: 'window.e = 10;'}).catch(error => {
return void error; return void error;
}); });
expect( expect(
@ -543,7 +541,7 @@ describe('Evaluation specs', function () {
describe('Frame.evaluate', function () { describe('Frame.evaluate', function () {
it('should have different execution contexts', async () => { it('should have different execution contexts', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
@ -566,7 +564,7 @@ describe('Evaluation specs', function () {
).toBe('bar'); ).toBe('bar');
}); });
it('should have correct execution contexts', async () => { it('should have correct execution contexts', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/frames/one-frame.html'); await page.goto(server.PREFIX + '/frames/one-frame.html');
expect(page.frames().length).toBe(2); expect(page.frames().length).toBe(2);
@ -582,7 +580,7 @@ describe('Evaluation specs', function () {
).toBe(`Hi, I'm frame`); ).toBe(`Hi, I'm frame`);
}); });
it('should execute after cross-site navigation', async () => { it('should execute after cross-site navigation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const mainFrame = page.mainFrame(); const mainFrame = page.mainFrame();

View File

@ -17,16 +17,16 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
import expect from 'expect'; import expect from 'expect';
import { getTestState, itHeadlessOnly } from './mocha-utils.js'; import {getTestState, itHeadlessOnly} from './mocha-utils.js';
import path from 'path'; import path from 'path';
describe('Fixtures', function () { describe('Fixtures', function () {
itHeadlessOnly('dumpio option should work with pipe option ', async () => { itHeadlessOnly('dumpio option should work with pipe option ', async () => {
const { defaultBrowserOptions, puppeteerPath } = getTestState(); const {defaultBrowserOptions, puppeteerPath} = getTestState();
let dumpioData = ''; let dumpioData = '';
const { spawn } = await import('child_process'); const {spawn} = await import('child_process');
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
pipe: true, pipe: true,
dumpio: true, dumpio: true,
@ -36,37 +36,37 @@ describe('Fixtures', function () {
puppeteerPath, puppeteerPath,
JSON.stringify(options), JSON.stringify(options),
]); ]);
res.stderr.on('data', (data) => { res.stderr.on('data', data => {
return (dumpioData += data.toString('utf8')); return (dumpioData += data.toString('utf8'));
}); });
await new Promise((resolve) => { await new Promise(resolve => {
return res.on('close', resolve); return res.on('close', resolve);
}); });
expect(dumpioData).toContain('message from dumpio'); expect(dumpioData).toContain('message from dumpio');
}); });
it('should dump browser process stderr', async () => { it('should dump browser process stderr', async () => {
const { defaultBrowserOptions, puppeteerPath } = getTestState(); const {defaultBrowserOptions, puppeteerPath} = getTestState();
let dumpioData = ''; let dumpioData = '';
const { spawn } = await import('child_process'); const {spawn} = await import('child_process');
const options = Object.assign({}, defaultBrowserOptions, { dumpio: true }); const options = Object.assign({}, defaultBrowserOptions, {dumpio: true});
const res = spawn('node', [ const res = spawn('node', [
path.join(__dirname, '../fixtures', 'dumpio.js'), path.join(__dirname, '../fixtures', 'dumpio.js'),
puppeteerPath, puppeteerPath,
JSON.stringify(options), JSON.stringify(options),
]); ]);
res.stderr.on('data', (data) => { res.stderr.on('data', data => {
return (dumpioData += data.toString('utf8')); return (dumpioData += data.toString('utf8'));
}); });
await new Promise((resolve) => { await new Promise(resolve => {
return res.on('close', resolve); return res.on('close', resolve);
}); });
expect(dumpioData).toContain('DevTools listening on ws://'); expect(dumpioData).toContain('DevTools listening on ws://');
}); });
it('should close the browser when the node process closes', async () => { it('should close the browser when the node process closes', async () => {
const { defaultBrowserOptions, puppeteerPath, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteerPath, puppeteer} = getTestState();
const { spawn, execSync } = await import('child_process'); const {spawn, execSync} = await import('child_process');
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
// Disable DUMPIO to cleanly read stdout. // Disable DUMPIO to cleanly read stdout.
dumpio: false, dumpio: false,
@ -77,11 +77,11 @@ describe('Fixtures', function () {
JSON.stringify(options), JSON.stringify(options),
]); ]);
let wsEndPointCallback: (value: string) => void; let wsEndPointCallback: (value: string) => void;
const wsEndPointPromise = new Promise<string>((x) => { const wsEndPointPromise = new Promise<string>(x => {
return (wsEndPointCallback = x); return (wsEndPointCallback = x);
}); });
let output = ''; let output = '';
res.stdout.on('data', (data) => { res.stdout.on('data', data => {
output += data; output += data;
if (output.indexOf('\n')) { if (output.indexOf('\n')) {
wsEndPointCallback(output.substring(0, output.indexOf('\n'))); wsEndPointCallback(output.substring(0, output.indexOf('\n')));
@ -91,10 +91,10 @@ describe('Fixtures', function () {
browserWSEndpoint: await wsEndPointPromise, browserWSEndpoint: await wsEndPointPromise,
}); });
const promises = [ const promises = [
new Promise((resolve) => { new Promise(resolve => {
return browser.once('disconnected', resolve); return browser.once('disconnected', resolve);
}), }),
new Promise((resolve) => { new Promise(resolve => {
return res.on('close', resolve); return res.on('close', resolve);
}), }),
]; ];

View File

@ -15,15 +15,15 @@
*/ */
import expect from 'expect'; import expect from 'expect';
import { CDPSession } from '../../lib/cjs/puppeteer/common/Connection.js'; import {CDPSession} from '../../lib/cjs/puppeteer/common/Connection.js';
import { Frame } from '../../lib/cjs/puppeteer/common/FrameManager.js'; import {Frame} from '../../lib/cjs/puppeteer/common/FrameManager.js';
import { import {
getTestState, getTestState,
itFailsFirefox, itFailsFirefox,
setupTestBrowserHooks, setupTestBrowserHooks,
setupTestPageAndContextHooks, setupTestPageAndContextHooks,
} from './mocha-utils.js'; } from './mocha-utils.js';
import utils, { dumpFrames } from './utils.js'; import utils, {dumpFrames} from './utils.js';
describe('Frame specs', function () { describe('Frame specs', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
@ -31,7 +31,7 @@ describe('Frame specs', function () {
describe('Frame.executionContext', function () { describe('Frame.executionContext', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
@ -68,7 +68,7 @@ describe('Frame specs', function () {
describe('Frame.evaluateHandle', function () { describe('Frame.evaluateHandle', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const mainFrame = page.mainFrame(); const mainFrame = page.mainFrame();
@ -81,7 +81,7 @@ describe('Frame specs', function () {
describe('Frame.evaluate', function () { describe('Frame.evaluate', function () {
itFailsFirefox('should throw for detached frames', async () => { itFailsFirefox('should throw for detached frames', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const frame1 = (await utils.attachFrame( const frame1 = (await utils.attachFrame(
page, page,
@ -94,7 +94,7 @@ describe('Frame specs', function () {
.evaluate(() => { .evaluate(() => {
return 7 * 8; return 7 * 8;
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain( expect(error.message).toContain(
@ -103,14 +103,14 @@ describe('Frame specs', function () {
}); });
it('allows readonly array to be an argument', async () => { it('allows readonly array to be an argument', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const mainFrame = page.mainFrame(); const mainFrame = page.mainFrame();
// This test checks if Frame.evaluate allows a readonly array to be an argument. // This test checks if Frame.evaluate allows a readonly array to be an argument.
// See https://github.com/puppeteer/puppeteer/issues/6953. // See https://github.com/puppeteer/puppeteer/issues/6953.
const readonlyArray: readonly string[] = ['a', 'b', 'c']; const readonlyArray: readonly string[] = ['a', 'b', 'c'];
await mainFrame.evaluate((arr) => { await mainFrame.evaluate(arr => {
return arr; return arr;
}, readonlyArray); }, readonlyArray);
}); });
@ -118,7 +118,7 @@ describe('Frame specs', function () {
describe('Frame Management', function () { describe('Frame Management', function () {
itFailsFirefox('should handle nested frames', async () => { itFailsFirefox('should handle nested frames', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/frames/nested-frames.html'); await page.goto(server.PREFIX + '/frames/nested-frames.html');
expect(dumpFrames(page.mainFrame())).toEqual([ expect(dumpFrames(page.mainFrame())).toEqual([
@ -132,12 +132,12 @@ describe('Frame specs', function () {
itFailsFirefox( itFailsFirefox(
'should send events when frames are manipulated dynamically', 'should send events when frames are manipulated dynamically',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
// validate frameattached events // validate frameattached events
const attachedFrames: Frame[] = []; const attachedFrames: Frame[] = [];
page.on('frameattached', (frame) => { page.on('frameattached', frame => {
return attachedFrames.push(frame); return attachedFrames.push(frame);
}); });
await utils.attachFrame(page, 'frame1', './assets/frame.html'); await utils.attachFrame(page, 'frame1', './assets/frame.html');
@ -146,7 +146,7 @@ describe('Frame specs', function () {
// validate framenavigated events // validate framenavigated events
const navigatedFrames: Frame[] = []; const navigatedFrames: Frame[] = [];
page.on('framenavigated', (frame) => { page.on('framenavigated', frame => {
return navigatedFrames.push(frame); return navigatedFrames.push(frame);
}); });
await utils.navigateFrame(page, 'frame1', './empty.html'); await utils.navigateFrame(page, 'frame1', './empty.html');
@ -155,7 +155,7 @@ describe('Frame specs', function () {
// validate framedetached events // validate framedetached events
const detachedFrames: Frame[] = []; const detachedFrames: Frame[] = [];
page.on('framedetached', (frame) => { page.on('framedetached', frame => {
return detachedFrames.push(frame); return detachedFrames.push(frame);
}); });
await utils.detachFrame(page, 'frame1'); await utils.detachFrame(page, 'frame1');
@ -164,7 +164,7 @@ describe('Frame specs', function () {
} }
); );
it('should send "framenavigated" when navigating on anchor URLs', async () => { it('should send "framenavigated" when navigating on anchor URLs', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await Promise.all([ await Promise.all([
@ -174,7 +174,7 @@ describe('Frame specs', function () {
expect(page.url()).toBe(server.EMPTY_PAGE + '#foo'); expect(page.url()).toBe(server.EMPTY_PAGE + '#foo');
}); });
it('should persist mainFrame on cross-process navigation', async () => { it('should persist mainFrame on cross-process navigation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const mainFrame = page.mainFrame(); const mainFrame = page.mainFrame();
@ -182,7 +182,7 @@ describe('Frame specs', function () {
expect(page.mainFrame() === mainFrame).toBeTruthy(); expect(page.mainFrame() === mainFrame).toBeTruthy();
}); });
it('should not send attach/detach events for main frame', async () => { it('should not send attach/detach events for main frame', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let hasEvents = false; let hasEvents = false;
page.on('frameattached', () => { page.on('frameattached', () => {
@ -195,18 +195,18 @@ describe('Frame specs', function () {
expect(hasEvents).toBe(false); expect(hasEvents).toBe(false);
}); });
it('should detach child frames on navigation', async () => { it('should detach child frames on navigation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let attachedFrames = []; let attachedFrames = [];
let detachedFrames = []; let detachedFrames = [];
let navigatedFrames = []; let navigatedFrames = [];
page.on('frameattached', (frame) => { page.on('frameattached', frame => {
return attachedFrames.push(frame); return attachedFrames.push(frame);
}); });
page.on('framedetached', (frame) => { page.on('framedetached', frame => {
return detachedFrames.push(frame); return detachedFrames.push(frame);
}); });
page.on('framenavigated', (frame) => { page.on('framenavigated', frame => {
return navigatedFrames.push(frame); return navigatedFrames.push(frame);
}); });
await page.goto(server.PREFIX + '/frames/nested-frames.html'); await page.goto(server.PREFIX + '/frames/nested-frames.html');
@ -223,18 +223,18 @@ describe('Frame specs', function () {
expect(navigatedFrames.length).toBe(1); expect(navigatedFrames.length).toBe(1);
}); });
it('should support framesets', async () => { it('should support framesets', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let attachedFrames = []; let attachedFrames = [];
let detachedFrames = []; let detachedFrames = [];
let navigatedFrames = []; let navigatedFrames = [];
page.on('frameattached', (frame) => { page.on('frameattached', frame => {
return attachedFrames.push(frame); return attachedFrames.push(frame);
}); });
page.on('framedetached', (frame) => { page.on('framedetached', frame => {
return detachedFrames.push(frame); return detachedFrames.push(frame);
}); });
page.on('framenavigated', (frame) => { page.on('framenavigated', frame => {
return navigatedFrames.push(frame); return navigatedFrames.push(frame);
}); });
await page.goto(server.PREFIX + '/frames/frameset.html'); await page.goto(server.PREFIX + '/frames/frameset.html');
@ -251,14 +251,14 @@ describe('Frame specs', function () {
expect(navigatedFrames.length).toBe(1); expect(navigatedFrames.length).toBe(1);
}); });
itFailsFirefox('should report frame from-inside shadow DOM', async () => { itFailsFirefox('should report frame from-inside shadow DOM', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/shadow.html'); await page.goto(server.PREFIX + '/shadow.html');
await page.evaluate(async (url: string) => { await page.evaluate(async (url: string) => {
const frame = document.createElement('iframe'); const frame = document.createElement('iframe');
frame.src = url; frame.src = url;
document.body.shadowRoot!.appendChild(frame); document.body.shadowRoot!.appendChild(frame);
await new Promise((x) => { await new Promise(x => {
return (frame.onload = x); return (frame.onload = x);
}); });
}, server.EMPTY_PAGE); }, server.EMPTY_PAGE);
@ -266,7 +266,7 @@ describe('Frame specs', function () {
expect(page.frames()[1]!.url()).toBe(server.EMPTY_PAGE); expect(page.frames()[1]!.url()).toBe(server.EMPTY_PAGE);
}); });
itFailsFirefox('should report frame.name()', async () => { itFailsFirefox('should report frame.name()', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await utils.attachFrame(page, 'theFrameId', server.EMPTY_PAGE); await utils.attachFrame(page, 'theFrameId', server.EMPTY_PAGE);
await page.evaluate((url: string) => { await page.evaluate((url: string) => {
@ -274,7 +274,7 @@ describe('Frame specs', function () {
frame.name = 'theFrameName'; frame.name = 'theFrameName';
frame.src = url; frame.src = url;
document.body.appendChild(frame); document.body.appendChild(frame);
return new Promise((x) => { return new Promise(x => {
return (frame.onload = x); return (frame.onload = x);
}); });
}, server.EMPTY_PAGE); }, server.EMPTY_PAGE);
@ -283,7 +283,7 @@ describe('Frame specs', function () {
expect(page.frames()[2]!.name()).toBe('theFrameName'); expect(page.frames()[2]!.name()).toBe('theFrameName');
}); });
itFailsFirefox('should report frame.parent()', async () => { itFailsFirefox('should report frame.parent()', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE);
@ -294,7 +294,7 @@ describe('Frame specs', function () {
itFailsFirefox( itFailsFirefox(
'should report different frame instance when frame re-attaches', 'should report different frame instance when frame re-attaches',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const frame1 = await utils.attachFrame( const frame1 = await utils.attachFrame(
page, page,
@ -317,7 +317,7 @@ describe('Frame specs', function () {
} }
); );
it('should support url fragment', async () => { it('should support url fragment', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/frames/one-frame-url-fragment.html'); await page.goto(server.PREFIX + '/frames/one-frame-url-fragment.html');
@ -327,13 +327,13 @@ describe('Frame specs', function () {
); );
}); });
itFailsFirefox('should support lazy frames', async () => { itFailsFirefox('should support lazy frames', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.setViewport({ width: 1000, height: 1000 }); await page.setViewport({width: 1000, height: 1000});
await page.goto(server.PREFIX + '/frames/lazy-frame.html'); await page.goto(server.PREFIX + '/frames/lazy-frame.html');
expect( expect(
page.frames().map((frame) => { page.frames().map(frame => {
return frame._hasStartedLoading; return frame._hasStartedLoading;
}) })
).toEqual([true, true, false]); ).toEqual([true, true, false]);
@ -342,7 +342,7 @@ describe('Frame specs', function () {
describe('Frame.client', function () { describe('Frame.client', function () {
it('should return the client instance', async () => { it('should return the client instance', async () => {
const { page } = getTestState(); const {page} = getTestState();
expect(page.mainFrame()._client()).toBeInstanceOf(CDPSession); expect(page.mainFrame()._client()).toBeInstanceOf(CDPSession);
}); });
}); });

View File

@ -20,7 +20,7 @@ import jpeg from 'jpeg-js';
import mime from 'mime'; import mime from 'mime';
import path from 'path'; import path from 'path';
import pixelmatch from 'pixelmatch'; import pixelmatch from 'pixelmatch';
import { PNG } from 'pngjs'; import {PNG} from 'pngjs';
interface DiffFile { interface DiffFile {
diff: string | Buffer; diff: string | Buffer;
@ -69,16 +69,16 @@ const compareImages = (
`Sizes differ: expected image ${expected.width}px X ${expected.height}px, but got ${actual.width}px X ${actual.height}px.` `Sizes differ: expected image ${expected.width}px X ${expected.height}px, but got ${actual.width}px X ${actual.height}px.`
); );
} }
const diff = new PNG({ width: expected.width, height: expected.height }); const diff = new PNG({width: expected.width, height: expected.height});
const count = pixelmatch( const count = pixelmatch(
expected.data, expected.data,
actual.data, actual.data,
diff.data, diff.data,
expected.width, expected.width,
expected.height, expected.height,
{ threshold: 0.1 } {threshold: 0.1}
); );
return count > 0 ? { diff: PNG.sync.write(diff) } : undefined; return count > 0 ? {diff: PNG.sync.write(diff)} : undefined;
}; };
const compareText = ( const compareText = (
@ -114,7 +114,7 @@ export const compare = (
outputPath: string, outputPath: string,
actual: string | Buffer, actual: string | Buffer,
goldenName: string goldenName: string
): { pass: true } | { pass: false; message: string } => { ): {pass: true} | {pass: false; message: string} => {
goldenPath = path.normalize(goldenPath); goldenPath = path.normalize(goldenPath);
outputPath = path.normalize(outputPath); outputPath = path.normalize(outputPath);
const expectedPath = path.join(goldenPath, goldenName); const expectedPath = path.join(goldenPath, goldenName);
@ -144,7 +144,7 @@ export const compare = (
} }
const result = comparator(actual, expected, mimeType); const result = comparator(actual, expected, mimeType);
if (!result) { if (!result) {
return { pass: true }; return {pass: true};
} }
ensureOutputDir(); ensureOutputDir();
if (goldenPath === outputPath) { if (goldenPath === outputPath) {

View File

@ -19,7 +19,7 @@ import fs from 'fs';
import os from 'os'; import os from 'os';
import path from 'path'; import path from 'path';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import { promisify } from 'util'; import {promisify} from 'util';
import { import {
PuppeteerLaunchOptions, PuppeteerLaunchOptions,
PuppeteerNode, PuppeteerNode,
@ -44,7 +44,7 @@ describeChromeOnly('headful tests', function () {
this.timeout(20 * 1000); this.timeout(20 * 1000);
let headfulOptions: PuppeteerLaunchOptions | undefined; let headfulOptions: PuppeteerLaunchOptions | undefined;
let headlessOptions: PuppeteerLaunchOptions & { headless: boolean }; let headlessOptions: PuppeteerLaunchOptions & {headless: boolean};
let extensionOptions: PuppeteerLaunchOptions & { let extensionOptions: PuppeteerLaunchOptions & {
headless: boolean; headless: boolean;
args: string[]; args: string[];
@ -61,7 +61,7 @@ describeChromeOnly('headful tests', function () {
const browsers: any[] = []; const browsers: any[] = [];
beforeEach(() => { beforeEach(() => {
const { server, defaultBrowserOptions } = getTestState(); const {server, defaultBrowserOptions} = getTestState();
headfulOptions = Object.assign({}, defaultBrowserOptions, { headfulOptions = Object.assign({}, defaultBrowserOptions, {
headless: false, headless: false,
}); });
@ -113,14 +113,14 @@ describeChromeOnly('headful tests', function () {
describe('HEADFUL', function () { describe('HEADFUL', function () {
it('background_page target type should be available', async () => { it('background_page target type should be available', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const browserWithExtension = await launchBrowser( const browserWithExtension = await launchBrowser(
puppeteer, puppeteer,
extensionOptions extensionOptions
); );
const page = await browserWithExtension.newPage(); const page = await browserWithExtension.newPage();
const backgroundPageTarget = await browserWithExtension.waitForTarget( const backgroundPageTarget = await browserWithExtension.waitForTarget(
(target: { type: () => string }) => { (target: {type: () => string}) => {
return target.type() === 'background_page'; return target.type() === 'background_page';
} }
); );
@ -129,13 +129,13 @@ describeChromeOnly('headful tests', function () {
expect(backgroundPageTarget).toBeTruthy(); expect(backgroundPageTarget).toBeTruthy();
}); });
it('target.page() should return a background_page', async function () { it('target.page() should return a background_page', async function () {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const browserWithExtension = await launchBrowser( const browserWithExtension = await launchBrowser(
puppeteer, puppeteer,
extensionOptions extensionOptions
); );
const backgroundPageTarget = await browserWithExtension.waitForTarget( const backgroundPageTarget = await browserWithExtension.waitForTarget(
(target: { type: () => string }) => { (target: {type: () => string}) => {
return target.type() === 'background_page'; return target.type() === 'background_page';
} }
); );
@ -153,7 +153,7 @@ describeChromeOnly('headful tests', function () {
await browserWithExtension.close(); await browserWithExtension.close();
}); });
it('target.page() should return a DevTools page if custom isPageTarget is provided', async function () { it('target.page() should return a DevTools page if custom isPageTarget is provided', async function () {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const originalBrowser = await launchBrowser(puppeteer, devtoolsOptions); const originalBrowser = await launchBrowser(puppeteer, devtoolsOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
@ -166,7 +166,7 @@ describeChromeOnly('headful tests', function () {
); );
}, },
}); });
const devtoolsPageTarget = await browser.waitForTarget((target) => { const devtoolsPageTarget = await browser.waitForTarget(target => {
return target.type() === 'other'; return target.type() === 'other';
}); });
const page = (await devtoolsPageTarget.page())!; const page = (await devtoolsPageTarget.page())!;
@ -179,9 +179,9 @@ describeChromeOnly('headful tests', function () {
await browser.close(); await browser.close();
}); });
it('should have default url when launching browser', async function () { it('should have default url when launching browser', async function () {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const browser = await launchBrowser(puppeteer, extensionOptions); const browser = await launchBrowser(puppeteer, extensionOptions);
const pages = (await browser.pages()).map((page: { url: () => any }) => { const pages = (await browser.pages()).map((page: {url: () => any}) => {
return page.url(); return page.url();
}); });
expect(pages).toEqual(['about:blank']); expect(pages).toEqual(['about:blank']);
@ -191,13 +191,13 @@ describeChromeOnly('headful tests', function () {
'headless should be able to read cookies written by headful', 'headless should be able to read cookies written by headful',
async () => { async () => {
/* Needs investigation into why but this fails consistently on Windows CI. */ /* Needs investigation into why but this fails consistently on Windows CI. */
const { server, puppeteer } = getTestState(); const {server, puppeteer} = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER); const userDataDir = await mkdtempAsync(TMP_FOLDER);
// Write a cookie in headful chrome // Write a cookie in headful chrome
const headfulBrowser = await launchBrowser( const headfulBrowser = await launchBrowser(
puppeteer, puppeteer,
Object.assign({ userDataDir }, headfulOptions) Object.assign({userDataDir}, headfulOptions)
); );
const headfulPage = await headfulBrowser.newPage(); const headfulPage = await headfulBrowser.newPage();
await headfulPage.goto(server.EMPTY_PAGE); await headfulPage.goto(server.EMPTY_PAGE);
@ -209,7 +209,7 @@ describeChromeOnly('headful tests', function () {
// Read the cookie from headless chrome // Read the cookie from headless chrome
const headlessBrowser = await launchBrowser( const headlessBrowser = await launchBrowser(
puppeteer, puppeteer,
Object.assign({ userDataDir }, headlessOptions) Object.assign({userDataDir}, headlessOptions)
); );
const headlessPage = await headlessBrowser.newPage(); const headlessPage = await headlessBrowser.newPage();
await headlessPage.goto(server.EMPTY_PAGE); await headlessPage.goto(server.EMPTY_PAGE);
@ -224,28 +224,28 @@ describeChromeOnly('headful tests', function () {
); );
// TODO: Support OOOPIF. @see https://github.com/puppeteer/puppeteer/issues/2548 // TODO: Support OOOPIF. @see https://github.com/puppeteer/puppeteer/issues/2548
xit('OOPIF: should report google.com frame', async () => { xit('OOPIF: should report google.com frame', async () => {
const { server, puppeteer } = getTestState(); const {server, puppeteer} = getTestState();
// https://google.com is isolated by default in Chromium embedder. // https://google.com is isolated by default in Chromium embedder.
const browser = await launchBrowser(puppeteer, headfulOptions); const browser = await launchBrowser(puppeteer, headfulOptions);
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(true); await page.setRequestInterception(true);
page.on('request', (r: { respond: (arg0: { body: string }) => any }) => { page.on('request', (r: {respond: (arg0: {body: string}) => any}) => {
return r.respond({ body: 'YO, GOOGLE.COM' }); return r.respond({body: 'YO, GOOGLE.COM'});
}); });
await page.evaluate(() => { await page.evaluate(() => {
const frame = document.createElement('iframe'); const frame = document.createElement('iframe');
frame.setAttribute('src', 'https://google.com/'); frame.setAttribute('src', 'https://google.com/');
document.body.appendChild(frame); document.body.appendChild(frame);
return new Promise((x) => { return new Promise(x => {
return (frame.onload = x); return (frame.onload = x);
}); });
}); });
await page.waitForSelector('iframe[src="https://google.com/"]'); await page.waitForSelector('iframe[src="https://google.com/"]');
const urls = page const urls = page
.frames() .frames()
.map((frame: { url: () => any }) => { .map((frame: {url: () => any}) => {
return frame.url(); return frame.url();
}) })
.sort(); .sort();
@ -253,7 +253,7 @@ describeChromeOnly('headful tests', function () {
await browser.close(); await browser.close();
}); });
it('OOPIF: should expose events within OOPIFs', async () => { it('OOPIF: should expose events within OOPIFs', async () => {
const { server, puppeteer } = getTestState(); const {server, puppeteer} = getTestState();
const browser = await launchBrowser(puppeteer, forcedOopifOptions); const browser = await launchBrowser(puppeteer, forcedOopifOptions);
const page = await browser.newPage(); const page = await browser.newPage();
@ -307,13 +307,13 @@ describeChromeOnly('headful tests', function () {
}); });
await browser.close(); await browser.close();
const requests = networkEvents.map((event) => { const requests = networkEvents.map(event => {
return event.request.url; return event.request.url;
}); });
expect(requests).toContain(`http://oopifdomain:${server.PORT}/fetch`); expect(requests).toContain(`http://oopifdomain:${server.PORT}/fetch`);
}); });
it('should close browser with beforeunload page', async () => { it('should close browser with beforeunload page', async () => {
const { server, puppeteer } = getTestState(); const {server, puppeteer} = getTestState();
const browser = await launchBrowser(puppeteer, headfulOptions); const browser = await launchBrowser(puppeteer, headfulOptions);
const page = await browser.newPage(); const page = await browser.newPage();
@ -324,16 +324,16 @@ describeChromeOnly('headful tests', function () {
await browser.close(); await browser.close();
}); });
it('should open devtools when "devtools: true" option is given', async () => { it('should open devtools when "devtools: true" option is given', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const browser = await launchBrowser( const browser = await launchBrowser(
puppeteer, puppeteer,
Object.assign({ devtools: true }, headfulOptions) Object.assign({devtools: true}, headfulOptions)
); );
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();
await Promise.all([ await Promise.all([
context.newPage(), context.newPage(),
browser.waitForTarget((target: { url: () => string | string[] }) => { browser.waitForTarget((target: {url: () => string | string[]}) => {
return target.url().includes('devtools://'); return target.url().includes('devtools://');
}), }),
]); ]);
@ -343,7 +343,7 @@ describeChromeOnly('headful tests', function () {
describe('Page.bringToFront', function () { describe('Page.bringToFront', function () {
it('should work', async () => { it('should work', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const browser = await launchBrowser(puppeteer, headfulOptions); const browser = await launchBrowser(puppeteer, headfulOptions);
const page1 = await browser.newPage(); const page1 = await browser.newPage();
const page2 = await browser.newPage(); const page2 = await browser.newPage();
@ -380,7 +380,7 @@ describeChromeOnly('headful tests', function () {
describe('Page.screenshot', function () { describe('Page.screenshot', function () {
it('should run in parallel in multiple pages', async () => { it('should run in parallel in multiple pages', async () => {
const { server, puppeteer } = getTestState(); const {server, puppeteer} = getTestState();
const browser = await puppeteer.launch(headfulOptions); const browser = await puppeteer.launch(headfulOptions);
const context = await browser.createIncognitoBrowserContext(); const context = await browser.createIncognitoBrowserContext();
@ -398,7 +398,7 @@ describeChromeOnly('headful tests', function () {
for (let i = 0; i < N; ++i) { for (let i = 0; i < N; ++i) {
promises.push( promises.push(
pages[i]!.screenshot({ pages[i]!.screenshot({
clip: { x: 50 * i, y: 0, width: 50, height: 50 }, clip: {x: 50 * i, y: 0, width: 50, height: 50},
}) })
); );
} }
@ -407,7 +407,7 @@ describeChromeOnly('headful tests', function () {
expect(screenshots[i]).toBeGolden(`grid-cell-${i}.png`); expect(screenshots[i]).toBeGolden(`grid-cell-${i}.png`);
} }
await Promise.all( await Promise.all(
pages.map((page) => { pages.map(page => {
return page.close(); return page.close();
}) })
); );

View File

@ -27,7 +27,7 @@ describeFailsFirefox('Emulate idle state', () => {
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
async function getIdleState() { async function getIdleState() {
const { page } = getTestState(); const {page} = getTestState();
const stateElement = (await page.$('#state'))!; const stateElement = (await page.$('#state'))!;
return await page.evaluate((element: HTMLElement) => { return await page.evaluate((element: HTMLElement) => {
@ -41,7 +41,7 @@ describeFailsFirefox('Emulate idle state', () => {
} }
it('changing idle state emulation causes change of the IdleDetector state', async () => { it('changing idle state emulation causes change of the IdleDetector state', async () => {
const { page, server, context } = getTestState(); const {page, server, context} = getTestState();
await context.overridePermissions(server.PREFIX + '/idle-detector.html', [ await context.overridePermissions(server.PREFIX + '/idle-detector.html', [
'idle-detection', 'idle-detection',
]); ]);

View File

@ -15,13 +15,13 @@
*/ */
import expect from 'expect'; import expect from 'expect';
import { TLSSocket } from 'tls'; import {TLSSocket} from 'tls';
import { import {
Browser, Browser,
BrowserContext, BrowserContext,
} from '../../lib/cjs/puppeteer/common/Browser.js'; } from '../../lib/cjs/puppeteer/common/Browser.js';
import { Page } from '../../lib/cjs/puppeteer/common/Page.js'; import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
import { HTTPResponse } from '../../lib/cjs/puppeteer/common/HTTPResponse.js'; import {HTTPResponse} from '../../lib/cjs/puppeteer/common/HTTPResponse.js';
import { import {
getTestState, getTestState,
describeFailsFirefox, describeFailsFirefox,
@ -38,9 +38,9 @@ describe('ignoreHTTPSErrors', function () {
let page!: Page; let page!: Page;
before(async () => { before(async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const options = Object.assign( const options = Object.assign(
{ ignoreHTTPSErrors: true }, {ignoreHTTPSErrors: true},
defaultBrowserOptions defaultBrowserOptions
); );
browser = await puppeteer.launch(options); browser = await puppeteer.launch(options);
@ -61,7 +61,7 @@ describe('ignoreHTTPSErrors', function () {
describeFailsFirefox('Response.securityDetails', function () { describeFailsFirefox('Response.securityDetails', function () {
it('should work', async () => { it('should work', async () => {
const { httpsServer } = getTestState(); const {httpsServer} = getTestState();
const [serverRequest, response] = await Promise.all([ const [serverRequest, response] = await Promise.all([
httpsServer.waitForRequest('/empty.html'), httpsServer.waitForRequest('/empty.html'),
@ -82,17 +82,17 @@ describe('ignoreHTTPSErrors', function () {
]); ]);
}); });
it('should be |null| for non-secure requests', async () => { it('should be |null| for non-secure requests', async () => {
const { server } = getTestState(); const {server} = getTestState();
const response = (await page.goto(server.EMPTY_PAGE))!; const response = (await page.goto(server.EMPTY_PAGE))!;
expect(response.securityDetails()).toBe(null); expect(response.securityDetails()).toBe(null);
}); });
it('Network redirects should report SecurityDetails', async () => { it('Network redirects should report SecurityDetails', async () => {
const { httpsServer } = getTestState(); const {httpsServer} = getTestState();
httpsServer.setRedirect('/plzredirect', '/empty.html'); httpsServer.setRedirect('/plzredirect', '/empty.html');
const responses: HTTPResponse[] = []; const responses: HTTPResponse[] = [];
page.on('response', (response) => { page.on('response', response => {
return responses.push(response); return responses.push(response);
}); });
const [serverRequest] = await Promise.all([ const [serverRequest] = await Promise.all([
@ -110,27 +110,27 @@ describe('ignoreHTTPSErrors', function () {
}); });
it('should work', async () => { it('should work', async () => {
const { httpsServer } = getTestState(); const {httpsServer} = getTestState();
let error!: Error; let error!: Error;
const response = await page.goto(httpsServer.EMPTY_PAGE).catch((error_) => { const response = await page.goto(httpsServer.EMPTY_PAGE).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeUndefined(); expect(error).toBeUndefined();
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
}); });
itFailsFirefox('should work with request interception', async () => { itFailsFirefox('should work with request interception', async () => {
const { httpsServer } = getTestState(); const {httpsServer} = getTestState();
await page.setRequestInterception(true); await page.setRequestInterception(true);
page.on('request', (request) => { page.on('request', request => {
return request.continue(); return request.continue();
}); });
const response = (await page.goto(httpsServer.EMPTY_PAGE))!; const response = (await page.goto(httpsServer.EMPTY_PAGE))!;
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
}); });
itFailsFirefox('should work with mixed content', async () => { itFailsFirefox('should work with mixed content', async () => {
const { server, httpsServer } = getTestState(); const {server, httpsServer} = getTestState();
httpsServer.setRoute('/mixedcontent.html', (_req, res) => { httpsServer.setRoute('/mixedcontent.html', (_req, res) => {
res.end(`<iframe src=${server.EMPTY_PAGE}></iframe>`); res.end(`<iframe src=${server.EMPTY_PAGE}></iframe>`);

View File

@ -31,17 +31,17 @@ describe('input tests', function () {
describeFailsFirefox('input', function () { describeFailsFirefox('input', function () {
it('should upload the file', async () => { it('should upload the file', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/fileupload.html'); await page.goto(server.PREFIX + '/input/fileupload.html');
const filePath = path.relative(process.cwd(), FILE_TO_UPLOAD); const filePath = path.relative(process.cwd(), FILE_TO_UPLOAD);
const input = (await page.$('input'))!; const input = (await page.$('input'))!;
await page.evaluate((e: HTMLElement) => { await page.evaluate((e: HTMLElement) => {
(globalThis as any)._inputEvents = []; (globalThis as any)._inputEvents = [];
e.addEventListener('change', (ev) => { e.addEventListener('change', ev => {
return (globalThis as any)._inputEvents.push(ev.type); return (globalThis as any)._inputEvents.push(ev.type);
}); });
e.addEventListener('input', (ev) => { e.addEventListener('input', ev => {
return (globalThis as any)._inputEvents.push(ev.type); return (globalThis as any)._inputEvents.push(ev.type);
}); });
}, input); }, input);
@ -64,7 +64,7 @@ describe('input tests', function () {
expect( expect(
await page.evaluate((e: HTMLInputElement) => { await page.evaluate((e: HTMLInputElement) => {
const reader = new FileReader(); const reader = new FileReader();
const promise = new Promise((fulfill) => { const promise = new Promise(fulfill => {
return (reader.onload = fulfill); return (reader.onload = fulfill);
}); });
reader.readAsText(e.files![0]!); reader.readAsText(e.files![0]!);
@ -78,7 +78,7 @@ describe('input tests', function () {
describeFailsFirefox('Page.waitForFileChooser', function () { describeFailsFirefox('Page.waitForFileChooser', function () {
it('should work when file input is attached to DOM', async () => { it('should work when file input is attached to DOM', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([
@ -88,7 +88,7 @@ describe('input tests', function () {
expect(chooser).toBeTruthy(); expect(chooser).toBeTruthy();
}); });
it('should work when file input is not attached to DOM', async () => { it('should work when file input is not attached to DOM', async () => {
const { page } = getTestState(); const {page} = getTestState();
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([
page.waitForFileChooser(), page.waitForFileChooser(),
@ -101,39 +101,39 @@ describe('input tests', function () {
expect(chooser).toBeTruthy(); expect(chooser).toBeTruthy();
}); });
it('should respect timeout', async () => { it('should respect timeout', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
let error!: Error; let error!: Error;
await page.waitForFileChooser({ timeout: 1 }).catch((error_) => { await page.waitForFileChooser({timeout: 1}).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should respect default timeout when there is no custom timeout', async () => { it('should respect default timeout when there is no custom timeout', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
page.setDefaultTimeout(1); page.setDefaultTimeout(1);
let error!: Error; let error!: Error;
await page.waitForFileChooser().catch((error_) => { await page.waitForFileChooser().catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should prioritize exact timeout over default timeout', async () => { it('should prioritize exact timeout over default timeout', async () => {
const { page, puppeteer } = getTestState(); const {page, puppeteer} = getTestState();
page.setDefaultTimeout(0); page.setDefaultTimeout(0);
let error!: Error; let error!: Error;
await page.waitForFileChooser({ timeout: 1 }).catch((error_) => { await page.waitForFileChooser({timeout: 1}).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should work with no timeout', async () => { it('should work with no timeout', async () => {
const { page } = getTestState(); const {page} = getTestState();
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([
page.waitForFileChooser({ timeout: 0 }), page.waitForFileChooser({timeout: 0}),
page.evaluate(() => { page.evaluate(() => {
return setTimeout(() => { return setTimeout(() => {
const el = document.createElement('input'); const el = document.createElement('input');
@ -145,13 +145,13 @@ describe('input tests', function () {
expect(chooser).toBeTruthy(); expect(chooser).toBeTruthy();
}); });
it('should return the same file chooser when there are many watchdogs simultaneously', async () => { it('should return the same file chooser when there are many watchdogs simultaneously', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [fileChooser1, fileChooser2] = await Promise.all([ const [fileChooser1, fileChooser2] = await Promise.all([
page.waitForFileChooser(), page.waitForFileChooser(),
page.waitForFileChooser(), page.waitForFileChooser(),
page.$eval('input', (input) => { page.$eval('input', input => {
return (input as HTMLInputElement).click(); return (input as HTMLInputElement).click();
}), }),
]); ]);
@ -161,7 +161,7 @@ describe('input tests', function () {
describeFailsFirefox('FileChooser.accept', function () { describeFailsFirefox('FileChooser.accept', function () {
it('should accept single file', async () => { it('should accept single file', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent( await page.setContent(
`<input type=file oninput='javascript:console.timeStamp()'>` `<input type=file oninput='javascript:console.timeStamp()'>`
@ -172,37 +172,37 @@ describe('input tests', function () {
]); ]);
await Promise.all([ await Promise.all([
chooser.accept([FILE_TO_UPLOAD]), chooser.accept([FILE_TO_UPLOAD]),
new Promise((x) => { new Promise(x => {
return page.once('metrics', x); return page.once('metrics', x);
}), }),
]); ]);
expect( expect(
await page.$eval('input', (input) => { await page.$eval('input', input => {
return (input as HTMLInputElement).files!.length; return (input as HTMLInputElement).files!.length;
}) })
).toBe(1); ).toBe(1);
expect( expect(
await page.$eval('input', (input) => { await page.$eval('input', input => {
return (input as HTMLInputElement).files![0]!.name; return (input as HTMLInputElement).files![0]!.name;
}) })
).toBe('file-to-upload.txt'); ).toBe('file-to-upload.txt');
}); });
it('should be able to read selected file', async () => { it('should be able to read selected file', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
page.waitForFileChooser().then((chooser) => { page.waitForFileChooser().then(chooser => {
return chooser.accept([FILE_TO_UPLOAD]); return chooser.accept([FILE_TO_UPLOAD]);
}); });
expect( expect(
await page.$eval('input', async (picker) => { await page.$eval('input', async picker => {
const pick = picker as HTMLInputElement; const pick = picker as HTMLInputElement;
pick.click(); pick.click();
await new Promise((x) => { await new Promise(x => {
return (pick.oninput = x); return (pick.oninput = x);
}); });
const reader = new FileReader(); const reader = new FileReader();
const promise = new Promise((fulfill) => { const promise = new Promise(fulfill => {
return (reader.onload = fulfill); return (reader.onload = fulfill);
}); });
reader.readAsText(pick.files![0]!); reader.readAsText(pick.files![0]!);
@ -213,30 +213,30 @@ describe('input tests', function () {
).toBe('contents of the file'); ).toBe('contents of the file');
}); });
it('should be able to reset selected files with empty file list', async () => { it('should be able to reset selected files with empty file list', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
page.waitForFileChooser().then((chooser) => { page.waitForFileChooser().then(chooser => {
return chooser.accept([FILE_TO_UPLOAD]); return chooser.accept([FILE_TO_UPLOAD]);
}); });
expect( expect(
await page.$eval('input', async (picker) => { await page.$eval('input', async picker => {
const pick = picker as HTMLInputElement; const pick = picker as HTMLInputElement;
pick.click(); pick.click();
await new Promise((x) => { await new Promise(x => {
return (pick.oninput = x); return (pick.oninput = x);
}); });
return pick.files!.length; return pick.files!.length;
}) })
).toBe(1); ).toBe(1);
page.waitForFileChooser().then((chooser) => { page.waitForFileChooser().then(chooser => {
return chooser.accept([]); return chooser.accept([]);
}); });
expect( expect(
await page.$eval('input', async (picker) => { await page.$eval('input', async picker => {
const pick = picker as HTMLInputElement; const pick = picker as HTMLInputElement;
pick.click(); pick.click();
await new Promise((x) => { await new Promise(x => {
return (pick.oninput = x); return (pick.oninput = x);
}); });
return pick.files!.length; return pick.files!.length;
@ -244,7 +244,7 @@ describe('input tests', function () {
).toBe(0); ).toBe(0);
}); });
it('should not accept multiple files for single-file input', async () => { it('should not accept multiple files for single-file input', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([
@ -260,13 +260,13 @@ describe('input tests', function () {
), ),
path.relative(process.cwd(), __dirname + '/../assets/pptr.png'), path.relative(process.cwd(), __dirname + '/../assets/pptr.png'),
]) ])
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).not.toBe(null); expect(error).not.toBe(null);
}); });
it('should succeed even for non-existent files', async () => { it('should succeed even for non-existent files', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([
@ -274,27 +274,27 @@ describe('input tests', function () {
page.click('input'), page.click('input'),
]); ]);
let error!: Error; let error!: Error;
await chooser.accept(['file-does-not-exist.txt']).catch((error_) => { await chooser.accept(['file-does-not-exist.txt']).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeUndefined(); expect(error).toBeUndefined();
}); });
it('should error on read of non-existent files', async () => { it('should error on read of non-existent files', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
page.waitForFileChooser().then((chooser) => { page.waitForFileChooser().then(chooser => {
return chooser.accept(['file-does-not-exist.txt']); return chooser.accept(['file-does-not-exist.txt']);
}); });
expect( expect(
await page.$eval('input', async (picker) => { await page.$eval('input', async picker => {
const pick = picker as HTMLInputElement; const pick = picker as HTMLInputElement;
pick.click(); pick.click();
await new Promise((x) => { await new Promise(x => {
return (pick.oninput = x); return (pick.oninput = x);
}); });
const reader = new FileReader(); const reader = new FileReader();
const promise = new Promise((fulfill) => { const promise = new Promise(fulfill => {
return (reader.onerror = fulfill); return (reader.onerror = fulfill);
}); });
reader.readAsText(pick.files![0]!); reader.readAsText(pick.files![0]!);
@ -305,18 +305,18 @@ describe('input tests', function () {
).toBeFalsy(); ).toBeFalsy();
}); });
it('should fail when accepting file chooser twice', async () => { it('should fail when accepting file chooser twice', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [fileChooser] = await Promise.all([ const [fileChooser] = await Promise.all([
page.waitForFileChooser(), page.waitForFileChooser(),
page.$eval('input', (input) => { page.$eval('input', input => {
return (input as HTMLInputElement).click(); return (input as HTMLInputElement).click();
}), }),
]); ]);
await fileChooser.accept([]); await fileChooser.accept([]);
let error!: Error; let error!: Error;
await fileChooser.accept([]).catch((error_) => { await fileChooser.accept([]).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toBe( expect(error.message).toBe(
@ -327,7 +327,7 @@ describe('input tests', function () {
describeFailsFirefox('FileChooser.cancel', function () { describeFailsFirefox('FileChooser.cancel', function () {
it('should cancel dialog', async () => { it('should cancel dialog', async () => {
const { page } = getTestState(); const {page} = getTestState();
// Consider file chooser canceled if we can summon another one. // Consider file chooser canceled if we can summon another one.
// There's no reliable way in WebPlatform to see that FileChooser was // There's no reliable way in WebPlatform to see that FileChooser was
@ -335,7 +335,7 @@ describe('input tests', function () {
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [fileChooser1] = await Promise.all([ const [fileChooser1] = await Promise.all([
page.waitForFileChooser(), page.waitForFileChooser(),
page.$eval('input', (input) => { page.$eval('input', input => {
return (input as HTMLInputElement).click(); return (input as HTMLInputElement).click();
}), }),
]); ]);
@ -343,18 +343,18 @@ describe('input tests', function () {
// If this resolves, than we successfully canceled file chooser. // If this resolves, than we successfully canceled file chooser.
await Promise.all([ await Promise.all([
page.waitForFileChooser(), page.waitForFileChooser(),
page.$eval('input', (input) => { page.$eval('input', input => {
return (input as HTMLInputElement).click(); return (input as HTMLInputElement).click();
}), }),
]); ]);
}); });
it('should fail when canceling file chooser twice', async () => { it('should fail when canceling file chooser twice', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [fileChooser] = await Promise.all([ const [fileChooser] = await Promise.all([
page.waitForFileChooser(), page.waitForFileChooser(),
page.$eval('input', (input) => { page.$eval('input', input => {
return (input as HTMLElement).click(); return (input as HTMLElement).click();
}), }),
]); ]);
@ -375,7 +375,7 @@ describe('input tests', function () {
describeFailsFirefox('FileChooser.isMultiple', () => { describeFailsFirefox('FileChooser.isMultiple', () => {
it('should work for single file pick', async () => { it('should work for single file pick', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input type=file>`); await page.setContent(`<input type=file>`);
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([
@ -385,7 +385,7 @@ describe('input tests', function () {
expect(chooser.isMultiple()).toBe(false); expect(chooser.isMultiple()).toBe(false);
}); });
it('should work for "multiple"', async () => { it('should work for "multiple"', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input multiple type=file>`); await page.setContent(`<input multiple type=file>`);
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([
@ -395,7 +395,7 @@ describe('input tests', function () {
expect(chooser.isMultiple()).toBe(true); expect(chooser.isMultiple()).toBe(true);
}); });
it('should work for "webkitdirectory"', async () => { it('should work for "webkitdirectory"', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent(`<input multiple webkitdirectory type=file>`); await page.setContent(`<input multiple webkitdirectory type=file>`);
const [chooser] = await Promise.all([ const [chooser] = await Promise.all([

View File

@ -15,7 +15,7 @@
*/ */
import expect from 'expect'; import expect from 'expect';
import { JSHandle } from '../../lib/cjs/puppeteer/common/JSHandle.js'; import {JSHandle} from '../../lib/cjs/puppeteer/common/JSHandle.js';
import { import {
getTestState, getTestState,
setupTestBrowserHooks, setupTestBrowserHooks,
@ -30,7 +30,7 @@ describe('JSHandle', function () {
describe('Page.evaluateHandle', function () { describe('Page.evaluateHandle', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const windowHandle = await page.evaluateHandle(() => { const windowHandle = await page.evaluateHandle(() => {
return window; return window;
@ -38,7 +38,7 @@ describe('JSHandle', function () {
expect(windowHandle).toBeTruthy(); expect(windowHandle).toBeTruthy();
}); });
it('should accept object handle as an argument', async () => { it('should accept object handle as an argument', async () => {
const { page } = getTestState(); const {page} = getTestState();
const navigatorHandle = await page.evaluateHandle(() => { const navigatorHandle = await page.evaluateHandle(() => {
return navigator; return navigator;
@ -49,56 +49,56 @@ describe('JSHandle', function () {
expect(text).toContain('Mozilla'); expect(text).toContain('Mozilla');
}); });
it('should accept object handle to primitive types', async () => { it('should accept object handle to primitive types', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return 5; return 5;
}); });
const isFive = await page.evaluate((e) => { const isFive = await page.evaluate(e => {
return Object.is(e, 5); return Object.is(e, 5);
}, aHandle); }, aHandle);
expect(isFive).toBeTruthy(); expect(isFive).toBeTruthy();
}); });
it('should warn about recursive objects', async () => { it('should warn about recursive objects', async () => {
const { page } = getTestState(); const {page} = getTestState();
const test: { obj?: unknown } = {}; const test: {obj?: unknown} = {};
test.obj = test; test.obj = test;
let error!: Error; let error!: Error;
await page await page
.evaluateHandle( .evaluateHandle(
(opts) => { opts => {
return opts.elem; return opts.elem;
}, },
// @ts-expect-error we are deliberately passing a bad type here (nested object) // @ts-expect-error we are deliberately passing a bad type here (nested object)
{ test } {test}
) )
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('Recursive objects are not allowed.'); expect(error.message).toContain('Recursive objects are not allowed.');
}); });
it('should accept object handle to unserializable value', async () => { it('should accept object handle to unserializable value', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return Infinity; return Infinity;
}); });
expect( expect(
await page.evaluate((e) => { await page.evaluate(e => {
return Object.is(e, Infinity); return Object.is(e, Infinity);
}, aHandle) }, aHandle)
).toBe(true); ).toBe(true);
}); });
it('should use the same JS wrappers', async () => { it('should use the same JS wrappers', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
(globalThis as any).FOO = 123; (globalThis as any).FOO = 123;
return window; return window;
}); });
expect( expect(
await page.evaluate((e: { FOO: number }) => { await page.evaluate((e: {FOO: number}) => {
return e.FOO; return e.FOO;
}, aHandle) }, aHandle)
).toBe(123); ).toBe(123);
@ -107,7 +107,7 @@ describe('JSHandle', function () {
describe('JSHandle.getProperty', function () { describe('JSHandle.getProperty', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return { return {
@ -121,7 +121,7 @@ describe('JSHandle', function () {
}); });
it('should return a JSHandle even if the property does not exist', async () => { it('should return a JSHandle even if the property does not exist', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return { return {
@ -138,17 +138,17 @@ describe('JSHandle', function () {
describe('JSHandle.jsonValue', function () { describe('JSHandle.jsonValue', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return { foo: 'bar' }; return {foo: 'bar'};
}); });
const json = await aHandle.jsonValue<Record<string, string>>(); const json = await aHandle.jsonValue<Record<string, string>>();
expect(json).toEqual({ foo: 'bar' }); expect(json).toEqual({foo: 'bar'});
}); });
it('works with jsonValues that are not objects', async () => { it('works with jsonValues that are not objects', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return ['a', 'b']; return ['a', 'b'];
@ -158,7 +158,7 @@ describe('JSHandle', function () {
}); });
it('works with jsonValues that are primitives', async () => { it('works with jsonValues that are primitives', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return 'foo'; return 'foo';
@ -168,7 +168,7 @@ describe('JSHandle', function () {
}); });
itFailsFirefox('should not work with dates', async () => { itFailsFirefox('should not work with dates', async () => {
const { page } = getTestState(); const {page} = getTestState();
const dateHandle = await page.evaluateHandle(() => { const dateHandle = await page.evaluateHandle(() => {
return new Date('2017-09-26T00:00:00.000Z'); return new Date('2017-09-26T00:00:00.000Z');
@ -177,11 +177,11 @@ describe('JSHandle', function () {
expect(json).toEqual({}); expect(json).toEqual({});
}); });
it('should throw for circular objects', async () => { it('should throw for circular objects', async () => {
const { page, isChrome } = getTestState(); const {page, isChrome} = getTestState();
const windowHandle = await page.evaluateHandle('window'); const windowHandle = await page.evaluateHandle('window');
let error!: Error; let error!: Error;
await windowHandle.jsonValue().catch((error_) => { await windowHandle.jsonValue().catch(error_ => {
return (error = error_); return (error = error_);
}); });
if (isChrome) { if (isChrome) {
@ -194,7 +194,7 @@ describe('JSHandle', function () {
describe('JSHandle.getProperties', function () { describe('JSHandle.getProperties', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return { return {
@ -207,7 +207,7 @@ describe('JSHandle', function () {
expect(await foo.jsonValue()).toBe('bar'); expect(await foo.jsonValue()).toBe('bar');
}); });
it('should return even non-own properties', async () => { it('should return even non-own properties', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
class A { class A {
@ -233,7 +233,7 @@ describe('JSHandle', function () {
describe('JSHandle.asElement', function () { describe('JSHandle.asElement', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return document.body; return document.body;
@ -242,7 +242,7 @@ describe('JSHandle', function () {
expect(element).toBeTruthy(); expect(element).toBeTruthy();
}); });
it('should return null for non-elements', async () => { it('should return null for non-elements', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return 2; return 2;
@ -251,7 +251,7 @@ describe('JSHandle', function () {
expect(element).toBeFalsy(); expect(element).toBeFalsy();
}); });
it('should return ElementHandle for TextNodes', async () => { it('should return ElementHandle for TextNodes', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.setContent('<div>ee!</div>'); await page.setContent('<div>ee!</div>');
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
@ -269,7 +269,7 @@ describe('JSHandle', function () {
describe('JSHandle.toString', function () { describe('JSHandle.toString', function () {
it('should work for primitives', async () => { it('should work for primitives', async () => {
const { page } = getTestState(); const {page} = getTestState();
const numberHandle = await page.evaluateHandle(() => { const numberHandle = await page.evaluateHandle(() => {
return 2; return 2;
@ -281,7 +281,7 @@ describe('JSHandle', function () {
expect(stringHandle.toString()).toBe('JSHandle:a'); expect(stringHandle.toString()).toBe('JSHandle:a');
}); });
it('should work for complicated objects', async () => { it('should work for complicated objects', async () => {
const { page } = getTestState(); const {page} = getTestState();
const aHandle = await page.evaluateHandle(() => { const aHandle = await page.evaluateHandle(() => {
return window; return window;
@ -289,7 +289,7 @@ describe('JSHandle', function () {
expect(aHandle.toString()).toBe('JSHandle@object'); expect(aHandle.toString()).toBe('JSHandle@object');
}); });
it('should work with different subtypes', async () => { it('should work with different subtypes', async () => {
const { page } = getTestState(); const {page} = getTestState();
expect((await page.evaluateHandle('(function(){})')).toString()).toBe( expect((await page.evaluateHandle('(function(){})')).toString()).toBe(
'JSHandle@function' 'JSHandle@function'
@ -348,7 +348,7 @@ describe('JSHandle', function () {
describe('JSHandle.clickablePoint', function () { describe('JSHandle.clickablePoint', function () {
it('should work', async () => { it('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
document.body.style.padding = '0'; document.body.style.padding = '0';
@ -358,7 +358,7 @@ describe('JSHandle', function () {
`; `;
}); });
await page.evaluate(async () => { await page.evaluate(async () => {
return new Promise((resolve) => { return new Promise(resolve => {
return window.requestAnimationFrame(resolve); return window.requestAnimationFrame(resolve);
}); });
}); });
@ -379,7 +379,7 @@ describe('JSHandle', function () {
}); });
it('should work for iframes', async () => { it('should work for iframes', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
document.body.style.padding = '10px'; document.body.style.padding = '10px';
document.body.style.margin = '10px'; document.body.style.margin = '10px';
@ -388,7 +388,7 @@ describe('JSHandle', function () {
`; `;
}); });
await page.evaluate(async () => { await page.evaluate(async () => {
return new Promise((resolve) => { return new Promise(resolve => {
return window.requestAnimationFrame(resolve); return window.requestAnimationFrame(resolve);
}); });
}); });
@ -412,7 +412,7 @@ describe('JSHandle', function () {
describe('JSHandle.click', function () { describe('JSHandle.click', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { page } = getTestState(); const {page} = getTestState();
const clicks: [x: number, y: number][] = []; const clicks: [x: number, y: number][] = [];
@ -426,7 +426,7 @@ describe('JSHandle', function () {
document.body.innerHTML = ` document.body.innerHTML = `
<div style="cursor: pointer; width: 120px; height: 60px; margin: 30px; padding: 15px;"></div> <div style="cursor: pointer; width: 120px; height: 60px; margin: 30px; padding: 15px;"></div>
`; `;
document.body.addEventListener('click', (e) => { document.body.addEventListener('click', e => {
(window as any).reportClick(e.clientX, e.clientY); (window as any).reportClick(e.clientX, e.clientY);
}); });
}); });

View File

@ -23,14 +23,14 @@ import {
setupTestPageAndContextHooks, setupTestPageAndContextHooks,
itFailsFirefox, itFailsFirefox,
} from './mocha-utils.js'; } from './mocha-utils.js';
import { KeyInput } from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js'; import {KeyInput} from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js';
describe('Keyboard', function () { describe('Keyboard', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should type into a textarea', async () => { it('should type into a textarea', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
const textarea = document.createElement('textarea'); const textarea = document.createElement('textarea');
@ -46,11 +46,11 @@ describe('Keyboard', function () {
).toBe(text); ).toBe(text);
}); });
itFailsFirefox('should press the metaKey', async () => { itFailsFirefox('should press the metaKey', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
(window as any).keyPromise = new Promise((resolve) => { (window as any).keyPromise = new Promise(resolve => {
return document.addEventListener('keydown', (event) => { return document.addEventListener('keydown', event => {
return resolve(event.key); return resolve(event.key);
}); });
}); });
@ -61,7 +61,7 @@ describe('Keyboard', function () {
); );
}); });
it('should move with the arrow keys', async () => { it('should move with the arrow keys', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.type('textarea', 'Hello World!'); await page.type('textarea', 'Hello World!');
@ -92,7 +92,7 @@ describe('Keyboard', function () {
).toBe('Hello World!'); ).toBe('Hello World!');
}); });
it('should send a character with ElementHandle.press', async () => { it('should send a character with ElementHandle.press', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
const textarea = (await page.$('textarea'))!; const textarea = (await page.$('textarea'))!;
@ -106,7 +106,7 @@ describe('Keyboard', function () {
await page.evaluate(() => { await page.evaluate(() => {
return window.addEventListener( return window.addEventListener(
'keydown', 'keydown',
(e) => { e => {
return e.preventDefault(); return e.preventDefault();
}, },
true true
@ -123,11 +123,11 @@ describe('Keyboard', function () {
itFailsFirefox( itFailsFirefox(
'ElementHandle.press should support |text| option', 'ElementHandle.press should support |text| option',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
const textarea = (await page.$('textarea'))!; const textarea = (await page.$('textarea'))!;
await textarea.press('a', { text: 'ё' }); await textarea.press('a', {text: 'ё'});
expect( expect(
await page.evaluate(() => { await page.evaluate(() => {
return document.querySelector('textarea')!.value; return document.querySelector('textarea')!.value;
@ -136,7 +136,7 @@ describe('Keyboard', function () {
} }
); );
itFailsFirefox('should send a character with sendCharacter', async () => { itFailsFirefox('should send a character with sendCharacter', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
@ -149,7 +149,7 @@ describe('Keyboard', function () {
await page.evaluate(() => { await page.evaluate(() => {
return window.addEventListener( return window.addEventListener(
'keydown', 'keydown',
(e) => { e => {
return e.preventDefault(); return e.preventDefault();
}, },
true true
@ -163,7 +163,7 @@ describe('Keyboard', function () {
).toBe('嗨a'); ).toBe('嗨a');
}); });
itFailsFirefox('should report shiftKey', async () => { itFailsFirefox('should report shiftKey', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/keyboard.html'); await page.goto(server.PREFIX + '/input/keyboard.html');
const keyboard = page.keyboard; const keyboard = page.keyboard;
@ -234,7 +234,7 @@ describe('Keyboard', function () {
} }
}); });
it('should report multiple modifiers', async () => { it('should report multiple modifiers', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/keyboard.html'); await page.goto(server.PREFIX + '/input/keyboard.html');
const keyboard = page.keyboard; const keyboard = page.keyboard;
@ -276,7 +276,7 @@ describe('Keyboard', function () {
).toBe('Keyup: Alt AltLeft 18 []'); ).toBe('Keyup: Alt AltLeft 18 []');
}); });
it('should send proper codes while typing', async () => { it('should send proper codes while typing', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/keyboard.html'); await page.goto(server.PREFIX + '/input/keyboard.html');
await page.keyboard.type('!'); await page.keyboard.type('!');
@ -305,7 +305,7 @@ describe('Keyboard', function () {
); );
}); });
it('should send proper codes while typing with shift', async () => { it('should send proper codes while typing with shift', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/keyboard.html'); await page.goto(server.PREFIX + '/input/keyboard.html');
const keyboard = page.keyboard; const keyboard = page.keyboard;
@ -326,14 +326,14 @@ describe('Keyboard', function () {
await keyboard.up('Shift'); await keyboard.up('Shift');
}); });
it('should not type canceled events', async () => { it('should not type canceled events', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
await page.evaluate(() => { await page.evaluate(() => {
window.addEventListener( window.addEventListener(
'keydown', 'keydown',
(event) => { event => {
event.stopPropagation(); event.stopPropagation();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
if (event.key === 'l') { if (event.key === 'l') {
@ -354,14 +354,14 @@ describe('Keyboard', function () {
).toBe('He Wrd!'); ).toBe('He Wrd!');
}); });
itFailsFirefox('should specify repeat property', async () => { itFailsFirefox('should specify repeat property', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
await page.evaluate(() => { await page.evaluate(() => {
return document.querySelector('textarea')!.addEventListener( return document.querySelector('textarea')!.addEventListener(
'keydown', 'keydown',
(e) => { e => {
return ((globalThis as any).lastEvent = e); return ((globalThis as any).lastEvent = e);
}, },
true true
@ -402,7 +402,7 @@ describe('Keyboard', function () {
).toBe(false); ).toBe(false);
}); });
itFailsFirefox('should type all kinds of characters', async () => { itFailsFirefox('should type all kinds of characters', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
@ -411,13 +411,13 @@ describe('Keyboard', function () {
expect(await page.evaluate('result')).toBe(text); expect(await page.evaluate('result')).toBe(text);
}); });
itFailsFirefox('should specify location', async () => { itFailsFirefox('should specify location', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.evaluate(() => { await page.evaluate(() => {
window.addEventListener( window.addEventListener(
'keydown', 'keydown',
(event) => { event => {
return ((globalThis as any).keyLocation = event.location); return ((globalThis as any).keyLocation = event.location);
}, },
true true
@ -438,41 +438,41 @@ describe('Keyboard', function () {
expect(await page.evaluate('keyLocation')).toBe(3); expect(await page.evaluate('keyLocation')).toBe(3);
}); });
it('should throw on unknown keys', async () => { it('should throw on unknown keys', async () => {
const { page } = getTestState(); const {page} = getTestState();
let error = await page.keyboard let error = await page.keyboard
// @ts-expect-error bad input // @ts-expect-error bad input
.press('NotARealKey') .press('NotARealKey')
.catch((error_) => { .catch(error_ => {
return error_; return error_;
}); });
expect(error.message).toBe('Unknown key: "NotARealKey"'); expect(error.message).toBe('Unknown key: "NotARealKey"');
// @ts-expect-error bad input // @ts-expect-error bad input
error = await page.keyboard.press('ё').catch((error_) => { error = await page.keyboard.press('ё').catch(error_ => {
return error_; return error_;
}); });
expect(error && error.message).toBe('Unknown key: "ё"'); expect(error && error.message).toBe('Unknown key: "ё"');
// @ts-expect-error bad input // @ts-expect-error bad input
error = await page.keyboard.press('😊').catch((error_) => { error = await page.keyboard.press('😊').catch(error_ => {
return error_; return error_;
}); });
expect(error && error.message).toBe('Unknown key: "😊"'); expect(error && error.message).toBe('Unknown key: "😊"');
}); });
itFailsFirefox('should type emoji', async () => { itFailsFirefox('should type emoji', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.type('textarea', '👹 Tokyo street Japan 🇯🇵'); await page.type('textarea', '👹 Tokyo street Japan 🇯🇵');
expect( expect(
await page.$eval('textarea', (textarea) => { await page.$eval('textarea', textarea => {
return (textarea as HTMLInputElement).value; return (textarea as HTMLInputElement).value;
}) })
).toBe('👹 Tokyo street Japan 🇯🇵'); ).toBe('👹 Tokyo street Japan 🇯🇵');
}); });
itFailsFirefox('should type emoji into an iframe', async () => { itFailsFirefox('should type emoji into an iframe', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await utils.attachFrame( await utils.attachFrame(
@ -484,17 +484,17 @@ describe('Keyboard', function () {
const textarea = (await frame.$('textarea'))!; const textarea = (await frame.$('textarea'))!;
await textarea.type('👹 Tokyo street Japan 🇯🇵'); await textarea.type('👹 Tokyo street Japan 🇯🇵');
expect( expect(
await frame.$eval('textarea', (textarea) => { await frame.$eval('textarea', textarea => {
return (textarea as HTMLInputElement).value; return (textarea as HTMLInputElement).value;
}) })
).toBe('👹 Tokyo street Japan 🇯🇵'); ).toBe('👹 Tokyo street Japan 🇯🇵');
}); });
itFailsFirefox('should press the meta key', async () => { itFailsFirefox('should press the meta key', async () => {
const { page, isFirefox } = getTestState(); const {page, isFirefox} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
(globalThis as any).result = null; (globalThis as any).result = null;
document.addEventListener('keydown', (event) => { document.addEventListener('keydown', event => {
(globalThis as any).result = [event.key, event.code, event.metaKey]; (globalThis as any).result = [event.key, event.code, event.metaKey];
}); });
}); });

View File

@ -20,10 +20,10 @@ import os from 'os';
import path from 'path'; import path from 'path';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import sinon from 'sinon'; import sinon from 'sinon';
import { TLSSocket } from 'tls'; import {TLSSocket} from 'tls';
import { promisify } from 'util'; import {promisify} from 'util';
import { Page } from '../../lib/cjs/puppeteer/common/Page.js'; import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
import { Product } from '../../lib/cjs/puppeteer/common/Product.js'; import {Product} from '../../lib/cjs/puppeteer/common/Product.js';
import { import {
getTestState, getTestState,
itChromeOnly, itChromeOnly,
@ -50,7 +50,7 @@ describe('Launcher specs', function () {
describe('Puppeteer', function () { describe('Puppeteer', function () {
describe('BrowserFetcher', function () { describe('BrowserFetcher', function () {
it('should download and extract chrome linux binary', async () => { it('should download and extract chrome linux binary', async () => {
const { server, puppeteer } = getTestState(); const {server, puppeteer} = getTestState();
const downloadsFolder = await mkdtempAsync(TMP_FOLDER); const downloadsFolder = await mkdtempAsync(TMP_FOLDER);
const browserFetcher = puppeteer.createBrowserFetcher({ const browserFetcher = puppeteer.createBrowserFetcher({
@ -91,7 +91,7 @@ describe('Launcher specs', function () {
await rmAsync(downloadsFolder); await rmAsync(downloadsFolder);
}); });
it('should download and extract firefox linux binary', async () => { it('should download and extract firefox linux binary', async () => {
const { server, puppeteer } = getTestState(); const {server, puppeteer} = getTestState();
const downloadsFolder = await mkdtempAsync(TMP_FOLDER); const downloadsFolder = await mkdtempAsync(TMP_FOLDER);
const browserFetcher = puppeteer.createBrowserFetcher({ const browserFetcher = puppeteer.createBrowserFetcher({
@ -139,7 +139,7 @@ describe('Launcher specs', function () {
describe('Browser.disconnect', function () { describe('Browser.disconnect', function () {
it('should reject navigation when browser closes', async () => { it('should reject navigation when browser closes', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
server.setRoute('/one-style.css', () => {}); server.setRoute('/one-style.css', () => {});
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const remote = await puppeteer.connect({ const remote = await puppeteer.connect({
@ -147,8 +147,8 @@ describe('Launcher specs', function () {
}); });
const page = await remote.newPage(); const page = await remote.newPage();
const navigationPromise = page const navigationPromise = page
.goto(server.PREFIX + '/one-style.html', { timeout: 60000 }) .goto(server.PREFIX + '/one-style.html', {timeout: 60000})
.catch((error_) => { .catch(error_ => {
return error_; return error_;
}); });
await server.waitForRequest('/one-style.css'); await server.waitForRequest('/one-style.css');
@ -163,7 +163,7 @@ describe('Launcher specs', function () {
await browser.close(); await browser.close();
}); });
it('should reject waitForSelector when browser closes', async () => { it('should reject waitForSelector when browser closes', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
server.setRoute('/empty.html', () => {}); server.setRoute('/empty.html', () => {});
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
@ -172,8 +172,8 @@ describe('Launcher specs', function () {
}); });
const page = await remote.newPage(); const page = await remote.newPage();
const watchdog = page const watchdog = page
.waitForSelector('div', { timeout: 60000 }) .waitForSelector('div', {timeout: 60000})
.catch((error_) => { .catch(error_ => {
return error_; return error_;
}); });
remote.disconnect(); remote.disconnect();
@ -184,7 +184,7 @@ describe('Launcher specs', function () {
}); });
describe('Browser.close', function () { describe('Browser.close', function () {
it('should terminate network waiters', async () => { it('should terminate network waiters', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const remote = await puppeteer.connect({ const remote = await puppeteer.connect({
@ -192,10 +192,10 @@ describe('Launcher specs', function () {
}); });
const newPage = await remote.newPage(); const newPage = await remote.newPage();
const results = await Promise.all([ const results = await Promise.all([
newPage.waitForRequest(server.EMPTY_PAGE).catch((error) => { newPage.waitForRequest(server.EMPTY_PAGE).catch(error => {
return error; return error;
}), }),
newPage.waitForResponse(server.EMPTY_PAGE).catch((error) => { newPage.waitForResponse(server.EMPTY_PAGE).catch(error => {
return error; return error;
}), }),
browser.close(), browser.close(),
@ -210,7 +210,7 @@ describe('Launcher specs', function () {
}); });
describe('Puppeteer.launch', function () { describe('Puppeteer.launch', function () {
it('should reject all promises when browser is closed', async () => { it('should reject all promises when browser is closed', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const page = await browser.newPage(); const page = await browser.newPage();
let error!: Error; let error!: Error;
@ -218,7 +218,7 @@ describe('Launcher specs', function () {
.evaluate(() => { .evaluate(() => {
return new Promise(() => {}); return new Promise(() => {});
}) })
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
await browser.close(); await browser.close();
@ -226,22 +226,22 @@ describe('Launcher specs', function () {
expect(error.message).toContain('Protocol error'); expect(error.message).toContain('Protocol error');
}); });
it('should reject if executable path is invalid', async () => { it('should reject if executable path is invalid', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
let waitError!: Error; let waitError!: Error;
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
executablePath: 'random-invalid-path', executablePath: 'random-invalid-path',
}); });
await puppeteer.launch(options).catch((error) => { await puppeteer.launch(options).catch(error => {
return (waitError = error); return (waitError = error);
}); });
expect(waitError.message).toContain('Failed to launch'); expect(waitError.message).toContain('Failed to launch');
}); });
it('userDataDir option', async () => { it('userDataDir option', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER); const userDataDir = await mkdtempAsync(TMP_FOLDER);
const options = Object.assign({ userDataDir }, defaultBrowserOptions); const options = Object.assign({userDataDir}, defaultBrowserOptions);
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
// Open a page to make sure its functional. // Open a page to make sure its functional.
await browser.newPage(); await browser.newPage();
@ -252,7 +252,7 @@ describe('Launcher specs', function () {
await rmAsync(userDataDir).catch(() => {}); await rmAsync(userDataDir).catch(() => {});
}); });
itFirefoxOnly('userDataDir option restores preferences', async () => { itFirefoxOnly('userDataDir option restores preferences', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER); const userDataDir = await mkdtempAsync(TMP_FOLDER);
@ -260,7 +260,7 @@ describe('Launcher specs', function () {
const prefsJSContent = 'user_pref("browser.warnOnQuit", true)'; const prefsJSContent = 'user_pref("browser.warnOnQuit", true)';
await writeFileAsync(prefsJSPath, prefsJSContent); await writeFileAsync(prefsJSPath, prefsJSContent);
const options = Object.assign({ userDataDir }, defaultBrowserOptions); const options = Object.assign({userDataDir}, defaultBrowserOptions);
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
// Open a page to make sure its functional. // Open a page to make sure its functional.
await browser.newPage(); await browser.newPage();
@ -274,7 +274,7 @@ describe('Launcher specs', function () {
await rmAsync(userDataDir).catch(() => {}); await rmAsync(userDataDir).catch(() => {});
}); });
it('userDataDir argument', async () => { it('userDataDir argument', async () => {
const { isChrome, puppeteer, defaultBrowserOptions } = getTestState(); const {isChrome, puppeteer, defaultBrowserOptions} = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER); const userDataDir = await mkdtempAsync(TMP_FOLDER);
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, defaultBrowserOptions);
@ -298,7 +298,7 @@ describe('Launcher specs', function () {
await rmAsync(userDataDir).catch(() => {}); await rmAsync(userDataDir).catch(() => {});
}); });
itChromeOnly('userDataDir argument with non-existent dir', async () => { itChromeOnly('userDataDir argument with non-existent dir', async () => {
const { isChrome, puppeteer, defaultBrowserOptions } = getTestState(); const {isChrome, puppeteer, defaultBrowserOptions} = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER); const userDataDir = await mkdtempAsync(TMP_FOLDER);
await rmAsync(userDataDir); await rmAsync(userDataDir);
@ -323,10 +323,10 @@ describe('Launcher specs', function () {
await rmAsync(userDataDir).catch(() => {}); await rmAsync(userDataDir).catch(() => {});
}); });
it('userDataDir option should restore state', async () => { it('userDataDir option should restore state', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER); const userDataDir = await mkdtempAsync(TMP_FOLDER);
const options = Object.assign({ userDataDir }, defaultBrowserOptions); const options = Object.assign({userDataDir}, defaultBrowserOptions);
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -350,10 +350,10 @@ describe('Launcher specs', function () {
// This mysteriously fails on Windows on AppVeyor. See // This mysteriously fails on Windows on AppVeyor. See
// https://github.com/puppeteer/puppeteer/issues/4111 // https://github.com/puppeteer/puppeteer/issues/4111
xit('userDataDir option should restore cookies', async () => { xit('userDataDir option should restore cookies', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER); const userDataDir = await mkdtempAsync(TMP_FOLDER);
const options = Object.assign({ userDataDir }, defaultBrowserOptions); const options = Object.assign({userDataDir}, defaultBrowserOptions);
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -376,15 +376,15 @@ describe('Launcher specs', function () {
await rmAsync(userDataDir).catch(() => {}); await rmAsync(userDataDir).catch(() => {});
}); });
it('should return the default arguments', async () => { it('should return the default arguments', async () => {
const { isChrome, isFirefox, puppeteer } = getTestState(); const {isChrome, isFirefox, puppeteer} = getTestState();
if (isChrome) { if (isChrome) {
expect(puppeteer.defaultArgs()).toContain('--no-first-run'); expect(puppeteer.defaultArgs()).toContain('--no-first-run');
expect(puppeteer.defaultArgs()).toContain('--headless'); expect(puppeteer.defaultArgs()).toContain('--headless');
expect(puppeteer.defaultArgs({ headless: false })).not.toContain( expect(puppeteer.defaultArgs({headless: false})).not.toContain(
'--headless' '--headless'
); );
expect(puppeteer.defaultArgs({ userDataDir: 'foo' })).toContain( expect(puppeteer.defaultArgs({userDataDir: 'foo'})).toContain(
`--user-data-dir=${path.resolve('foo')}` `--user-data-dir=${path.resolve('foo')}`
); );
} else if (isFirefox) { } else if (isFirefox) {
@ -395,30 +395,28 @@ describe('Launcher specs', function () {
} else { } else {
expect(puppeteer.defaultArgs()).not.toContain('--foreground'); expect(puppeteer.defaultArgs()).not.toContain('--foreground');
} }
expect(puppeteer.defaultArgs({ headless: false })).not.toContain( expect(puppeteer.defaultArgs({headless: false})).not.toContain(
'--headless' '--headless'
); );
expect(puppeteer.defaultArgs({ userDataDir: 'foo' })).toContain( expect(puppeteer.defaultArgs({userDataDir: 'foo'})).toContain(
'--profile' '--profile'
); );
expect(puppeteer.defaultArgs({ userDataDir: 'foo' })).toContain( expect(puppeteer.defaultArgs({userDataDir: 'foo'})).toContain('foo');
'foo'
);
} else { } else {
expect(puppeteer.defaultArgs()).toContain('-headless'); expect(puppeteer.defaultArgs()).toContain('-headless');
expect(puppeteer.defaultArgs({ headless: false })).not.toContain( expect(puppeteer.defaultArgs({headless: false})).not.toContain(
'-headless' '-headless'
); );
expect(puppeteer.defaultArgs({ userDataDir: 'foo' })).toContain( expect(puppeteer.defaultArgs({userDataDir: 'foo'})).toContain(
'-profile' '-profile'
); );
expect(puppeteer.defaultArgs({ userDataDir: 'foo' })).toContain( expect(puppeteer.defaultArgs({userDataDir: 'foo'})).toContain(
path.resolve('foo') path.resolve('foo')
); );
} }
}); });
it('should report the correct product', async () => { it('should report the correct product', async () => {
const { isChrome, isFirefox, puppeteer } = getTestState(); const {isChrome, isFirefox, puppeteer} = getTestState();
if (isChrome) { if (isChrome) {
expect(puppeteer.product).toBe('chrome'); expect(puppeteer.product).toBe('chrome');
} else if (isFirefox) { } else if (isFirefox) {
@ -426,7 +424,7 @@ describe('Launcher specs', function () {
} }
}); });
it('should work with no default arguments', async () => { it('should work with no default arguments', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, defaultBrowserOptions);
options.ignoreDefaultArgs = true; options.ignoreDefaultArgs = true;
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
@ -438,7 +436,7 @@ describe('Launcher specs', function () {
itChromeOnly( itChromeOnly(
'should filter out ignored default arguments in Chrome', 'should filter out ignored default arguments in Chrome',
async () => { async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
// Make sure we launch with `--enable-automation` by default. // Make sure we launch with `--enable-automation` by default.
const defaultArgs = puppeteer.defaultArgs(); const defaultArgs = puppeteer.defaultArgs();
const browser = await puppeteer.launch( const browser = await puppeteer.launch(
@ -460,7 +458,7 @@ describe('Launcher specs', function () {
itFirefoxOnly( itFirefoxOnly(
'should filter out ignored default argument in Firefox', 'should filter out ignored default argument in Firefox',
async () => { async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const defaultArgs = puppeteer.defaultArgs(); const defaultArgs = puppeteer.defaultArgs();
const browser = await puppeteer.launch( const browser = await puppeteer.launch(
@ -479,9 +477,9 @@ describe('Launcher specs', function () {
} }
); );
it('should have default URL when launching browser', async function () { it('should have default URL when launching browser', async function () {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const pages = (await browser.pages()).map((page) => { const pages = (await browser.pages()).map(page => {
return page.url(); return page.url();
}); });
expect(pages).toEqual(['about:blank']); expect(pages).toEqual(['about:blank']);
@ -490,7 +488,7 @@ describe('Launcher specs', function () {
itFailsFirefox( itFailsFirefox(
'should have custom URL when launching browser', 'should have custom URL when launching browser',
async () => { async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, defaultBrowserOptions);
options.args = [server.EMPTY_PAGE].concat(options.args || []); options.args = [server.EMPTY_PAGE].concat(options.args || []);
@ -506,18 +504,18 @@ describe('Launcher specs', function () {
} }
); );
it('should pass the timeout parameter to browser.waitForTarget', async () => { it('should pass the timeout parameter to browser.waitForTarget', async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
timeout: 1, timeout: 1,
}); });
let error!: Error; let error!: Error;
await puppeteer.launch(options).catch((error_) => { await puppeteer.launch(options).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should set the default viewport', async () => { it('should set the default viewport', async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
defaultViewport: { defaultViewport: {
width: 456, width: 456,
@ -531,7 +529,7 @@ describe('Launcher specs', function () {
await browser.close(); await browser.close();
}); });
it('should disable the default viewport', async () => { it('should disable the default viewport', async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
defaultViewport: null, defaultViewport: null,
}); });
@ -541,7 +539,7 @@ describe('Launcher specs', function () {
await browser.close(); await browser.close();
}); });
it('should take fullPage screenshots when defaultViewport is null', async () => { it('should take fullPage screenshots when defaultViewport is null', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
defaultViewport: null, defaultViewport: null,
@ -556,7 +554,7 @@ describe('Launcher specs', function () {
await browser.close(); await browser.close();
}); });
it('should set the debugging port', async () => { it('should set the debugging port', async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
defaultViewport: null, defaultViewport: null,
@ -568,7 +566,7 @@ describe('Launcher specs', function () {
expect(url.port).toBe('9999'); expect(url.port).toBe('9999');
}); });
it('should not allow setting debuggingPort and pipe', async () => { it('should not allow setting debuggingPort and pipe', async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const options = Object.assign({}, defaultBrowserOptions, { const options = Object.assign({}, defaultBrowserOptions, {
defaultViewport: null, defaultViewport: null,
@ -577,7 +575,7 @@ describe('Launcher specs', function () {
}); });
let error!: Error; let error!: Error;
await puppeteer.launch(options).catch((error_) => { await puppeteer.launch(options).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('either pipe or debugging port'); expect(error.message).toContain('either pipe or debugging port');
@ -585,7 +583,7 @@ describe('Launcher specs', function () {
itChromeOnly( itChromeOnly(
'should launch Chrome properly with --no-startup-window and waitForInitialPage=false', 'should launch Chrome properly with --no-startup-window and waitForInitialPage=false',
async () => { async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const options = { const options = {
waitForInitialPage: false, waitForInitialPage: false,
// This is needed to prevent Puppeteer from adding an initial blank page. // This is needed to prevent Puppeteer from adding an initial blank page.
@ -606,12 +604,12 @@ describe('Launcher specs', function () {
let productName!: Product; let productName!: Product;
before(async () => { before(async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
productName = puppeteer._productName!; productName = puppeteer._productName!;
}); });
after(async () => { after(async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
// @ts-expect-error launcher is a private property that users can't // @ts-expect-error launcher is a private property that users can't
// touch, but for testing purposes we need to reset it. // touch, but for testing purposes we need to reset it.
puppeteer._lazyLauncher = undefined; puppeteer._lazyLauncher = undefined;
@ -619,8 +617,8 @@ describe('Launcher specs', function () {
}); });
itOnlyRegularInstall('should be able to launch Chrome', async () => { itOnlyRegularInstall('should be able to launch Chrome', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const browser = await puppeteer.launch({ product: 'chrome' }); const browser = await puppeteer.launch({product: 'chrome'});
const userAgent = await browser.userAgent(); const userAgent = await browser.userAgent();
await browser.close(); await browser.close();
expect(userAgent).toContain('Chrome'); expect(userAgent).toContain('Chrome');
@ -629,7 +627,7 @@ describe('Launcher specs', function () {
itOnlyRegularInstall( itOnlyRegularInstall(
'falls back to launching chrome if there is an unknown product but logs a warning', 'falls back to launching chrome if there is an unknown product but logs a warning',
async () => { async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const consoleStub = sinon.stub(console, 'warn'); const consoleStub = sinon.stub(console, 'warn');
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
// @ts-expect-error purposeful bad input // @ts-expect-error purposeful bad input
@ -649,8 +647,8 @@ describe('Launcher specs', function () {
'should be able to launch Firefox', 'should be able to launch Firefox',
async function () { async function () {
this.timeout(FIREFOX_TIMEOUT); this.timeout(FIREFOX_TIMEOUT);
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const browser = await puppeteer.launch({ product: 'firefox' }); const browser = await puppeteer.launch({product: 'firefox'});
const userAgent = await browser.userAgent(); const userAgent = await browser.userAgent();
await browser.close(); await browser.close();
expect(userAgent).toContain('Firefox'); expect(userAgent).toContain('Firefox');
@ -660,7 +658,7 @@ describe('Launcher specs', function () {
describe('Puppeteer.connect', function () { describe('Puppeteer.connect', function () {
it('should be able to connect multiple times to the same browser', async () => { it('should be able to connect multiple times to the same browser', async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const otherBrowser = await puppeteer.connect({ const otherBrowser = await puppeteer.connect({
@ -683,7 +681,7 @@ describe('Launcher specs', function () {
await originalBrowser.close(); await originalBrowser.close();
}); });
it('should be able to close remote browser', async () => { it('should be able to close remote browser', async () => {
const { defaultBrowserOptions, puppeteer } = getTestState(); const {defaultBrowserOptions, puppeteer} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const remoteBrowser = await puppeteer.connect({ const remoteBrowser = await puppeteer.connect({
@ -695,8 +693,7 @@ describe('Launcher specs', function () {
]); ]);
}); });
it('should support ignoreHTTPSErrors option', async () => { it('should support ignoreHTTPSErrors option', async () => {
const { httpsServer, puppeteer, defaultBrowserOptions } = const {httpsServer, puppeteer, defaultBrowserOptions} = getTestState();
getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
@ -709,7 +706,7 @@ describe('Launcher specs', function () {
let error!: Error; let error!: Error;
const [serverRequest, response] = await Promise.all([ const [serverRequest, response] = await Promise.all([
httpsServer.waitForRequest('/empty.html'), httpsServer.waitForRequest('/empty.html'),
page.goto(httpsServer.EMPTY_PAGE).catch((error_) => { page.goto(httpsServer.EMPTY_PAGE).catch(error_ => {
return (error = error_); return (error = error_);
}), }),
]); ]);
@ -725,7 +722,7 @@ describe('Launcher specs', function () {
}); });
// @see https://github.com/puppeteer/puppeteer/issues/4197 // @see https://github.com/puppeteer/puppeteer/issues/4197
itFailsFirefox('should support targetFilter option', async () => { itFailsFirefox('should support targetFilter option', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
@ -761,7 +758,7 @@ describe('Launcher specs', function () {
itFailsFirefox( itFailsFirefox(
'should be able to reconnect to a disconnected browser', 'should be able to reconnect to a disconnected browser',
async () => { async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
@ -769,9 +766,9 @@ describe('Launcher specs', function () {
await page.goto(server.PREFIX + '/frames/nested-frames.html'); await page.goto(server.PREFIX + '/frames/nested-frames.html');
originalBrowser.disconnect(); originalBrowser.disconnect();
const browser = await puppeteer.connect({ browserWSEndpoint }); const browser = await puppeteer.connect({browserWSEndpoint});
const pages = await browser.pages(); const pages = await browser.pages();
const restoredPage = pages.find((page) => { const restoredPage = pages.find(page => {
return page.url() === server.PREFIX + '/frames/nested-frames.html'; return page.url() === server.PREFIX + '/frames/nested-frames.html';
})!; })!;
expect(utils.dumpFrames(restoredPage.mainFrame())).toEqual([ expect(utils.dumpFrames(restoredPage.mainFrame())).toEqual([
@ -793,15 +790,15 @@ describe('Launcher specs', function () {
itFailsFirefox( itFailsFirefox(
'should be able to connect to the same page simultaneously', 'should be able to connect to the same page simultaneously',
async () => { async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const browserOne = await puppeteer.launch(defaultBrowserOptions); const browserOne = await puppeteer.launch(defaultBrowserOptions);
const browserTwo = await puppeteer.connect({ const browserTwo = await puppeteer.connect({
browserWSEndpoint: browserOne.wsEndpoint(), browserWSEndpoint: browserOne.wsEndpoint(),
}); });
const [page1, page2] = await Promise.all([ const [page1, page2] = await Promise.all([
new Promise<Page>((x) => { new Promise<Page>(x => {
return browserOne.once('targetcreated', (target) => { return browserOne.once('targetcreated', target => {
return x(target.page()); return x(target.page());
}); });
}), }),
@ -821,16 +818,16 @@ describe('Launcher specs', function () {
} }
); );
it('should be able to reconnect', async () => { it('should be able to reconnect', async () => {
const { puppeteer, server, defaultBrowserOptions } = getTestState(); const {puppeteer, server, defaultBrowserOptions} = getTestState();
const browserOne = await puppeteer.launch(defaultBrowserOptions); const browserOne = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = browserOne.wsEndpoint(); const browserWSEndpoint = browserOne.wsEndpoint();
const pageOne = await browserOne.newPage(); const pageOne = await browserOne.newPage();
await pageOne.goto(server.EMPTY_PAGE); await pageOne.goto(server.EMPTY_PAGE);
browserOne.disconnect(); browserOne.disconnect();
const browserTwo = await puppeteer.connect({ browserWSEndpoint }); const browserTwo = await puppeteer.connect({browserWSEndpoint});
const pages = await browserTwo.pages(); const pages = await browserTwo.pages();
const pageTwo = pages.find((page) => { const pageTwo = pages.find(page => {
return page.url() === server.EMPTY_PAGE; return page.url() === server.EMPTY_PAGE;
})!; })!;
await pageTwo.reload(); await pageTwo.reload();
@ -843,14 +840,14 @@ describe('Launcher specs', function () {
}); });
describe('Puppeteer.executablePath', function () { describe('Puppeteer.executablePath', function () {
itOnlyRegularInstall('should work', async () => { itOnlyRegularInstall('should work', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const executablePath = puppeteer.executablePath(); const executablePath = puppeteer.executablePath();
expect(fs.existsSync(executablePath)).toBe(true); expect(fs.existsSync(executablePath)).toBe(true);
expect(fs.realpathSync(executablePath)).toBe(executablePath); expect(fs.realpathSync(executablePath)).toBe(executablePath);
}); });
it('returns executablePath for channel', () => { it('returns executablePath for channel', () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const executablePath = puppeteer.executablePath('chrome'); const executablePath = puppeteer.executablePath('chrome');
expect(executablePath).toBeTruthy(); expect(executablePath).toBeTruthy();
@ -870,7 +867,7 @@ describe('Launcher specs', function () {
}); });
it('its value is returned', async () => { it('its value is returned', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const executablePath = puppeteer.executablePath(); const executablePath = puppeteer.executablePath();
@ -881,7 +878,7 @@ describe('Launcher specs', function () {
describe('when the product is chrome, platform is not darwin, and arch is arm64', () => { describe('when the product is chrome, platform is not darwin, and arch is arm64', () => {
describe('and the executable exists', () => { describe('and the executable exists', () => {
itChromeOnly('returns /usr/bin/chromium-browser', async () => { itChromeOnly('returns /usr/bin/chromium-browser', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const osPlatformStub = sinon.stub(os, 'platform').returns('linux'); const osPlatformStub = sinon.stub(os, 'platform').returns('linux');
const osArchStub = sinon.stub(os, 'arch').returns('arm64'); const osArchStub = sinon.stub(os, 'arch').returns('arm64');
const fsExistsStub = sinon.stub(fs, 'existsSync'); const fsExistsStub = sinon.stub(fs, 'existsSync');
@ -910,7 +907,7 @@ describe('Launcher specs', function () {
}); });
it('its value is returned', async () => { it('its value is returned', async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const executablePath = puppeteer.executablePath(); const executablePath = puppeteer.executablePath();
@ -922,7 +919,7 @@ describe('Launcher specs', function () {
itChromeOnly( itChromeOnly(
'does not return /usr/bin/chromium-browser', 'does not return /usr/bin/chromium-browser',
async () => { async () => {
const { puppeteer } = getTestState(); const {puppeteer} = getTestState();
const osPlatformStub = sinon const osPlatformStub = sinon
.stub(os, 'platform') .stub(os, 'platform')
.returns('linux'); .returns('linux');
@ -946,7 +943,7 @@ describe('Launcher specs', function () {
describe('Browser target events', function () { describe('Browser target events', function () {
itFailsFirefox('should work', async () => { itFailsFirefox('should work', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState(); const {server, puppeteer, defaultBrowserOptions} = getTestState();
const browser = await puppeteer.launch(defaultBrowserOptions); const browser = await puppeteer.launch(defaultBrowserOptions);
const events: string[] = []; const events: string[] = [];
@ -969,11 +966,11 @@ describe('Launcher specs', function () {
describe('Browser.Events.disconnected', function () { describe('Browser.Events.disconnected', function () {
it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async () => { it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async () => {
const { puppeteer, defaultBrowserOptions } = getTestState(); const {puppeteer, defaultBrowserOptions} = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions); const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint(); const browserWSEndpoint = originalBrowser.wsEndpoint();
const remoteBrowser1 = await puppeteer.connect({ browserWSEndpoint }); const remoteBrowser1 = await puppeteer.connect({browserWSEndpoint});
const remoteBrowser2 = await puppeteer.connect({ browserWSEndpoint }); const remoteBrowser2 = await puppeteer.connect({browserWSEndpoint});
let disconnectedOriginal = 0; let disconnectedOriginal = 0;
let disconnectedRemote1 = 0; let disconnectedRemote1 = 0;

View File

@ -25,15 +25,15 @@ import {
Browser, Browser,
BrowserContext, BrowserContext,
} from '../../lib/cjs/puppeteer/common/Browser.js'; } from '../../lib/cjs/puppeteer/common/Browser.js';
import { Page } from '../../lib/cjs/puppeteer/common/Page.js'; import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
import { isErrorLike } from '../../lib/cjs/puppeteer/common/util.js'; import {isErrorLike} from '../../lib/cjs/puppeteer/common/util.js';
import { import {
PuppeteerLaunchOptions, PuppeteerLaunchOptions,
PuppeteerNode, PuppeteerNode,
} from '../../lib/cjs/puppeteer/node/Puppeteer.js'; } from '../../lib/cjs/puppeteer/node/Puppeteer.js';
import puppeteer from '../../lib/cjs/puppeteer/puppeteer.js'; import puppeteer from '../../lib/cjs/puppeteer/puppeteer.js';
import { TestServer } from '../../utils/testserver/lib/index.js'; import {TestServer} from '../../utils/testserver/lib/index.js';
import { extendExpectWithToBeGolden } from './utils.js'; import {extendExpectWithToBeGolden} from './utils.js';
const setupServer = async () => { const setupServer = async () => {
const assetsPath = path.join(__dirname, '../assets'); const assetsPath = path.join(__dirname, '../assets');
@ -55,7 +55,7 @@ const setupServer = async () => {
httpsServer.CROSS_PROCESS_PREFIX = `https://127.0.0.1:${httpsPort}`; httpsServer.CROSS_PROCESS_PREFIX = `https://127.0.0.1:${httpsPort}`;
httpsServer.EMPTY_PAGE = `https://localhost:${httpsPort}/empty.html`; httpsServer.EMPTY_PAGE = `https://localhost:${httpsPort}/empty.html`;
return { server, httpsServer }; return {server, httpsServer};
}; };
export const getTestState = (): PuppeteerTestState => { export const getTestState = (): PuppeteerTestState => {
@ -259,7 +259,7 @@ console.log(
}` }`
); );
process.on('unhandledRejection', (reason) => { process.on('unhandledRejection', reason => {
throw reason; throw reason;
}); });
@ -291,7 +291,7 @@ export const setupTestPageAndContextHooks = (): void => {
export const mochaHooks = { export const mochaHooks = {
beforeAll: [ beforeAll: [
async (): Promise<void> => { async (): Promise<void> => {
const { server, httpsServer } = await setupServer(); const {server, httpsServer} = await setupServer();
state.puppeteer = puppeteer; state.puppeteer = puppeteer;
state.defaultBrowserOptions = defaultBrowserOptions; state.defaultBrowserOptions = defaultBrowserOptions;
@ -328,10 +328,10 @@ export const expectCookieEquals = (
cookies: Protocol.Network.Cookie[], cookies: Protocol.Network.Cookie[],
expectedCookies: Array<Partial<Protocol.Network.Cookie>> expectedCookies: Array<Partial<Protocol.Network.Cookie>>
): void => { ): void => {
const { isChrome } = getTestState(); const {isChrome} = getTestState();
if (!isChrome) { if (!isChrome) {
// Only keep standard properties when testing on a browser other than Chrome. // Only keep standard properties when testing on a browser other than Chrome.
expectedCookies = expectedCookies.map((cookie) => { expectedCookies = expectedCookies.map(cookie => {
return { return {
domain: cookie.domain, domain: cookie.domain,
expires: cookie.expires, expires: cookie.expires,
@ -359,7 +359,7 @@ export const shortWaitForArrayToHaveAtLeastNElements = async (
if (data.length >= minLength) { if (data.length >= minLength) {
break; break;
} }
await new Promise((resolve) => { await new Promise(resolve => {
return setTimeout(resolve, timeout); return setTimeout(resolve, timeout);
}); });
} }

View File

@ -21,7 +21,7 @@ import {
setupTestPageAndContextHooks, setupTestPageAndContextHooks,
itFailsFirefox, itFailsFirefox,
} from './mocha-utils.js'; } from './mocha-utils.js';
import { KeyInput } from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js'; import {KeyInput} from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js';
interface Dimensions { interface Dimensions {
x: number; x: number;
@ -44,11 +44,11 @@ describe('Mouse', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
it('should click the document', async () => { it('should click the document', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.evaluate(() => { await page.evaluate(() => {
(globalThis as any).clickPromise = new Promise((resolve) => { (globalThis as any).clickPromise = new Promise(resolve => {
document.addEventListener('click', (event) => { document.addEventListener('click', event => {
resolve({ resolve({
type: event.type, type: event.type,
detail: event.detail, detail: event.detail,
@ -72,10 +72,10 @@ describe('Mouse', function () {
expect(event.button).toBe(0); expect(event.button).toBe(0);
}); });
it('should resize the textarea', async () => { it('should resize the textarea', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
const { x, y, width, height } = await page.evaluate<() => Dimensions>( const {x, y, width, height} = await page.evaluate<() => Dimensions>(
dimensions dimensions
); );
const mouse = page.mouse; const mouse = page.mouse;
@ -88,7 +88,7 @@ describe('Mouse', function () {
expect(newDimensions.height).toBe(Math.round(height + 104)); expect(newDimensions.height).toBe(Math.round(height + 104));
}); });
it('should select the text with mouse', async () => { it('should select the text with mouse', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
@ -102,7 +102,7 @@ describe('Mouse', function () {
await page.evaluate(() => { await page.evaluate(() => {
return (document.querySelector('textarea')!.scrollTop = 0); return (document.querySelector('textarea')!.scrollTop = 0);
}); });
const { x, y } = await page.evaluate(dimensions); const {x, y} = await page.evaluate(dimensions);
await page.mouse.move(x + 2, y + 2); await page.mouse.move(x + 2, y + 2);
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(100, 100); await page.mouse.move(100, 100);
@ -118,7 +118,7 @@ describe('Mouse', function () {
).toBe(text); ).toBe(text);
}); });
itFailsFirefox('should trigger hover state', async () => { itFailsFirefox('should trigger hover state', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.hover('#button-6'); await page.hover('#button-6');
@ -143,7 +143,7 @@ describe('Mouse', function () {
itFailsFirefox( itFailsFirefox(
'should trigger hover state with removed window.Node', 'should trigger hover state with removed window.Node',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.evaluate(() => { await page.evaluate(() => {
@ -159,13 +159,13 @@ describe('Mouse', function () {
} }
); );
it('should set modifier keys on click', async () => { it('should set modifier keys on click', async () => {
const { page, server, isFirefox } = getTestState(); const {page, server, isFirefox} = getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.evaluate(() => { await page.evaluate(() => {
return document.querySelector('#button-3')!.addEventListener( return document.querySelector('#button-3')!.addEventListener(
'mousedown', 'mousedown',
(e) => { e => {
return ((globalThis as any).lastEvent = e); return ((globalThis as any).lastEvent = e);
}, },
true true
@ -205,7 +205,7 @@ describe('Mouse', function () {
} }
}); });
itFailsFirefox('should send mouse wheel events', async () => { itFailsFirefox('should send mouse wheel events', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/input/wheel.html'); await page.goto(server.PREFIX + '/input/wheel.html');
const elem = (await page.$('div'))!; const elem = (await page.$('div'))!;
@ -220,7 +220,7 @@ describe('Mouse', function () {
boundingBoxBefore.y + boundingBoxBefore.height / 2 boundingBoxBefore.y + boundingBoxBefore.height / 2
); );
await page.mouse.wheel({ deltaY: -100 }); await page.mouse.wheel({deltaY: -100});
const boundingBoxAfter = await elem.boundingBox(); const boundingBoxAfter = await elem.boundingBox();
expect(boundingBoxAfter).toMatchObject({ expect(boundingBoxAfter).toMatchObject({
width: 230, width: 230,
@ -228,16 +228,16 @@ describe('Mouse', function () {
}); });
}); });
itFailsFirefox('should tween mouse movement', async () => { itFailsFirefox('should tween mouse movement', async () => {
const { page } = getTestState(); const {page} = getTestState();
await page.mouse.move(100, 100); await page.mouse.move(100, 100);
await page.evaluate(() => { await page.evaluate(() => {
(globalThis as any).result = []; (globalThis as any).result = [];
document.addEventListener('mousemove', (event) => { document.addEventListener('mousemove', event => {
(globalThis as any).result.push([event.clientX, event.clientY]); (globalThis as any).result.push([event.clientX, event.clientY]);
}); });
}); });
await page.mouse.move(200, 300, { steps: 5 }); await page.mouse.move(200, 300, {steps: 5});
expect(await page.evaluate('result')).toEqual([ expect(await page.evaluate('result')).toEqual([
[120, 140], [120, 140],
[140, 180], [140, 180],
@ -248,19 +248,19 @@ describe('Mouse', function () {
}); });
// @see https://crbug.com/929806 // @see https://crbug.com/929806
it('should work with mobile viewports and cross process navigations', async () => { it('should work with mobile viewports and cross process navigations', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setViewport({ width: 360, height: 640, isMobile: true }); await page.setViewport({width: 360, height: 640, isMobile: true});
await page.goto(server.CROSS_PROCESS_PREFIX + '/mobile.html'); await page.goto(server.CROSS_PROCESS_PREFIX + '/mobile.html');
await page.evaluate(() => { await page.evaluate(() => {
document.addEventListener('click', (event) => { document.addEventListener('click', event => {
(globalThis as any).result = { x: event.clientX, y: event.clientY }; (globalThis as any).result = {x: event.clientX, y: event.clientY};
}); });
}); });
await page.mouse.click(30, 40); await page.mouse.click(30, 40);
expect(await page.evaluate('result')).toEqual({ x: 30, y: 40 }); expect(await page.evaluate('result')).toEqual({x: 30, y: 40});
}); });
}); });

View File

@ -24,21 +24,21 @@ import {
describeFailsFirefox, describeFailsFirefox,
} from './mocha-utils.js'; } from './mocha-utils.js';
import os from 'os'; import os from 'os';
import { ServerResponse } from 'http'; import {ServerResponse} from 'http';
import { HTTPRequest } from '../../lib/cjs/puppeteer/common/HTTPRequest.js'; import {HTTPRequest} from '../../lib/cjs/puppeteer/common/HTTPRequest.js';
describe('navigation', function () { describe('navigation', function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
setupTestPageAndContextHooks(); setupTestPageAndContextHooks();
describe('Page.goto', function () { describe('Page.goto', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
expect(page.url()).toBe(server.EMPTY_PAGE); expect(page.url()).toBe(server.EMPTY_PAGE);
}); });
it('should work with anchor navigation', async () => { it('should work with anchor navigation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
expect(page.url()).toBe(server.EMPTY_PAGE); expect(page.url()).toBe(server.EMPTY_PAGE);
@ -48,7 +48,7 @@ describe('navigation', function () {
expect(page.url()).toBe(server.EMPTY_PAGE + '#bar'); expect(page.url()).toBe(server.EMPTY_PAGE + '#bar');
}); });
it('should work with redirects', async () => { it('should work with redirects', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setRedirect('/redirect/1.html', '/redirect/2.html'); server.setRedirect('/redirect/1.html', '/redirect/2.html');
server.setRedirect('/redirect/2.html', '/empty.html'); server.setRedirect('/redirect/2.html', '/empty.html');
@ -56,19 +56,19 @@ describe('navigation', function () {
expect(page.url()).toBe(server.EMPTY_PAGE); expect(page.url()).toBe(server.EMPTY_PAGE);
}); });
it('should navigate to about:blank', async () => { it('should navigate to about:blank', async () => {
const { page } = getTestState(); const {page} = getTestState();
const response = await page.goto('about:blank'); const response = await page.goto('about:blank');
expect(response).toBe(null); expect(response).toBe(null);
}); });
it('should return response when page changes its URL after load', async () => { it('should return response when page changes its URL after load', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const response = (await page.goto(server.PREFIX + '/historyapi.html'))!; const response = (await page.goto(server.PREFIX + '/historyapi.html'))!;
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
}); });
itFailsFirefox('should work with subframes return 204', async () => { itFailsFirefox('should work with subframes return 204', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setRoute('/frames/frame.html', (_req, res) => { server.setRoute('/frames/frame.html', (_req, res) => {
res.statusCode = 204; res.statusCode = 204;
@ -77,20 +77,20 @@ describe('navigation', function () {
let error!: Error; let error!: Error;
await page await page
.goto(server.PREFIX + '/frames/one-frame.html') .goto(server.PREFIX + '/frames/one-frame.html')
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeUndefined(); expect(error).toBeUndefined();
}); });
itFailsFirefox('should fail when server returns 204', async () => { itFailsFirefox('should fail when server returns 204', async () => {
const { page, server, isChrome } = getTestState(); const {page, server, isChrome} = getTestState();
server.setRoute('/empty.html', (_req, res) => { server.setRoute('/empty.html', (_req, res) => {
res.statusCode = 204; res.statusCode = 204;
res.end(); res.end();
}); });
let error!: Error; let error!: Error;
await page.goto(server.EMPTY_PAGE).catch((error_) => { await page.goto(server.EMPTY_PAGE).catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).not.toBe(null); expect(error).not.toBe(null);
@ -101,7 +101,7 @@ describe('navigation', function () {
} }
}); });
it('should navigate to empty page with domcontentloaded', async () => { it('should navigate to empty page with domcontentloaded', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const response = await page.goto(server.EMPTY_PAGE, { const response = await page.goto(server.EMPTY_PAGE, {
waitUntil: 'domcontentloaded', waitUntil: 'domcontentloaded',
@ -109,7 +109,7 @@ describe('navigation', function () {
expect(response!.status()).toBe(200); expect(response!.status()).toBe(200);
}); });
it('should work when page calls history API in beforeunload', async () => { it('should work when page calls history API in beforeunload', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {
@ -127,7 +127,7 @@ describe('navigation', function () {
itFailsFirefox( itFailsFirefox(
'should navigate to empty page with networkidle0', 'should navigate to empty page with networkidle0',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const response = await page.goto(server.EMPTY_PAGE, { const response = await page.goto(server.EMPTY_PAGE, {
waitUntil: 'networkidle0', waitUntil: 'networkidle0',
@ -138,7 +138,7 @@ describe('navigation', function () {
itFailsFirefox( itFailsFirefox(
'should navigate to empty page with networkidle2', 'should navigate to empty page with networkidle2',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const response = await page.goto(server.EMPTY_PAGE, { const response = await page.goto(server.EMPTY_PAGE, {
waitUntil: 'networkidle2', waitUntil: 'networkidle2',
@ -147,10 +147,10 @@ describe('navigation', function () {
} }
); );
itFailsFirefox('should fail when navigating to bad url', async () => { itFailsFirefox('should fail when navigating to bad url', async () => {
const { page, isChrome } = getTestState(); const {page, isChrome} = getTestState();
let error!: Error; let error!: Error;
await page.goto('asdfasdf').catch((error_) => { await page.goto('asdfasdf').catch(error_ => {
return (error = error_); return (error = error_);
}); });
if (isChrome) { if (isChrome) {
@ -171,7 +171,7 @@ describe('navigation', function () {
: 'net::ERR_CERT_AUTHORITY_INVALID'; : 'net::ERR_CERT_AUTHORITY_INVALID';
itFailsFirefox('should fail when navigating to bad SSL', async () => { itFailsFirefox('should fail when navigating to bad SSL', async () => {
const { page, httpsServer, isChrome } = getTestState(); const {page, httpsServer, isChrome} = getTestState();
// Make sure that network events do not emit 'undefined'. // Make sure that network events do not emit 'undefined'.
// @see https://crbug.com/750469 // @see https://crbug.com/750469
@ -187,7 +187,7 @@ describe('navigation', function () {
}); });
let error!: Error; let error!: Error;
await page.goto(httpsServer.EMPTY_PAGE).catch((error_) => { await page.goto(httpsServer.EMPTY_PAGE).catch(error_ => {
return (error = error_); return (error = error_);
}); });
if (isChrome) { if (isChrome) {
@ -201,16 +201,14 @@ describe('navigation', function () {
expect(requests[1]!).toBe('requestfailed'); expect(requests[1]!).toBe('requestfailed');
}); });
it('should fail when navigating to bad SSL after redirects', async () => { it('should fail when navigating to bad SSL after redirects', async () => {
const { page, server, httpsServer, isChrome } = getTestState(); const {page, server, httpsServer, isChrome} = getTestState();
server.setRedirect('/redirect/1.html', '/redirect/2.html'); server.setRedirect('/redirect/1.html', '/redirect/2.html');
server.setRedirect('/redirect/2.html', '/empty.html'); server.setRedirect('/redirect/2.html', '/empty.html');
let error!: Error; let error!: Error;
await page await page.goto(httpsServer.PREFIX + '/redirect/1.html').catch(error_ => {
.goto(httpsServer.PREFIX + '/redirect/1.html') return (error = error_);
.catch((error_) => { });
return (error = error_);
});
if (isChrome) { if (isChrome) {
expect(error.message).toContain(EXPECTED_SSL_CERT_MESSAGE); expect(error.message).toContain(EXPECTED_SSL_CERT_MESSAGE);
} else { } else {
@ -218,13 +216,13 @@ describe('navigation', function () {
} }
}); });
it('should throw if networkidle is passed as an option', async () => { it('should throw if networkidle is passed as an option', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let error!: Error; let error!: Error;
await page await page
// @ts-expect-error purposefully passing an old option // @ts-expect-error purposefully passing an old option
.goto(server.EMPTY_PAGE, { waitUntil: 'networkidle' }) .goto(server.EMPTY_PAGE, {waitUntil: 'networkidle'})
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain( expect(error.message).toContain(
@ -232,12 +230,12 @@ describe('navigation', function () {
); );
}); });
it('should fail when main resources failed to load', async () => { it('should fail when main resources failed to load', async () => {
const { page, isChrome } = getTestState(); const {page, isChrome} = getTestState();
let error!: Error; let error!: Error;
await page await page
.goto('http://localhost:44123/non-existing-url') .goto('http://localhost:44123/non-existing-url')
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
if (isChrome) { if (isChrome) {
@ -247,61 +245,61 @@ describe('navigation', function () {
} }
}); });
it('should fail when exceeding maximum navigation timeout', async () => { it('should fail when exceeding maximum navigation timeout', async () => {
const { page, server, puppeteer } = getTestState(); const {page, server, puppeteer} = getTestState();
// Hang for request to the empty.html // Hang for request to the empty.html
server.setRoute('/empty.html', () => {}); server.setRoute('/empty.html', () => {});
let error!: Error; let error!: Error;
await page await page
.goto(server.PREFIX + '/empty.html', { timeout: 1 }) .goto(server.PREFIX + '/empty.html', {timeout: 1})
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('Navigation timeout of 1 ms exceeded'); expect(error.message).toContain('Navigation timeout of 1 ms exceeded');
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should fail when exceeding default maximum navigation timeout', async () => { it('should fail when exceeding default maximum navigation timeout', async () => {
const { page, server, puppeteer } = getTestState(); const {page, server, puppeteer} = getTestState();
// Hang for request to the empty.html // Hang for request to the empty.html
server.setRoute('/empty.html', () => {}); server.setRoute('/empty.html', () => {});
let error!: Error; let error!: Error;
page.setDefaultNavigationTimeout(1); page.setDefaultNavigationTimeout(1);
await page.goto(server.PREFIX + '/empty.html').catch((error_) => { await page.goto(server.PREFIX + '/empty.html').catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('Navigation timeout of 1 ms exceeded'); expect(error.message).toContain('Navigation timeout of 1 ms exceeded');
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should fail when exceeding default maximum timeout', async () => { it('should fail when exceeding default maximum timeout', async () => {
const { page, server, puppeteer } = getTestState(); const {page, server, puppeteer} = getTestState();
// Hang for request to the empty.html // Hang for request to the empty.html
server.setRoute('/empty.html', () => {}); server.setRoute('/empty.html', () => {});
let error!: Error; let error!: Error;
page.setDefaultTimeout(1); page.setDefaultTimeout(1);
await page.goto(server.PREFIX + '/empty.html').catch((error_) => { await page.goto(server.PREFIX + '/empty.html').catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('Navigation timeout of 1 ms exceeded'); expect(error.message).toContain('Navigation timeout of 1 ms exceeded');
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should prioritize default navigation timeout over default timeout', async () => { it('should prioritize default navigation timeout over default timeout', async () => {
const { page, server, puppeteer } = getTestState(); const {page, server, puppeteer} = getTestState();
// Hang for request to the empty.html // Hang for request to the empty.html
server.setRoute('/empty.html', () => {}); server.setRoute('/empty.html', () => {});
let error!: Error; let error!: Error;
page.setDefaultTimeout(0); page.setDefaultTimeout(0);
page.setDefaultNavigationTimeout(1); page.setDefaultNavigationTimeout(1);
await page.goto(server.PREFIX + '/empty.html').catch((error_) => { await page.goto(server.PREFIX + '/empty.html').catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error.message).toContain('Navigation timeout of 1 ms exceeded'); expect(error.message).toContain('Navigation timeout of 1 ms exceeded');
expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError);
}); });
it('should disable timeout when its set to 0', async () => { it('should disable timeout when its set to 0', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let error!: Error; let error!: Error;
let loaded = false; let loaded = false;
@ -309,34 +307,34 @@ describe('navigation', function () {
return (loaded = true); return (loaded = true);
}); });
await page await page
.goto(server.PREFIX + '/grid.html', { timeout: 0, waitUntil: ['load'] }) .goto(server.PREFIX + '/grid.html', {timeout: 0, waitUntil: ['load']})
.catch((error_) => { .catch(error_ => {
return (error = error_); return (error = error_);
}); });
expect(error).toBeUndefined(); expect(error).toBeUndefined();
expect(loaded).toBe(true); expect(loaded).toBe(true);
}); });
it('should work when navigating to valid url', async () => { it('should work when navigating to valid url', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const response = (await page.goto(server.EMPTY_PAGE))!; const response = (await page.goto(server.EMPTY_PAGE))!;
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
}); });
itFailsFirefox('should work when navigating to data url', async () => { itFailsFirefox('should work when navigating to data url', async () => {
const { page } = getTestState(); const {page} = getTestState();
const response = (await page.goto('data:text/html,hello'))!; const response = (await page.goto('data:text/html,hello'))!;
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
}); });
it('should work when navigating to 404', async () => { it('should work when navigating to 404', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const response = (await page.goto(server.PREFIX + '/not-found'))!; const response = (await page.goto(server.PREFIX + '/not-found'))!;
expect(response.ok()).toBe(false); expect(response.ok()).toBe(false);
expect(response.status()).toBe(404); expect(response.status()).toBe(404);
}); });
it('should return last response in redirect chain', async () => { it('should return last response in redirect chain', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setRedirect('/redirect/1.html', '/redirect/2.html'); server.setRedirect('/redirect/1.html', '/redirect/2.html');
server.setRedirect('/redirect/2.html', '/redirect/3.html'); server.setRedirect('/redirect/2.html', '/redirect/3.html');
@ -348,7 +346,7 @@ describe('navigation', function () {
itFailsFirefox( itFailsFirefox(
'should wait for network idle to succeed navigation', 'should wait for network idle to succeed navigation',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let responses: ServerResponse[] = []; let responses: ServerResponse[] = [];
// Hold on to a bunch of requests without answering. // Hold on to a bunch of requests without answering.
@ -388,7 +386,7 @@ describe('navigation', function () {
}); });
// Wait for the page's 'load' event. // Wait for the page's 'load' event.
await new Promise((fulfill) => { await new Promise(fulfill => {
return page.once('load', fulfill); return page.once('load', fulfill);
}); });
expect(navigationFinished).toBe(false); expect(navigationFinished).toBe(false);
@ -425,10 +423,10 @@ describe('navigation', function () {
} }
); );
it('should not leak listeners during navigation', async () => { it('should not leak listeners during navigation', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let warning = null; let warning = null;
const warningHandler: NodeJS.WarningListener = (w) => { const warningHandler: NodeJS.WarningListener = w => {
return (warning = w); return (warning = w);
}; };
process.on('warning', warningHandler); process.on('warning', warningHandler);
@ -439,10 +437,10 @@ describe('navigation', function () {
expect(warning).toBe(null); expect(warning).toBe(null);
}); });
it('should not leak listeners during bad navigation', async () => { it('should not leak listeners during bad navigation', async () => {
const { page } = getTestState(); const {page} = getTestState();
let warning = null; let warning = null;
const warningHandler: NodeJS.WarningListener = (w) => { const warningHandler: NodeJS.WarningListener = w => {
return (warning = w); return (warning = w);
}; };
process.on('warning', warningHandler); process.on('warning', warningHandler);
@ -455,10 +453,10 @@ describe('navigation', function () {
expect(warning).toBe(null); expect(warning).toBe(null);
}); });
it('should not leak listeners during navigation of 11 pages', async () => { it('should not leak listeners during navigation of 11 pages', async () => {
const { context, server } = getTestState(); const {context, server} = getTestState();
let warning = null; let warning = null;
const warningHandler: NodeJS.WarningListener = (w) => { const warningHandler: NodeJS.WarningListener = w => {
return (warning = w); return (warning = w);
}; };
process.on('warning', warningHandler); process.on('warning', warningHandler);
@ -475,10 +473,10 @@ describe('navigation', function () {
itFailsFirefox( itFailsFirefox(
'should navigate to dataURL and fire dataURL requests', 'should navigate to dataURL and fire dataURL requests',
async () => { async () => {
const { page } = getTestState(); const {page} = getTestState();
const requests: HTTPRequest[] = []; const requests: HTTPRequest[] = [];
page.on('request', (request) => { page.on('request', request => {
return !utils.isFavicon(request) && requests.push(request); return !utils.isFavicon(request) && requests.push(request);
}); });
const dataURL = 'data:text/html,<div>yo</div>'; const dataURL = 'data:text/html,<div>yo</div>';
@ -491,10 +489,10 @@ describe('navigation', function () {
itFailsFirefox( itFailsFirefox(
'should navigate to URL with hash and fire requests without hash', 'should navigate to URL with hash and fire requests without hash',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const requests: HTTPRequest[] = []; const requests: HTTPRequest[] = [];
page.on('request', (request) => { page.on('request', request => {
return !utils.isFavicon(request) && requests.push(request); return !utils.isFavicon(request) && requests.push(request);
}); });
const response = (await page.goto(server.EMPTY_PAGE + '#hash'))!; const response = (await page.goto(server.EMPTY_PAGE + '#hash'))!;
@ -505,14 +503,14 @@ describe('navigation', function () {
} }
); );
it('should work with self requesting page', async () => { it('should work with self requesting page', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const response = (await page.goto(server.PREFIX + '/self-request.html'))!; const response = (await page.goto(server.PREFIX + '/self-request.html'))!;
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
expect(response.url()).toContain('self-request.html'); expect(response.url()).toContain('self-request.html');
}); });
it('should fail when navigating and show the url at the error message', async () => { it('should fail when navigating and show the url at the error message', async () => {
const { page, httpsServer } = getTestState(); const {page, httpsServer} = getTestState();
const url = httpsServer.PREFIX + '/redirect/1.html'; const url = httpsServer.PREFIX + '/redirect/1.html';
let error!: Error; let error!: Error;
@ -524,7 +522,7 @@ describe('navigation', function () {
expect(error.message).toContain(url); expect(error.message).toContain(url);
}); });
itFailsFirefox('should send referer', async () => { itFailsFirefox('should send referer', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
const [request1, request2] = await Promise.all([ const [request1, request2] = await Promise.all([
server.waitForRequest('/grid.html'), server.waitForRequest('/grid.html'),
@ -541,7 +539,7 @@ describe('navigation', function () {
describe('Page.waitForNavigation', function () { describe('Page.waitForNavigation', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const [response] = await Promise.all([ const [response] = await Promise.all([
@ -554,7 +552,7 @@ describe('navigation', function () {
expect(response!.url()).toContain('grid.html'); expect(response!.url()).toContain('grid.html');
}); });
it('should work with both domcontentloaded and load', async () => { it('should work with both domcontentloaded and load', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
let response!: ServerResponse; let response!: ServerResponse;
server.setRoute('/one-style.css', (_req, res) => { server.setRoute('/one-style.css', (_req, res) => {
@ -582,7 +580,7 @@ describe('navigation', function () {
await navigationPromise; await navigationPromise;
}); });
it('should work with clicking on anchor links', async () => { it('should work with clicking on anchor links', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setContent(`<a href='#foobar'>foobar</a>`); await page.setContent(`<a href='#foobar'>foobar</a>`);
@ -594,7 +592,7 @@ describe('navigation', function () {
expect(page.url()).toBe(server.EMPTY_PAGE + '#foobar'); expect(page.url()).toBe(server.EMPTY_PAGE + '#foobar');
}); });
itFailsFirefox('should work with history.pushState()', async () => { itFailsFirefox('should work with history.pushState()', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setContent(` await page.setContent(`
@ -611,7 +609,7 @@ describe('navigation', function () {
expect(page.url()).toBe(server.PREFIX + '/wow.html'); expect(page.url()).toBe(server.PREFIX + '/wow.html');
}); });
itFailsFirefox('should work with history.replaceState()', async () => { itFailsFirefox('should work with history.replaceState()', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setContent(` await page.setContent(`
@ -630,7 +628,7 @@ describe('navigation', function () {
itFailsFirefox( itFailsFirefox(
'should work with DOM history.back()/history.forward()', 'should work with DOM history.back()/history.forward()',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setContent(` await page.setContent(`
@ -661,15 +659,15 @@ describe('navigation', function () {
itFailsFirefox( itFailsFirefox(
'should work when subframe issues window.stop()', 'should work when subframe issues window.stop()',
async () => { async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
server.setRoute('/frames/style.css', () => {}); server.setRoute('/frames/style.css', () => {});
const navigationPromise = page.goto( const navigationPromise = page.goto(
server.PREFIX + '/frames/one-frame.html' server.PREFIX + '/frames/one-frame.html'
); );
const frame = await utils.waitEvent(page, 'frameattached'); const frame = await utils.waitEvent(page, 'frameattached');
await new Promise<void>((fulfill) => { await new Promise<void>(fulfill => {
page.on('framenavigated', (f) => { page.on('framenavigated', f => {
if (f === frame) { if (f === frame) {
fulfill(); fulfill();
} }
@ -687,7 +685,7 @@ describe('navigation', function () {
describe('Page.goBack', function () { describe('Page.goBack', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
@ -704,7 +702,7 @@ describe('navigation', function () {
expect(response).toBe(null); expect(response).toBe(null);
}); });
itFailsFirefox('should work with HistoryAPI', async () => { itFailsFirefox('should work with HistoryAPI', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {
@ -724,7 +722,7 @@ describe('navigation', function () {
describeFailsFirefox('Frame.goto', function () { describeFailsFirefox('Frame.goto', function () {
it('should navigate subframes', async () => { it('should navigate subframes', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/frames/one-frame.html'); await page.goto(server.PREFIX + '/frames/one-frame.html');
expect(page.frames()[0]!.url()).toContain('/frames/one-frame.html'); expect(page.frames()[0]!.url()).toContain('/frames/one-frame.html');
@ -735,7 +733,7 @@ describe('navigation', function () {
expect(response.frame()).toBe(page.frames()[1]!); expect(response.frame()).toBe(page.frames()[1]!);
}); });
it('should reject when frame detaches', async () => { it('should reject when frame detaches', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/frames/one-frame.html'); await page.goto(server.PREFIX + '/frames/one-frame.html');
@ -743,19 +741,19 @@ describe('navigation', function () {
const navigationPromise = page const navigationPromise = page
.frames()[1]! .frames()[1]!
.goto(server.EMPTY_PAGE) .goto(server.EMPTY_PAGE)
.catch((error_) => { .catch(error_ => {
return error_; return error_;
}); });
await server.waitForRequest('/empty.html'); await server.waitForRequest('/empty.html');
await page.$eval('iframe', (frame) => { await page.$eval('iframe', frame => {
return frame.remove(); return frame.remove();
}); });
const error = await navigationPromise; const error = await navigationPromise;
expect(error.message).toBe('Navigating frame was detached'); expect(error.message).toBe('Navigating frame was detached');
}); });
it('should return matching responses', async () => { it('should return matching responses', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
// Disable cache: otherwise, chromium will cache similar requests. // Disable cache: otherwise, chromium will cache similar requests.
await page.setCacheEnabled(false); await page.setCacheEnabled(false);
@ -789,7 +787,7 @@ describe('navigation', function () {
describeFailsFirefox('Frame.waitForNavigation', function () { describeFailsFirefox('Frame.waitForNavigation', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/frames/one-frame.html'); await page.goto(server.PREFIX + '/frames/one-frame.html');
const frame = page.frames()[1]!; const frame = page.frames()[1]!;
@ -805,14 +803,14 @@ describe('navigation', function () {
expect(page.url()).toContain('/frames/one-frame.html'); expect(page.url()).toContain('/frames/one-frame.html');
}); });
it('should fail when frame detaches', async () => { it('should fail when frame detaches', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.PREFIX + '/frames/one-frame.html'); await page.goto(server.PREFIX + '/frames/one-frame.html');
const frame = page.frames()[1]!; const frame = page.frames()[1]!;
server.setRoute('/empty.html', () => {}); server.setRoute('/empty.html', () => {});
let error!: Error; let error!: Error;
const navigationPromise = frame.waitForNavigation().catch((error_) => { const navigationPromise = frame.waitForNavigation().catch(error_ => {
return (error = error_); return (error = error_);
}); });
await Promise.all([ await Promise.all([
@ -821,7 +819,7 @@ describe('navigation', function () {
return ((window as any).location = '/empty.html'); return ((window as any).location = '/empty.html');
}), }),
]); ]);
await page.$eval('iframe', (frame) => { await page.$eval('iframe', frame => {
return frame.remove(); return frame.remove();
}); });
await navigationPromise; await navigationPromise;
@ -831,7 +829,7 @@ describe('navigation', function () {
describe('Page.reload', function () { describe('Page.reload', function () {
it('should work', async () => { it('should work', async () => {
const { page, server } = getTestState(); const {page, server} = getTestState();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => { await page.evaluate(() => {

Some files were not shown because too many files have changed in this diff Show More