mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: use Google's TS style guide's format config (#8542)
This commit is contained in:
parent
3744c2f584
commit
84712cbc28
@ -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
1
.prettierrc.cjs
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('gts/.prettierrc.json');
|
14
README.md
14
README.md
@ -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:
|
||||||
|
@ -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};
|
||||||
|
@ -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};
|
||||||
|
213
docs/api.md
213
docs/api.md
@ -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({
|
||||||
|
@ -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();
|
||||||
})();
|
})();
|
||||||
|
@ -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}`;
|
||||||
});
|
});
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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(() => {
|
||||||
|
@ -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:
|
||||||
|
@ -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();
|
||||||
})();
|
})();
|
||||||
|
@ -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();
|
||||||
})();
|
})();
|
||||||
|
@ -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}`;
|
||||||
});
|
});
|
||||||
|
@ -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",
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
semi: true,
|
|
||||||
trailingComma: 'es5',
|
|
||||||
singleQuote: true,
|
|
||||||
};
|
|
@ -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';
|
||||||
|
|
||||||
|
@ -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')
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -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) {
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { JSHandle } from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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([
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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',
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
});
|
});
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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('/');
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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},
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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
2
src/compat.d.ts
vendored
@ -1,3 +1,3 @@
|
|||||||
declare const puppeteerDirname: string;
|
declare const puppeteerDirname: string;
|
||||||
|
|
||||||
export { puppeteerDirname };
|
export {puppeteerDirname};
|
||||||
|
@ -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)));
|
||||||
|
@ -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';
|
||||||
|
@ -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}`);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
@ -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.
|
||||||
|
@ -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};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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;
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
@ -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"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -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"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
@ -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',
|
||||||
|
@ -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'}],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -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']);
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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');
|
||||||
|
@ -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;
|
||||||
|
@ -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'
|
||||||
);
|
);
|
||||||
|
@ -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');
|
||||||
|
@ -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(), [
|
||||||
{
|
{
|
||||||
|
@ -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(() => {
|
||||||
|
@ -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!'
|
||||||
|
@ -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('');
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -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',
|
||||||
]);
|
]);
|
||||||
|
@ -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>`);
|
||||||
|
@ -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([
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user