Bug 1714068 - Bug 1707588 - [puppeteer] Sync vendored puppeteer to v10.0.0 r=webdriver-reviewers,whimboo

Differential Revision: https://phabricator.services.mozilla.com/D118526
This commit is contained in:
Julian Descottes 2021-06-23 12:37:53 +00:00
Родитель e52d645cec
Коммит 1eef22c6b8
66 изменённых файлов: 948 добавлений и 599 удалений

Просмотреть файл

@ -41,12 +41,6 @@
"Accessibility filtering children of leaf nodes plaintext contenteditable plain text field with role should not have children (accessibility.spec.ts)": [
"SKIP"
],
"Accessibility filtering children of leaf nodes plaintext contenteditable plain text field without role should not have content (accessibility.spec.ts)": [
"SKIP"
],
"Accessibility filtering children of leaf nodes plaintext contenteditable plain text field with tabindex and without role should not have content (accessibility.spec.ts)": [
"SKIP"
],
"Accessibility filtering children of leaf nodes root option should work a button (accessibility.spec.ts)": [
"SKIP"
],
@ -386,6 +380,9 @@
"Emulation Page.emulateVisionDeficiency should throw for invalid vision deficiencies (emulation.spec.ts)": [
"PASS"
],
"Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType (emulation.spec.ts)": [
"FAIL"
],
"Evaluation specs Page.evaluate should work (evaluation.spec.ts)": [
"PASS"
],
@ -896,6 +893,9 @@
"Launcher specs Puppeteer Puppeteer.launch should take fullPage screenshots when defaultViewport is null (launcher.spec.ts)": [
"PASS"
],
"Launcher specs Puppeteer Puppeteer.launch should launch Chrome properly with --no-startup-window and waitForInitialPage=false (launcher.spec.ts)": [
"SKIP"
],
"Launcher specs Puppeteer Puppeteer.launch should be able to launch Chrome (launcher.spec.ts)": [
"SKIP"
],
@ -1286,7 +1286,7 @@
"Page BrowserContext.overridePermissions should trigger permission onchange (page.spec.ts)": [
"FAIL"
],
"Page BrowserContext.overridePermissions should isolate permissions between browser contexs (page.spec.ts)": [
"Page BrowserContext.overridePermissions should isolate permissions between browser contexts (page.spec.ts)": [
"FAIL"
],
"Page Page.setGeolocation should work (page.spec.ts)": [
@ -1301,9 +1301,6 @@
"Page Page.setOfflineMode should emulate navigator.onLine (page.spec.ts)": [
"FAIL"
],
"Page Page.emulateNetworkConditions should change navigator.connection.effectiveType (page.spec.ts)": [
"FAIL"
],
"Page ExecutionContext.queryObjects should work (page.spec.ts)": [
"FAIL"
],
@ -1589,7 +1586,7 @@
"Page Page.browser should return the correct browser instance (page.spec.ts)": [
"PASS"
],
"Page Page.browserContext should return the correct browser instance (page.spec.ts)": [
"Page Page.browserContext should return the correct browser context instance (page.spec.ts)": [
"PASS"
],
"querySelector Page.$eval should work (queryselector.spec.ts)": [
@ -1781,10 +1778,13 @@
"request interception Page.setRequestInterception should work with file URLs (requestinterception.spec.ts)": [
"FAIL"
],
"request interception Page.setRequestInterception should not cache if not cache-safe (requestinterception.spec.ts)": [
"request interception Page.setRequestInterception should not cache if cache disabled (requestinterception.spec.ts)": [
"FAIL"
],
"request interception Page.setRequestInterception should cache if cache-safe (requestinterception.spec.ts)": [
"request interception Page.setRequestInterception should cache if cache enabled (requestinterception.spec.ts)": [
"FAIL"
],
"request interception Page.setRequestInterception should load fonts if cache enabled (requestinterception.spec.ts)": [
"FAIL"
],
"request interception Request.continue should work (requestinterception.spec.ts)": [

Просмотреть файл

@ -166,6 +166,8 @@ module.exports = {
default: 'array-simple',
},
],
// By default this is a warning but we want it to error.
'@typescript-eslint/explicit-module-boundary-types': 2,
},
},
{

Просмотреть файл

@ -14,9 +14,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
# Include all major maintenance + active LTS Node.js versions.
# Include all major maintenance + active LTS + current Node.js versions.
# https://github.com/nodejs/Release#release-schedule
node: [10, 12, 14]
node: [12, 14, 16]
steps:
- name: Checkout
uses: actions/checkout@v2
@ -42,16 +42,20 @@ jobs:
- name: Run code checks
run: |
npm run ensure-pinned-deps
npm run lint
npm run generate-docs
npm run ensure-correct-devtools-protocol-revision
npm run test-types-file
- name: Run unit tests
uses: nick-invision/retry@v2
env:
CHROMIUM: true
run: |
xvfb-run --auto-servernum npm run unit
with:
max_attempts: 3
command: xvfb-run --auto-servernum npm run unit
timeout_minutes: 10
- name: Run unit tests with coverage
env:
@ -61,11 +65,15 @@ jobs:
xvfb-run --auto-servernum npm run assert-unit-coverage
- name: Run unit tests on Firefox
uses: nick-invision/retry@v2
env:
FIREFOX: true
MOZ_WEBRENDER: 0
run: |
xvfb-run --auto-servernum npm run funit
with:
max_attempts: 3
timeout_minutes: 10
command: xvfb-run --auto-servernum npm run funit
- name: Run browser tests
run: |
npm run test-browser
@ -93,7 +101,7 @@ jobs:
with:
# Test only the oldest maintenance LTS Node.js version.
# https://github.com/nodejs/Release#release-schedule
node-version: 10
node-version: 12
- name: Install dependencies
run: |
@ -114,11 +122,11 @@ jobs:
npm run unit
- name: Run unit tests on Firefox
env:
FIREFOX: true
MOZ_WEBRENDER: 0
run: |
npm run funit
uses: nick-invision/retry@v2
with:
max_attempts: 3
timeout_minutes: 10
command: npm run funit
windows:
# https://github.com/actions/virtual-environments#available-environments
@ -134,7 +142,7 @@ jobs:
with:
# Test only the oldest maintenance LTS Node.js version.
# https://github.com/nodejs/Release#release-schedule
node-version: 10
node-version: 12
- name: Install dependencies
run: |
@ -157,8 +165,11 @@ jobs:
npm run unit
- name: Run unit tests on Firefox
uses: nick-invision/retry@v2
env:
FIREFOX: true
MOZ_WEBRENDER: 0
run: |
npm run funit
with:
max_attempts: 3
timeout_minutes: 10
command: npm run funit

Просмотреть файл

@ -2,6 +2,30 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [10.0.0](https://github.com/puppeteer/puppeteer/compare/v9.1.1...v10.0.0) (2021-05-31)
### ⚠ BREAKING CHANGES
* Node.js 10 is no longer supported.
### Features
* **chromium:** roll to Chromium 92.0.4512.0 (r884014) ([#7288](https://github.com/puppeteer/puppeteer/issues/7288)) ([f863f4b](https://github.com/puppeteer/puppeteer/commit/f863f4bfe015e57ea1f9fbb322f1cedee468b857))
* **requestinterception:** remove cacheSafe flag ([#7217](https://github.com/puppeteer/puppeteer/issues/7217)) ([d01aa6c](https://github.com/puppeteer/puppeteer/commit/d01aa6c84a1e41f15ffed3a8d36ad26a404a7187))
* expose other sessions from connection ([#6863](https://github.com/puppeteer/puppeteer/issues/6863)) ([cb285a2](https://github.com/puppeteer/puppeteer/commit/cb285a237921259eac99ade1d8b5550e068a55eb))
* **launcher:** add new launcher option `waitForInitialPage` ([#7105](https://github.com/puppeteer/puppeteer/issues/7105)) ([2605309](https://github.com/puppeteer/puppeteer/commit/2605309f74b43da160cda4d214016e4422bf7676)), closes [#3630](https://github.com/puppeteer/puppeteer/issues/3630)
### Bug Fixes
* added comments for browsercontext, startCSSCoverage, and startJSCoverage. ([#7264](https://github.com/puppeteer/puppeteer/issues/7264)) ([b750397](https://github.com/puppeteer/puppeteer/commit/b75039746ac6bddf1411538242b5e70b0f2e6e8a))
* modified comment for method product, platform and newPage ([#7262](https://github.com/puppeteer/puppeteer/issues/7262)) ([159d283](https://github.com/puppeteer/puppeteer/commit/159d2835450697dabea6f9adf6e67d158b5b8ae3))
* **requestinterception:** fix font loading issue ([#7060](https://github.com/puppeteer/puppeteer/issues/7060)) ([c9978d2](https://github.com/puppeteer/puppeteer/commit/c9978d20d5584c9fd2dc902e4b4ac86ed8ea5d6e)), closes [/github.com/puppeteer/puppeteer/pull/6996#issuecomment-811546501](https://github.com/puppeteer//github.com/puppeteer/puppeteer/pull/6996/issues/issuecomment-811546501) [/github.com/puppeteer/puppeteer/pull/6996#issuecomment-813797393](https://github.com/puppeteer//github.com/puppeteer/puppeteer/pull/6996/issues/issuecomment-813797393) [#7038](https://github.com/puppeteer/puppeteer/issues/7038)
* drop support for Node.js 10 ([#7200](https://github.com/puppeteer/puppeteer/issues/7200)) ([97c9fe2](https://github.com/puppeteer/puppeteer/commit/97c9fe2520723d45a5a86da06b888ae888d400be)), closes [#6753](https://github.com/puppeteer/puppeteer/issues/6753)
### [9.1.1](https://github.com/puppeteer/puppeteer/compare/v9.1.0...v9.1.1) (2021-05-05)

Просмотреть файл

@ -8,7 +8,7 @@
<img src="https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png" height="200" align="right">
###### [API](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md) | [Troubleshooting](https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md)
###### [API](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md) | [Troubleshooting](https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md)
> Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). Puppeteer runs [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) by default, but can be configured to run full (non-headless) Chrome or Chromium.
@ -41,7 +41,7 @@ npm i puppeteer
# or "yarn add puppeteer"
```
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, or to download a different browser, see [Environment variables](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md#environment-variables).
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, or to download a different browser, see [Environment variables](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#environment-variables).
### puppeteer-core
@ -66,7 +66,7 @@ Note: Prior to v1.18.1, Puppeteer required at least Node v6.4.0. Versions from v
Node 8.9.0+. Starting from v3.0.0 Puppeteer starts to rely on Node 10.18.1+. All examples below use async/await which is only supported in Node v7.6.0 or greater.
Puppeteer will be familiar to people using other browser testing frameworks. You create an instance
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md#).
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#).
**Example** - navigating to https://example.com and saving a screenshot as _example.png_:
@ -91,7 +91,7 @@ Execute script on the command line
node example.js
```
Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md#pagesetviewportviewport).
Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#pagesetviewportviewport).
**Example** - create a PDF.
@ -118,7 +118,7 @@ Execute script on the command line
node hn.js
```
See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md#pagepdfoptions) for more information about creating pdfs.
See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.
**Example** - evaluate script in the context of the page
@ -153,7 +153,7 @@ Execute script on the command line
node get-dimensions.js
```
See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.
See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.
<!-- [END getstarted] -->
@ -163,7 +163,7 @@ See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/
**1. Uses Headless mode**
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/v9.1.1/docs/api.md#puppeteerlaunchoptions) when launching a browser:
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the [`headless` option](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#puppeteerlaunchoptions) when launching a browser:
```js
const browser = await puppeteer.launch({ headless: false }); // default is true
@ -179,7 +179,7 @@ pass in the executable's path when creating a `Browser` instance:
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/v9.1.1/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/v10.0.0/docs/api.md#puppeteerlaunchoptions) for more information.
See [`this article`](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [`This article`](https://chromium.googlesource.com/chromium/src/+/master/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.
@ -191,7 +191,7 @@ Puppeteer creates its own browser user profile which it **cleans up on every run
## Resources
- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md)
- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md)
- [Examples](https://github.com/puppeteer/puppeteer/tree/main/examples/)
- [Community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer)
@ -333,7 +333,7 @@ See [Contributing](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING
Official Firefox support is currently experimental. The ongoing collaboration with Mozilla aims to support common end-to-end testing use cases, for which developers expect cross-browser coverage. The Puppeteer team needs input from users to stabilize Firefox support and to bring missing APIs to our attention.
From Puppeteer v2.1.0 onwards you can specify [`puppeteer.launch({product: 'firefox'})`](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md#puppeteerlaunchoptions) to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While [an older experiment](https://www.npmjs.com/package/puppeteer-firefox) required a patched version of Firefox, [the current approach](https://wiki.mozilla.org/Remote) works with “stock” Firefox.
From Puppeteer v2.1.0 onwards you can specify [`puppeteer.launch({product: 'firefox'})`](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#puppeteerlaunchoptions) to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While [an older experiment](https://www.npmjs.com/package/puppeteer-firefox) required a patched version of Firefox, [the current approach](https://wiki.mozilla.org/Remote) works with “stock” Firefox.
We will continue to collaborate with other browser vendors to bring Puppeteer support to browsers such as Safari.
This effort includes exploration of a standard for executing cross-browser commands (instead of relying on the non-standard DevTools Protocol used by Chrome).
@ -433,7 +433,7 @@ await page.evaluate(() => {
You may find that Puppeteer does not behave as expected when controlling pages that incorporate audio and video. (For example, [video playback/screenshots is likely to fail](https://github.com/puppeteer/puppeteer/issues/291).) There are two reasons for this:
- Puppeteer is bundled with Chromium — not Chrome — and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/puppeteer/puppeteer/blob/v9.1.1/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.)
- Puppeteer is bundled with Chromium — not Chrome — and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.)
- Since Puppeteer (in all configurations) controls a desktop version of Chromium/Chrome, features that are only supported by the mobile version of Chrome are not supported. This means that Puppeteer [does not support HTTP Live Streaming (HLS)](https://caniuse.com/#feat=http-live-streaming).
#### Q: I am having trouble installing / running Puppeteer in my test environment. Where should I look for help?

Просмотреть файл

@ -5,6 +5,6 @@ origin:
description: Headless Chrome Node API
license: Apache-2.0
name: puppeteer
release: 59178c10d15e62ce135f7c39b984abe8cd909808
release: v10.0.0
url: /Users/jdescottes/Development/git/puppeteer
schema: 1

412
remote/test/puppeteer/package-lock.json сгенерированный
Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "puppeteer",
"version": "9.1.1",
"version": "10.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -51,6 +51,12 @@
"minimist": "^1.2.5"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@ -592,26 +598,11 @@
"strip-json-comments": "^3.1.1"
},
"dependencies": {
"globals": {
"version": "13.9.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz",
"integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
}
},
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"dev": true
},
"type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
}
}
},
@ -650,15 +641,15 @@
}
},
"@microsoft/api-documenter": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.12.11.tgz",
"integrity": "sha512-FcWEVeUfYo+eGnKfm9VWZGR2PX2LWDgplcE12+ggCD6F99oTSt35EPfEXwtgownNyc3b1U7ibiNahKvBUEfKwA==",
"version": "7.13.8",
"resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.13.8.tgz",
"integrity": "sha512-2E8Xrl0ZjsF42wA7EgKvxk/kFq/7tCF7aQpUspmT8Ntki90BRtfUCaZJBOMgHUln+1WndUeRt05fcJ6lhaowNA==",
"dev": true,
"requires": {
"@microsoft/api-extractor-model": "7.12.2",
"@microsoft/tsdoc": "0.12.24",
"@rushstack/node-core-library": "3.36.0",
"@rushstack/ts-command-line": "4.7.8",
"@microsoft/api-extractor-model": "7.13.1",
"@microsoft/tsdoc": "0.13.2",
"@rushstack/node-core-library": "3.37.0",
"@rushstack/ts-command-line": "4.7.10",
"colors": "~1.2.1",
"js-yaml": "~3.13.1",
"resolve": "~1.17.0"
@ -676,22 +667,23 @@
}
},
"@microsoft/api-extractor": {
"version": "7.13.2",
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.13.2.tgz",
"integrity": "sha512-2fD0c8OxZW+e6NTaxbtrdNxXVuX7aqil3+cqig3pKsHymvUuRJVCEAcAJmZrJ/ENqYXNiB265EyqOT6VxbMysw==",
"version": "7.15.1",
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.15.1.tgz",
"integrity": "sha512-PYbGAvxbM5B6HbafXY7tJ4ObYpeUZrZFt9vlN68tpYG/7aeldMLAZSjTyB30VFXaGlArjeEooKZIcs2ZnVAbNg==",
"dev": true,
"requires": {
"@microsoft/api-extractor-model": "7.12.2",
"@microsoft/tsdoc": "0.12.24",
"@rushstack/node-core-library": "3.36.0",
"@rushstack/rig-package": "0.2.10",
"@rushstack/ts-command-line": "4.7.8",
"@microsoft/api-extractor-model": "7.13.1",
"@microsoft/tsdoc": "0.13.2",
"@microsoft/tsdoc-config": "~0.15.2",
"@rushstack/node-core-library": "3.37.0",
"@rushstack/rig-package": "0.2.12",
"@rushstack/ts-command-line": "4.7.10",
"colors": "~1.2.1",
"lodash": "~4.17.15",
"resolve": "~1.17.0",
"semver": "~7.3.0",
"source-map": "~0.6.1",
"typescript": "~4.1.3"
"typescript": "~4.2.4"
},
"dependencies": {
"resolve": {
@ -702,31 +694,50 @@
"requires": {
"path-parse": "^1.0.6"
}
},
"typescript": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
"dev": true
}
}
},
"@microsoft/api-extractor-model": {
"version": "7.12.2",
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.12.2.tgz",
"integrity": "sha512-EU+U09Mj65zUH0qwPF4PFJiL6Y+PQQE/RRGEHEDGJJzab/mRQDpKOyrzSdb00xvcd/URehIHJqC55cY2Y4jGOA==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.13.1.tgz",
"integrity": "sha512-PKAjDmAJ6X07tvqCHSN1PRaKq8bZQXF9QI6WGEMnCHNFWwXUoITOAcvFW0Ol3TzwHO5rLbuy/CqWebfhv8eOtw==",
"dev": true,
"requires": {
"@microsoft/tsdoc": "0.12.24",
"@rushstack/node-core-library": "3.36.0"
"@microsoft/tsdoc": "0.13.2",
"@microsoft/tsdoc-config": "~0.15.2",
"@rushstack/node-core-library": "3.37.0"
}
},
"@microsoft/tsdoc": {
"version": "0.12.24",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.24.tgz",
"integrity": "sha512-Mfmij13RUTmHEMi9vRUhMXD7rnGR2VvxeNYtaGtaJ4redwwjT4UXYJ+nzmVJF7hhd4pn/Fx5sncDKxMVFJSWPg==",
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz",
"integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==",
"dev": true
},
"@microsoft/tsdoc-config": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz",
"integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==",
"dev": true,
"requires": {
"@microsoft/tsdoc": "0.13.2",
"ajv": "~6.12.6",
"jju": "~1.4.0",
"resolve": "~1.19.0"
},
"dependencies": {
"resolve": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
"integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
"dev": true,
"requires": {
"is-core-module": "^2.1.0",
"path-parse": "^1.0.6"
}
}
}
},
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -779,9 +790,9 @@
}
},
"@rushstack/node-core-library": {
"version": "3.36.0",
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.36.0.tgz",
"integrity": "sha512-bID2vzXpg8zweXdXgQkKToEdZwVrVCN9vE9viTRk58gqzYaTlz4fMId6V3ZfpXN6H0d319uGi2KDlm+lUEeqCg==",
"version": "3.37.0",
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.37.0.tgz",
"integrity": "sha512-b0OGvl20zfepytLBnKsOtemtiadNZAVolXxaSYssV9VjXaLPF97oLvtLfwc58BX05ufIsrKZgXatnRo8YeffNg==",
"dev": true,
"requires": {
"@types/node": "10.17.13",
@ -839,9 +850,9 @@
}
},
"@rushstack/rig-package": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.2.10.tgz",
"integrity": "sha512-WXYerEJEPf8bS3ruqfM57NnwXtA7ehn8VJjLjrjls6eSduE5CRydcob/oBTzlHKsQ7N196XKlqQl9P6qIyYG2A==",
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.2.12.tgz",
"integrity": "sha512-nbePcvF8hQwv0ql9aeQxcaMPK/h1OLAC00W7fWCRWIvD2MchZOE8jumIIr66HGrfG2X1sw++m/ZYI4D+BM5ovQ==",
"dev": true,
"requires": {
"resolve": "~1.17.0",
@ -860,9 +871,9 @@
}
},
"@rushstack/ts-command-line": {
"version": "4.7.8",
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.7.8.tgz",
"integrity": "sha512-8ghIWhkph7NnLCMDJtthpsb7TMOsVGXVDvmxjE/CeklTqjbbUFBjGXizJfpbEkRQTELuZQ2+vGn7sGwIWKN2uA==",
"version": "4.7.10",
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.7.10.tgz",
"integrity": "sha512-8t042g8eerypNOEcdpxwRA3uCmz0duMo21rG4Z2mdz7JxJeylDmzjlU3wDdef2t3P1Z61JCdZB6fbm1Mh0zi7w==",
"dev": true,
"requires": {
"@types/argparse": "1.0.38",
@ -1135,9 +1146,9 @@
"dev": true
},
"@types/node": {
"version": "14.14.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.33.tgz",
"integrity": "sha512-oJqcTrgPUF29oUP8AsUqbXGJNuPutsetaa9kTQAQce5Lx5dTYWV02ScBiT/k1BX/Z7pKeqedmvp39Wu4zR7N7g==",
"version": "14.14.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.45.tgz",
"integrity": "sha512-DssMqTV9UnnoxDWu959sDLZzfvqCF0qDNRjaWeYSui9xkFe61kKo4l1TWNTQONpuXEm+gLMRvdlzvNHBamzmEw==",
"dev": true
},
"@types/normalize-package-data": {
@ -1189,9 +1200,9 @@
}
},
"@types/rimraf": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.4.tgz",
"integrity": "sha512-8gBudvllD2A/c0CcEX/BivIDorHFt5UI5m46TsNj8DjWCCTTZT74kEe4g+QsY7P/B9WdO98d82zZgXO/RQzu2Q==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.2.tgz",
"integrity": "sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ==",
"dev": true,
"requires": {
"@types/glob": "*",
@ -1238,9 +1249,9 @@
"dev": true
},
"@types/tar-fs": {
"version": "1.16.3",
"resolved": "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-1.16.3.tgz",
"integrity": "sha512-Y+fdeg11tb9J3UNIatNtrTPM1i8U+WLv2mMhZ3W13mtU19stCgrXJ4iXLkTpoF8jqHi3T/qTS8+fQ3IPzXxpuA==",
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-1.16.2.tgz",
"integrity": "sha512-eds/pbRf0Fe0EKmrHDbs8mRkfbjz2upAdoUfREw14dPboZaHqqZ1Y+uVeoakoPavpZMpj22nhUTAYkX5bz3DXA==",
"dev": true,
"requires": {
"@types/node": "*",
@ -1263,9 +1274,9 @@
"dev": true
},
"@types/ws": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.0.tgz",
"integrity": "sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw==",
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-d/7W23JAXPodQNbOZNXvl2K+bqAQrCMwlh/nuQsPSQk6Fq0opHoPrUw43aHsvSbIiQPr8Of2hkFbnz1XBFVyZQ==",
"dev": true,
"requires": {
"@types/node": "*"
@ -1304,13 +1315,13 @@
}
},
"@typescript-eslint/eslint-plugin": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.17.0.tgz",
"integrity": "sha512-/fKFDcoHg8oNan39IKFOb5WmV7oWhQe1K6CDaAVfJaNWEhmfqlA24g+u1lqU5bMH7zuNasfMId4LaYWC5ijRLw==",
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz",
"integrity": "sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "4.17.0",
"@typescript-eslint/scope-manager": "4.17.0",
"@typescript-eslint/experimental-utils": "4.23.0",
"@typescript-eslint/scope-manager": "4.23.0",
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.15",
@ -1320,55 +1331,55 @@
}
},
"@typescript-eslint/experimental-utils": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.17.0.tgz",
"integrity": "sha512-ZR2NIUbnIBj+LGqCFGQ9yk2EBQrpVVFOh9/Kd0Lm6gLpSAcCuLLe5lUCibKGCqyH9HPwYC0GIJce2O1i8VYmWA==",
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz",
"integrity": "sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
"@typescript-eslint/scope-manager": "4.17.0",
"@typescript-eslint/types": "4.17.0",
"@typescript-eslint/typescript-estree": "4.17.0",
"@typescript-eslint/scope-manager": "4.23.0",
"@typescript-eslint/types": "4.23.0",
"@typescript-eslint/typescript-estree": "4.23.0",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
}
},
"@typescript-eslint/parser": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.17.0.tgz",
"integrity": "sha512-KYdksiZQ0N1t+6qpnl6JeK9ycCFprS9xBAiIrw4gSphqONt8wydBw4BXJi3C11ywZmyHulvMaLjWsxDjUSDwAw==",
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.23.0.tgz",
"integrity": "sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "4.17.0",
"@typescript-eslint/types": "4.17.0",
"@typescript-eslint/typescript-estree": "4.17.0",
"@typescript-eslint/scope-manager": "4.23.0",
"@typescript-eslint/types": "4.23.0",
"@typescript-eslint/typescript-estree": "4.23.0",
"debug": "^4.1.1"
}
},
"@typescript-eslint/scope-manager": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.17.0.tgz",
"integrity": "sha512-OJ+CeTliuW+UZ9qgULrnGpPQ1bhrZNFpfT/Bc0pzNeyZwMik7/ykJ0JHnQ7krHanFN9wcnPK89pwn84cRUmYjw==",
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz",
"integrity": "sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.17.0",
"@typescript-eslint/visitor-keys": "4.17.0"
"@typescript-eslint/types": "4.23.0",
"@typescript-eslint/visitor-keys": "4.23.0"
}
},
"@typescript-eslint/types": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.17.0.tgz",
"integrity": "sha512-RN5z8qYpJ+kXwnLlyzZkiJwfW2AY458Bf8WqllkondQIcN2ZxQowAToGSd9BlAUZDB5Ea8I6mqL2quGYCLT+2g==",
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.23.0.tgz",
"integrity": "sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.17.0.tgz",
"integrity": "sha512-lRhSFIZKUEPPWpWfwuZBH9trYIEJSI0vYsrxbvVvNyIUDoKWaklOAelsSkeh3E2VBSZiNe9BZ4E5tYBZbUczVQ==",
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz",
"integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.17.0",
"@typescript-eslint/visitor-keys": "4.17.0",
"@typescript-eslint/types": "4.23.0",
"@typescript-eslint/visitor-keys": "4.23.0",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
@ -1377,12 +1388,12 @@
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.17.0.tgz",
"integrity": "sha512-WfuMN8mm5SSqXuAr9NM+fItJ0SVVphobWYkWOwQ1odsfC014Vdxk/92t4JwS1Q6fCA/ABfCKpa3AVtpUKTNKGQ==",
"version": "4.23.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz",
"integrity": "sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.17.0",
"@typescript-eslint/types": "4.23.0",
"eslint-visitor-keys": "^2.0.0"
}
},
@ -1510,24 +1521,23 @@
}
},
"@web/test-runner": {
"version": "0.12.16",
"resolved": "https://registry.npmjs.org/@web/test-runner/-/test-runner-0.12.16.tgz",
"integrity": "sha512-Lz1lFgLsjOYaS0jcZs54TeWkq/qFUzuKNrmgO36RYr1AtReFbv/sDHEBCWL7uzpxBCHA0sT6KDkvuVaZWuinGA==",
"version": "0.12.20",
"resolved": "https://registry.npmjs.org/@web/test-runner/-/test-runner-0.12.20.tgz",
"integrity": "sha512-ibuZDuvXy30PWn05//ca06f2NCr0WM42m0QyNdQZ/GIR03W4FpNQ/6ogSq4O4mTBg1KW88IOfHvEXWL449bR6g==",
"dev": true,
"requires": {
"@web/browser-logs": "^0.2.0",
"@web/config-loader": "^0.1.3",
"@web/dev-server": "^0.1.8",
"@web/dev-server": "^0.1.11",
"@web/test-runner-chrome": "^0.9.4",
"@web/test-runner-commands": "^0.4.1",
"@web/test-runner-core": "^0.10.13",
"@web/test-runner-commands": "^0.4.3",
"@web/test-runner-core": "^0.10.14",
"@web/test-runner-mocha": "^0.7.2",
"camelcase": "^6.2.0",
"chalk": "^4.1.0",
"command-line-args": "^5.1.1",
"command-line-usage": "^6.1.1",
"convert-source-map": "^1.7.0",
"deepmerge": "^4.2.2",
"diff": "^5.0.0",
"globby": "^11.0.1",
"portfinder": "^1.0.28",
@ -2223,15 +2233,23 @@
"optional": true
},
"commonmark": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.28.1.tgz",
"integrity": "sha1-Buq41SM4uDn6Gi11rwCF7tGxvq4=",
"version": "0.29.3",
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.29.3.tgz",
"integrity": "sha512-fvt/NdOFKaL2gyhltSy6BC4LxbbxbnPxBMl923ittqO/JBM0wQHaoYZliE4tp26cRxX/ZZtRsJlZzQrVdUkXAA==",
"dev": true,
"requires": {
"entities": "~ 1.1.1",
"mdurl": "~ 1.0.1",
"minimist": "~ 1.2.0",
"entities": "~2.0",
"mdurl": "~1.0.1",
"minimist": ">=1.2.2",
"string.prototype.repeat": "^0.2.0"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
}
}
},
"compare-func": {
@ -2850,9 +2868,9 @@
"dev": true
},
"devtools-protocol": {
"version": "0.0.869402",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz",
"integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA=="
"version": "0.0.883894",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.883894.tgz",
"integrity": "sha512-33idhm54QJzf3Q7QofMgCvIVSd2o9H3kQPWaKT/fhoZh+digc+WSiMhbkeG3iN79WY4Hwr9G05NpbhEVrsOYAg=="
},
"diff": {
"version": "5.0.0",
@ -2981,9 +2999,9 @@
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
"integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
"dev": true
},
"error-ex": {
@ -3061,13 +3079,13 @@
"dev": true
},
"eslint": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz",
"integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==",
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz",
"integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==",
"dev": true,
"requires": {
"@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.4.0",
"@eslint/eslintrc": "^0.4.1",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@ -3083,7 +3101,7 @@
"file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
"globals": "^12.1.0",
"globals": "^13.6.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
@ -3091,7 +3109,7 @@
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash": "^4.17.20",
"lodash": "^4.17.21",
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
@ -3133,21 +3151,10 @@
}
},
"eslint-config-prettier": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz",
"integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==",
"dev": true,
"requires": {
"get-stdin": "^6.0.0"
},
"dependencies": {
"get-stdin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
"integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
"dev": true
}
}
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz",
"integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==",
"dev": true
},
"eslint-import-resolver-node": {
"version": "0.3.4",
@ -3417,9 +3424,9 @@
}
},
"eslint-plugin-prettier": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz",
"integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz",
"integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==",
"dev": true,
"requires": {
"prettier-linter-helpers": "^1.0.0"
@ -3512,9 +3519,9 @@
}
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
"dev": true
},
"esquery": {
@ -3576,16 +3583,16 @@
"dev": true
},
"expect": {
"version": "25.5.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-25.5.0.tgz",
"integrity": "sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA==",
"version": "25.2.7",
"resolved": "https://registry.npmjs.org/expect/-/expect-25.2.7.tgz",
"integrity": "sha512-yA+U2Ph0MkMsJ9N8q5hs9WgWI6oJYfecdXta6LkP/alY/jZZL1MHlJ2wbLh60Ucqf3G+51ytbqV3mlGfmxkpNw==",
"dev": true,
"requires": {
"@jest/types": "^25.5.0",
"@jest/types": "^25.2.6",
"ansi-styles": "^4.0.0",
"jest-get-type": "^25.2.6",
"jest-matcher-utils": "^25.5.0",
"jest-message-util": "^25.5.0",
"jest-matcher-utils": "^25.2.7",
"jest-message-util": "^25.2.6",
"jest-regex-util": "^25.2.6"
}
},
@ -4147,18 +4154,18 @@
}
},
"globals": {
"version": "12.4.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
"integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
"version": "13.9.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz",
"integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==",
"dev": true,
"requires": {
"type-fest": "^0.8.1"
"type-fest": "^0.20.2"
},
"dependencies": {
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
}
}
@ -4200,6 +4207,14 @@
"source-map": "^0.6.1",
"uglify-js": "^3.1.4",
"wordwrap": "^1.0.0"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
}
}
},
"hard-rejection": {
@ -5315,9 +5330,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"minimist-options": {
@ -5335,20 +5350,21 @@
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
},
"mkdirp-classic": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
},
"mocha": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.1.tgz",
"integrity": "sha512-5SBMxANWqOv5bw3Hx+HVgaWlcWcFEQDUdaUAr1AUU+qwtx6cowhn7gEDT/DwQP7uYxnvShdUOVLbTYAHOEGfDQ==",
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
"integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
"dev": true,
"requires": {
"@ungap/promise-all-settled": "1.1.2",
@ -5938,9 +5954,9 @@
"dev": true
},
"prettier": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz",
"integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==",
"dev": true
},
"prettier-linter-helpers": {
@ -5971,9 +5987,9 @@
"dev": true
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
"integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg=="
},
"proxy-from-env": {
"version": "1.1.0",
@ -6370,9 +6386,9 @@
}
},
"rollup": {
"version": "2.51.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.1.tgz",
"integrity": "sha512-8xfDbAtBleXotb6qKEHWuo/jkn94a9dVqGc7Rwl3sqspCVlnCfbRek7ldhCARSi7h32H0xR4QThm1t9zHN+3uw==",
"version": "2.51.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz",
"integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==",
"dev": true,
"requires": {
"fsevents": "~2.3.1"
@ -6618,9 +6634,9 @@
}
},
"standard-version": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.1.1.tgz",
"integrity": "sha512-PF9JnRauBwH7DAkmefYu1mB2Kx0MVG13udqDTFmDUiogbyikBAHBdMrVuauxtAb2YIkyZ3FMYCNv0hqUKMOPww==",
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.3.0.tgz",
"integrity": "sha512-cYxxKXhYfI3S9+CA84HmrJa9B88H56V5FQ302iFF2TNwJukJCNoU8FgWt+11YtwKFXRkQQFpepC2QOF7aDq2Ow==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
@ -6972,14 +6988,14 @@
}
},
"tar-fs": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
"integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz",
"integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==",
"requires": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
"mkdirp": "^0.5.1",
"pump": "^3.0.0",
"tar-stream": "^2.1.4"
"tar-stream": "^2.0.0"
}
},
"tar-stream": {
@ -7167,9 +7183,9 @@
"dev": true
},
"typescript": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
"dev": true
},
"typical": {
@ -7198,9 +7214,9 @@
}
},
"unbzip2-stream": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
"integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz",
"integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==",
"requires": {
"buffer": "^5.2.1",
"through": "^2.3.8"
@ -7431,9 +7447,9 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"ws": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A=="
},
"xtend": {
"version": "4.0.2",

Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "puppeteer",
"version": "9.1.1",
"version": "10.0.0",
"description": "A high-level API to control headless Chrome over the DevTools Protocol",
"main": "./cjs-entry.js",
"types": "lib/types.d.ts",
@ -24,8 +24,8 @@
"eslint": "([ \"$CI\" = true ] && eslint --ext js --ext ts --quiet -f codeframe . || eslint --ext js --ext ts .)",
"eslint-fix": "eslint --ext js --ext ts --fix .",
"commitlint": "commitlint --from=HEAD~1",
"markdownlint": "prettier --check **/README.md docs/api.md docs/troubleshooting.md",
"markdownlint-fix": "prettier --write **/README.md docs/api.md docs/troubleshooting.md",
"markdownlint": "prettier --check **/README.md docs/troubleshooting.md",
"markdownlint-fix": "prettier --write **/README.md docs/troubleshooting.md",
"lint": "npm run eslint && npm run build && npm run doc && npm run commitlint && npm run markdownlint",
"doc": "node utils/doclint/cli.js",
"clean-lib": "rimraf lib",
@ -38,6 +38,7 @@
"generate-d-ts": "api-extractor run --local --verbose",
"generate-docs": "npm run generate-d-ts && api-documenter markdown -i temp -o new-docs",
"ensure-correct-devtools-protocol-revision": "ts-node -s scripts/ensure-correct-devtools-protocol-package",
"ensure-pinned-deps": "ts-node -s scripts/ensure-pinned-deps",
"test-types-file": "ts-node -s scripts/test-ts-definition-files.ts",
"release": "node utils/remove_version_suffix.js && standard-version --commit-all"
},
@ -56,64 +57,65 @@
"license": "Apache-2.0",
"dependencies": {
"debug": "4.3.1",
"devtools-protocol": "0.0.869402",
"devtools-protocol": "0.0.883894",
"extract-zip": "2.0.1",
"https-proxy-agent": "5.0.0",
"node-fetch": "2.6.1",
"pkg-dir": "4.2.0",
"progress": "2.0.3",
"progress": "2.0.1",
"proxy-from-env": "1.1.0",
"rimraf": "3.0.2",
"tar-fs": "2.1.1",
"unbzip2-stream": "1.4.3",
"ws": "7.4.4"
"tar-fs": "2.0.0",
"unbzip2-stream": "1.3.3",
"ws": "7.4.6"
},
"devDependencies": {
"@commitlint/cli": "11.0.0",
"@commitlint/config-conventional": "11.0.0",
"@microsoft/api-documenter": "7.12.11",
"@microsoft/api-extractor": "7.13.2",
"@microsoft/api-documenter": "7.13.8",
"@microsoft/api-extractor": "7.15.1",
"@types/debug": "0.0.31",
"@types/mime": "2.0.3",
"@types/mocha": "7.0.2",
"@types/node": "14.14.33",
"@types/node": "14.14.45",
"@types/proxy-from-env": "1.0.1",
"@types/rimraf": "2.0.4",
"@types/rimraf": "2.0.2",
"@types/sinon": "9.0.11",
"@types/tar-fs": "1.16.3",
"@types/ws": "7.4.0",
"@typescript-eslint/eslint-plugin": "4.17.0",
"@typescript-eslint/parser": "4.17.0",
"@web/test-runner": "0.12.16",
"commonmark": "0.28.1",
"@types/tar-fs": "1.16.2",
"@types/ws": "7.4.4",
"@typescript-eslint/eslint-plugin": "4.23.0",
"@typescript-eslint/parser": "4.23.0",
"@web/test-runner": "0.12.20",
"commonmark": "0.29.3",
"cross-env": "7.0.3",
"eslint": "7.21.0",
"eslint-config-prettier": "6.15.0",
"eslint": "7.26.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-mocha": "8.1.0",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-prettier": "3.4.0",
"eslint-plugin-unicorn": "22.0.0",
"esprima": "4.0.1",
"expect": "25.5.0",
"esprima": "4.0.0",
"expect": "25.2.7",
"husky": "4.3.8",
"jpeg-js": "0.3.7",
"mime": "2.5.2",
"minimist": "1.2.5",
"mocha": "8.3.1",
"minimist": "1.2.0",
"mocha": "8.4.0",
"ncp": "2.0.0",
"pixelmatch": "4.0.2",
"pngjs": "5.0.0",
"prettier": "2.2.1",
"prettier": "2.3.0",
"sinon": "9.2.4",
"source-map-support": "0.5.19",
"standard-version": "9.1.1",
"standard-version": "9.3.0",
"text-diff": "1.0.1",
"ts-node": "9.1.1",
"typescript": "4.2.3"
"typescript": "4.2.4"
},
"husky": {
"hooks": {
"commit-msg": "commitlint --env HUSKY_GIT_PARAMS"
"commit-msg": "commitlint --env HUSKY_GIT_PARAMS",
"pre-push": "npm run ensure-pinned-deps"
}
}
}

Просмотреть файл

@ -0,0 +1,37 @@
/**
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import packageJson from '../package.json';
const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
const invalidDeps = new Map<string, string>();
for (const [depKey, depValue] of Object.entries(allDeps)) {
if (/[0-9]/.test(depValue[0])) {
continue;
}
invalidDeps.set(depKey, depValue);
}
if (invalidDeps.size > 0) {
console.error('Found non-pinned dependencies in package.json:');
console.log([...invalidDeps.keys()].map((k) => ` ${k}`).join('\n'));
process.exit(1);
}
process.exit(0);

Просмотреть файл

@ -10,6 +10,10 @@ const EXPECTED_ERRORS = new Map<string, string[]>([
"bad.ts(6,35): error TS2551: Property 'launh' does not exist on type",
"bad.ts(8,29): error TS2551: Property 'devics' does not exist on type",
'bad.ts(12,39): error TS2554: Expected 0 arguments, but got 1.',
"bad.ts(20,5): error TS2345: Argument of type '(divElem: number) => any' is not assignable to parameter of type 'EvaluateFn<HTMLAnchorElement>",
"bad.ts(20,34): error TS2339: Property 'innerText' does not exist on type 'number'.",
"bad.ts(24,45): error TS2344: Type '(x: number) => string' does not satisfy the constraint 'EvaluateFn<HTMLAnchorElement>'.",
"bad.ts(27,34): error TS2339: Property 'innerText' does not exist on type 'number'.",
],
],
[
@ -35,6 +39,8 @@ const EXPECTED_ERRORS = new Map<string, string[]>([
"bad.js(7,29): error TS2551: Property 'devics' does not exist on type",
'bad.js(11,39): error TS2554: Expected 0 arguments, but got 1.',
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
"bad.js(22,5): error TS2345: Argument of type '(divElem: number) => any' is not assignable to parameter of type 'EvaluateFn<HTMLElement>'.",
"bad.js(22,26): error TS2339: Property 'innerText' does not exist on type 'number'.",
],
],
[
@ -67,6 +73,13 @@ const EXPECTED_ERRORS = new Map<string, string[]>([
]);
const PROJECT_FOLDERS = [...EXPECTED_ERRORS.keys()];
if (!process.env.CI) {
console.log(`IMPORTANT: this script assumes you have compiled Puppeteer
and its types file before running. Make sure you have run:
=> npm run tsc && npm run generate-d-ts
before executing this script locally.`);
}
function packPuppeteer() {
console.log('Packing Puppeteer');
const result = spawnSync('npm', ['pack'], {

Просмотреть файл

@ -437,10 +437,11 @@ class AXNode {
properties.get(key) as boolean;
for (const booleanProperty of booleanProperties) {
// WebArea's treat focus differently than other nodes. They report whether
// RootWebArea's treat focus differently than other nodes. They report whether
// their frame has focus, not whether focus is specifically on the root
// node.
if (booleanProperty === 'focused' && this._role === 'WebArea') continue;
if (booleanProperty === 'focused' && this._role === 'RootWebArea')
continue;
const value = getBooleanPropertyValue(booleanProperty);
if (!value) continue;
node[booleanProperty] = getBooleanPropertyValue(booleanProperty);

Просмотреть файл

@ -32,7 +32,7 @@ async function queryAXTree(
role,
});
const filteredNodes: Protocol.Accessibility.AXNode[] = nodes.filter(
(node: Protocol.Accessibility.AXNode) => node.role.value !== 'text'
(node: Protocol.Accessibility.AXNode) => node.role.value !== 'StaticText'
);
return filteredNodes;
}
@ -52,7 +52,8 @@ function parseAriaSelector(selector: string): ariaQueryOption {
const normalize = (value: string): string => value.replace(/ +/g, ' ').trim();
const knownAttributes = new Set(['name', 'role']);
const queryOptions: ariaQueryOption = {};
const attributeRegexp = /\[\s*(?<attribute>\w+)\s*=\s*"(?<value>\\.|[^"\\]*)"\s*\]/g;
const attributeRegexp =
/\[\s*(?<attribute>\w+)\s*=\s*"(?<value>\\.|[^"\\]*)"\s*\]/g;
const defaultName = selector.replace(
attributeRegexp,
(_, attribute: string, value: string) => {

Просмотреть файл

@ -417,7 +417,8 @@ export class Browser extends EventEmitter {
}
/**
* Creates a {@link Page} in the default browser context.
* Promise which resolves to a new {@link Page} object. The Page is created in
* a default browser context.
*/
async newPage(): Promise<Page> {
return this._defaultContext.newPage();
@ -722,9 +723,8 @@ export class BrowserContext extends EventEmitter {
permissions: Permission[]
): Promise<void> {
const protocolPermissions = permissions.map((permission) => {
const protocolPermission = WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(
permission
);
const protocolPermission =
WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission);
if (!protocolPermission)
throw new Error('Unknown permission: ' + permission);
return protocolPermission;

Просмотреть файл

@ -89,16 +89,14 @@ export const connectToBrowser = async (
connection = new Connection('', transport, slowMo);
} else if (browserWSEndpoint) {
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport: ConnectionTransport = await WebSocketClass.create(
browserWSEndpoint
);
const connectionTransport: ConnectionTransport =
await WebSocketClass.create(browserWSEndpoint);
connection = new Connection(browserWSEndpoint, connectionTransport, slowMo);
} else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport: ConnectionTransport = await WebSocketClass.create(
connectionURL
);
const connectionTransport: ConnectionTransport =
await WebSocketClass.create(connectionURL);
connection = new Connection(connectionURL, connectionTransport, slowMo);
}

Просмотреть файл

@ -125,11 +125,21 @@ export class Connection extends EventEmitter {
sessionId
);
this._sessions.set(sessionId, session);
this.emit('sessionattached', session);
const parentSession = this._sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit('sessionattached', session);
}
} else if (object.method === 'Target.detachedFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session) {
session._onClosed();
this._sessions.delete(object.params.sessionId);
this.emit('sessiondetached', session);
const parentSession = this._sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit('sessiondetached', session);
}
}
}
if (object.sessionId) {
@ -253,6 +263,10 @@ export class CDPSession extends EventEmitter {
this._sessionId = sessionId;
}
connection(): Connection {
return this._connection;
}
send<T extends keyof ProtocolMapping.Commands>(
method: T,
...paramArgs: ProtocolMapping.Commands[T]['paramsType']
@ -270,11 +284,7 @@ export class CDPSession extends EventEmitter {
const id = this._connection._rawSend({
sessionId: this._sessionId,
method,
/* TODO(jacktfranklin@): once this Firefox bug is solved
* we no longer need the `|| {}` check
* https://bugzilla.mozilla.org/show_bug.cgi?id=1631570
*/
params: params || {},
params,
});
return new Promise((resolve, reject) => {

Просмотреть файл

@ -123,8 +123,8 @@ export class Coverage {
}
/**
* @param options - defaults to
* `{ resetOnNavigation : true, reportAnonymousScripts : false }`
* @param options - Set of configurable options for coverage defaults to `{
* resetOnNavigation : true, reportAnonymousScripts : false }`
* @returns Promise that resolves when coverage is started.
*
* @remarks
@ -150,7 +150,8 @@ export class Coverage {
}
/**
* @param options - defaults to `{ resetOnNavigation : true }`
* @param options - Set of configurable options for coverage, defaults to `{
* resetOnNavigation : true }`
* @returns Promise that resolves when coverage is started.
*/
async startCSSCoverage(options: CSSCoverageOptions = {}): Promise<void> {
@ -192,10 +193,8 @@ export class JSCoverage {
} = {}
): Promise<void> {
assert(!this._enabled, 'JSCoverage is already enabled');
const {
resetOnNavigation = true,
reportAnonymousScripts = false,
} = options;
const { resetOnNavigation = true, reportAnonymousScripts = false } =
options;
this._resetOnNavigation = resetOnNavigation;
this._reportAnonymousScripts = reportAnonymousScripts;
this._enabled = true;

Просмотреть файл

@ -484,9 +484,8 @@ export class DOMWorld {
selector: string,
options: WaitForSelectorOptions
): Promise<ElementHandle | null> {
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(
selector
);
const { updatedSelector, queryHandler } =
getQueryHandlerAndSelector(selector);
return queryHandler.waitFor(this, updatedSelector, options);
}
@ -687,10 +686,8 @@ export class DOMWorld {
options: { polling?: string | number; timeout?: number } = {},
...args: SerializableOrJSHandle[]
): Promise<JSHandle> {
const {
polling = 'raf',
timeout = this._timeoutSettings.timeout(),
} = options;
const { polling = 'raf', timeout = this._timeoutSettings.timeout() } =
options;
const waitTaskOptions: WaitTaskOptions = {
domWorld: this,
predicateBody: pageFunction,

Просмотреть файл

@ -31,9 +31,10 @@ export class EmulationManager {
const width = viewport.width;
const height = viewport.height;
const deviceScaleFactor = viewport.deviceScaleFactor || 1;
const screenOrientation: Protocol.Emulation.ScreenOrientation = viewport.isLandscape
? { angle: 90, type: 'landscapePrimary' }
: { angle: 0, type: 'portraitPrimary' };
const screenOrientation: Protocol.Emulation.ScreenOrientation =
viewport.isLandscape
? { angle: 90, type: 'landscapePrimary' }
: { angle: 0, type: 'portraitPrimary' };
const hasTouch = viewport.hasTouch || false;
await Promise.all([

Просмотреть файл

@ -21,7 +21,7 @@ export interface CommonEventEmitter {
*/
addListener(event: EventType, handler: Handler): CommonEventEmitter;
removeListener(event: EventType, handler: Handler): CommonEventEmitter;
emit(event: EventType, eventData?: any): boolean;
emit(event: EventType, eventData?: unknown): boolean;
once(event: EventType, handler: Handler): CommonEventEmitter;
listenerCount(event: string): number;
@ -55,7 +55,7 @@ export class EventEmitter implements CommonEventEmitter {
* Bind an event listener to fire when an event occurs.
* @param event - the event type you'd like to listen to. Can be a string or symbol.
* @param handler - the function to be called when the event occurs.
* @returns `this` to enable you to chain calls.
* @returns `this` to enable you to chain method calls.
*/
on(event: EventType, handler: Handler): EventEmitter {
this.emitter.on(event, handler);
@ -66,7 +66,7 @@ export class EventEmitter implements CommonEventEmitter {
* Remove an event listener from firing.
* @param event - the event type you'd like to stop listening to.
* @param handler - the function that should be removed.
* @returns `this` to enable you to chain calls.
* @returns `this` to enable you to chain method calls.
*/
off(event: EventType, handler: Handler): EventEmitter {
this.emitter.off(event, handler);
@ -75,7 +75,7 @@ export class EventEmitter implements CommonEventEmitter {
/**
* Remove an event listener.
* @deprecated please use `off` instead.
* @deprecated please use {@link EventEmitter.off} instead.
*/
removeListener(event: EventType, handler: Handler): EventEmitter {
this.off(event, handler);
@ -84,7 +84,7 @@ export class EventEmitter implements CommonEventEmitter {
/**
* Add an event listener.
* @deprecated please use `on` instead.
* @deprecated please use {@link EventEmitter.on} instead.
*/
addListener(event: EventType, handler: Handler): EventEmitter {
this.on(event, handler);
@ -98,7 +98,7 @@ export class EventEmitter implements CommonEventEmitter {
* @param eventData - any data you'd like to emit with the event
* @returns `true` if there are any listeners, `false` if there are not.
*/
emit(event: EventType, eventData?: any): boolean {
emit(event: EventType, eventData?: unknown): boolean {
this.emitter.emit(event, eventData);
return this.eventListenersCount(event) > 0;
}
@ -107,7 +107,7 @@ export class EventEmitter implements CommonEventEmitter {
* Like `on` but the listener will only be fired once and then it will be removed.
* @param event - the event you'd like to listen to
* @param handler - the handler function to run when the event occurs
* @returns `this` to enable you to chain calls.
* @returns `this` to enable you to chain method calls.
*/
once(event: EventType, handler: Handler): EventEmitter {
const onceHandler: Handler = (eventData) => {
@ -132,7 +132,7 @@ export class EventEmitter implements CommonEventEmitter {
* Removes all listeners. If given an event argument, it will remove only
* listeners for that event.
* @param event - the event to remove listeners for.
* @returns `this` to enable you to chain calls.
* @returns `this` to enable you to chain method calls.
*/
removeAllListeners(event?: EventType): EventEmitter {
if (event) {

Просмотреть файл

@ -267,10 +267,8 @@ export class ExecutionContext {
error.message += ' Are you passing a nested JSHandle?';
throw error;
}
const {
exceptionDetails,
result: remoteObject,
} = await callFunctionOnPromise.catch(rewriteError);
const { exceptionDetails, result: remoteObject } =
await callFunctionOnPromise.catch(rewriteError);
if (exceptionDetails)
throw new Error(
'Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails)

Просмотреть файл

@ -76,7 +76,7 @@ export class FileChooser {
/**
* Closes the file chooser without selecting any files.
*/
cancel() {
cancel(): void {
assert(
!this._handled,
'Cannot cancel FileChooser which is already handled!'

Просмотреть файл

@ -191,14 +191,16 @@ export class HTTPRequest {
}
/**
* @returns the response for this request, if a response has been received.
* @returns A matching `HTTPResponse` object, or null if the response has not
* been received yet.
*/
response(): HTTPResponse | null {
return this._response;
}
/**
* @returns the frame that initiated the request.
* @returns the frame that initiated the request, or null if navigating to
* error pages.
*/
frame(): Frame | null {
return this._frame;
@ -212,6 +214,7 @@ export class HTTPRequest {
}
/**
* A `redirectChain` is a chain of requests initiated to fetch a resource.
* @remarks
*
* `redirectChain` is shared between all the requests of the same chain.

Просмотреть файл

@ -105,7 +105,7 @@ export function createJSHandle(
*
* @public
*/
export class JSHandle {
export class JSHandle<HandleObjectType = unknown> {
/**
* @internal
*/
@ -154,7 +154,7 @@ export class JSHandle {
* ```
*/
async evaluate<T extends EvaluateFn>(
async evaluate<T extends EvaluateFn<HandleObjectType>>(
pageFunction: T | string,
...args: SerializableOrJSHandle[]
): Promise<UnwrapPromiseLike<EvaluateFnReturnType<T>>> {
@ -193,7 +193,7 @@ export class JSHandle {
*/
async getProperty(propertyName: string): Promise<JSHandle | undefined> {
const objectHandle = await this.evaluateHandle(
(object: HTMLElement, propertyName: string) => {
(object: Element, propertyName: string) => {
const result = { __proto__: null };
result[propertyName] = object[propertyName];
return result;
@ -237,8 +237,8 @@ export class JSHandle {
}
/**
* Returns a JSON representation of the object.
*
* @returns Returns a JSON representation of the object.If the object has a
* `toJSON` function, it will not be called.
* @remarks
*
* The JSON is generated by running {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify | JSON.stringify}
@ -259,12 +259,13 @@ export class JSHandle {
}
/**
* Returns either `null` or the object handle itself, if the object handle is
* an instance of {@link ElementHandle}.
* @returns Either `null` or the object handle itself, if the object
* handle is an instance of {@link ElementHandle}.
*/
asElement(): ElementHandle | null {
// This always returns null, but subclasses can override this and return an
// ElementHandle.
/* This always returns null, but subclasses can override this and return an
ElementHandle.
*/
return null;
}
@ -328,7 +329,7 @@ export class JSHandle {
*/
export class ElementHandle<
ElementType extends Element = Element
> extends JSHandle {
> extends JSHandle<ElementType> {
private _page: Page;
private _frameManager: FrameManager;
@ -521,24 +522,25 @@ export class ElementHandle<
'"'
);
return this.evaluate<
(element: HTMLSelectElement, values: string[]) => string[]
>((element, values) => {
if (element.nodeName.toLowerCase() !== 'select')
throw new Error('Element is not a <select> element.');
return this.evaluate<(element: Element, values: string[]) => string[]>(
(element, values) => {
if (!(element instanceof HTMLSelectElement))
throw new Error('Element is not a <select> element.');
const options = Array.from(element.options);
element.value = undefined;
for (const option of options) {
option.selected = values.includes(option.value);
if (option.selected && !element.multiple) break;
}
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
return options
.filter((option) => option.selected)
.map((option) => option.value);
}, values);
const options = Array.from(element.options);
element.value = undefined;
for (const option of options) {
option.selected = values.includes(option.value);
if (option.selected && !element.multiple) break;
}
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
return options
.filter((option) => option.selected)
.map((option) => option.value);
},
values
);
}
/**
@ -549,9 +551,14 @@ export class ElementHandle<
* relative to the {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}
*/
async uploadFile(...filePaths: string[]): Promise<void> {
const isMultiple = await this.evaluate<
(element: HTMLInputElement) => boolean
>((element) => element.multiple);
const isMultiple = await this.evaluate<(element: Element) => boolean>(
(element) => {
if (!(element instanceof HTMLInputElement)) {
throw new Error('uploadFile can only be called on an input element.');
}
return element.multiple;
}
);
assert(
filePaths.length <= 1 || isMultiple,
'Multiple file uploads only work with <input type=file multiple>'
@ -562,8 +569,10 @@ export class ElementHandle<
`JSHandle#uploadFile can only be used in Node environments.`
);
}
// This import is only needed for `uploadFile`, so keep it scoped here to avoid paying
// the cost unnecessarily.
/*
This import is only needed for `uploadFile`, so keep it scoped here to
avoid paying the cost unnecessarily.
*/
const path = await import('path');
const fs = await helper.importFSModule();
// Locate all files and confirm that they exist.
@ -584,11 +593,12 @@ export class ElementHandle<
const { node } = await this._client.send('DOM.describeNode', { objectId });
const { backendNodeId } = node;
// The zero-length array is a special case, it seems that 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.
/* The zero-length array is a special case, it seems that
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.
*/
if (files.length === 0) {
await this.evaluate<(element: HTMLInputElement) => void>((element) => {
await (this as ElementHandle<HTMLInputElement>).evaluate((element) => {
element.files = new DataTransfer().files;
// Dispatch events for this case because it should behave akin to a user action.
@ -619,7 +629,7 @@ export class ElementHandle<
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element.
*/
async focus(): Promise<void> {
await this.evaluate<(element: HTMLElement) => void>((element) =>
await (this as ElementHandle<HTMLElement>).evaluate((element) =>
element.focus()
);
}
@ -776,9 +786,8 @@ export class ElementHandle<
async $<T extends Element = Element>(
selector: string
): Promise<ElementHandle<T> | null> {
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(
selector
);
const { updatedSelector, queryHandler } =
getQueryHandlerAndSelector(selector);
return queryHandler.queryOne(this, updatedSelector);
}
@ -789,9 +798,8 @@ export class ElementHandle<
async $$<T extends Element = Element>(
selector: string
): Promise<Array<ElementHandle<T>>> {
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(
selector
);
const { updatedSelector, queryHandler } =
getQueryHandlerAndSelector(selector);
return queryHandler.queryAll(this, updatedSelector);
}
@ -873,9 +881,8 @@ export class ElementHandle<
) => ReturnType | Promise<ReturnType>,
...args: SerializableOrJSHandle[]
): Promise<WrapElementHandle<ReturnType>> {
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(
selector
);
const { updatedSelector, queryHandler } =
getQueryHandlerAndSelector(selector);
const arrayHandle = await queryHandler.queryAllArray(this, updatedSelector);
const result = await arrayHandle.evaluate<
(
@ -976,8 +983,9 @@ export interface PressOptions {
}
function computeQuadArea(quad: Array<{ x: number; y: number }>): number {
// Compute sum of all directed areas of adjacent triangles
// https://en.wikipedia.org/wiki/Polygon#Simple_polygons
/* Compute sum of all directed areas of adjacent triangles
https://en.wikipedia.org/wiki/Polygon#Simple_polygons
*/
let area = 0;
for (let i = 0; i < quad.length; ++i) {
const p1 = quad[i];

Просмотреть файл

@ -69,19 +69,53 @@ export class NetworkManager extends EventEmitter {
_client: CDPSession;
_ignoreHTTPSErrors: boolean;
_frameManager: FrameManager;
_requestIdToRequest = new Map<string, HTTPRequest>();
/*
* There are four possible orders of events:
* A. `_onRequestWillBeSent`
* B. `_onRequestWillBeSent`, `_onRequestPaused`
* C. `_onRequestPaused`, `_onRequestWillBeSent`
* D. `_onRequestPaused`, `_onRequestWillBeSent`, `_onRequestPaused`
* (see crbug.com/1196004)
*
* For `_onRequest` we need the event from `_onRequestWillBeSent` and
* optionally the `interceptionId` from `_onRequestPaused`.
*
* If request interception is disabled, call `_onRequest` once per call to
* `_onRequestWillBeSent`.
* If request interception is enabled, call `_onRequest` once per call to
* `_onRequestPaused` (once per `interceptionId`).
*
* Events are stored to allow for subsequent events to call `_onRequest`.
*
* Note that (chains of) redirect requests have the same `requestId` (!) as
* the original request. We have to anticipate series of events like these:
* A. `_onRequestWillBeSent`,
* `_onRequestWillBeSent`, ...
* B. `_onRequestWillBeSent`, `_onRequestPaused`,
* `_onRequestWillBeSent`, `_onRequestPaused`, ...
* C. `_onRequestWillBeSent`, `_onRequestPaused`,
* `_onRequestPaused`, `_onRequestWillBeSent`, ...
* D. `_onRequestPaused`, `_onRequestWillBeSent`,
* `_onRequestPaused`, `_onRequestWillBeSent`, `_onRequestPaused`, ...
* (see crbug.com/1196004)
*/
_requestIdToRequestWillBeSentEvent = new Map<
string,
Protocol.Network.RequestWillBeSentEvent
>();
_requestIdToRequestPausedEvent = new Map<
string,
Protocol.Fetch.RequestPausedEvent
>();
_requestIdToRequest = new Map<string, HTTPRequest>();
_extraHTTPHeaders: Record<string, string> = {};
_credentials?: Credentials = null;
_attemptedAuthentications = new Set<string>();
_userRequestInterceptionEnabled = false;
_userRequestInterceptionCacheSafe = false;
_protocolRequestInterceptionEnabled = false;
_userCacheDisabled = false;
_requestIdToInterceptionId = new Map<string, string>();
_emulatedNetworkConditions: InternalNetworkConditions = {
offline: false,
upload: -1,
@ -193,12 +227,8 @@ export class NetworkManager extends EventEmitter {
await this._updateProtocolCacheDisabled();
}
async setRequestInterception(
value: boolean,
cacheSafe = false
): Promise<void> {
async setRequestInterception(value: boolean): Promise<void> {
this._userRequestInterceptionEnabled = value;
this._userRequestInterceptionCacheSafe = cacheSafe;
await this._updateProtocolRequestInterception();
}
@ -222,12 +252,13 @@ export class NetworkManager extends EventEmitter {
}
}
_cacheDisabled(): boolean {
return this._userCacheDisabled;
}
async _updateProtocolCacheDisabled(): Promise<void> {
await this._client.send('Network.setCacheDisabled', {
cacheDisabled:
this._userCacheDisabled ||
(this._userRequestInterceptionEnabled &&
!this._userRequestInterceptionCacheSafe),
cacheDisabled: this._cacheDisabled(),
});
}
@ -238,13 +269,17 @@ export class NetworkManager extends EventEmitter {
!event.request.url.startsWith('data:')
) {
const requestId = event.requestId;
const interceptionId = this._requestIdToInterceptionId.get(requestId);
if (interceptionId) {
const requestPausedEvent =
this._requestIdToRequestPausedEvent.get(requestId);
this._requestIdToRequestWillBeSentEvent.set(requestId, event);
if (requestPausedEvent) {
const interceptionId = requestPausedEvent.requestId;
this._onRequest(event, interceptionId);
this._requestIdToInterceptionId.delete(requestId);
} else {
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);
this._requestIdToRequestPausedEvent.delete(requestId);
}
return;
}
this._onRequest(event, null);
@ -288,14 +323,29 @@ export class NetworkManager extends EventEmitter {
const requestId = event.networkId;
const interceptionId = event.requestId;
if (requestId && this._requestIdToRequestWillBeSentEvent.has(requestId)) {
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(
requestId
);
if (!requestId) {
return;
}
let requestWillBeSentEvent =
this._requestIdToRequestWillBeSentEvent.get(requestId);
// redirect requests have the same `requestId`,
if (
requestWillBeSentEvent &&
(requestWillBeSentEvent.request.url !== event.request.url ||
requestWillBeSentEvent.request.method !== event.request.method)
) {
this._requestIdToRequestWillBeSentEvent.delete(requestId);
requestWillBeSentEvent = null;
}
if (requestWillBeSentEvent) {
this._onRequest(requestWillBeSentEvent, interceptionId);
this._requestIdToRequestWillBeSentEvent.delete(requestId);
} else {
this._requestIdToInterceptionId.set(requestId, interceptionId);
this._requestIdToRequestPausedEvent.set(requestId, event);
}
}
@ -346,8 +396,7 @@ export class NetworkManager extends EventEmitter {
response._resolveBody(
new Error('Response body is unavailable for redirect responses')
);
this._requestIdToRequest.delete(request._requestId);
this._attemptedAuthentications.delete(request._interceptionId);
this._forgetRequest(request, false);
this.emit(NetworkManagerEmittedEvents.Response, response);
this.emit(NetworkManagerEmittedEvents.RequestFinished, request);
}
@ -361,6 +410,19 @@ export class NetworkManager extends EventEmitter {
this.emit(NetworkManagerEmittedEvents.Response, response);
}
_forgetRequest(request: HTTPRequest, events: boolean): void {
const requestId = request._requestId;
const interceptionId = request._interceptionId;
this._requestIdToRequest.delete(requestId);
this._attemptedAuthentications.delete(interceptionId);
if (events) {
this._requestIdToRequestWillBeSentEvent.delete(requestId);
this._requestIdToRequestPausedEvent.delete(requestId);
}
}
_onLoadingFinished(event: Protocol.Network.LoadingFinishedEvent): void {
const request = this._requestIdToRequest.get(event.requestId);
// For certain requestIds we never receive requestWillBeSent event.
@ -370,8 +432,7 @@ export class NetworkManager extends EventEmitter {
// Under certain conditions we never get the Network.responseReceived
// event from protocol. @see https://crbug.com/883475
if (request.response()) request.response()._resolveBody(null);
this._requestIdToRequest.delete(request._requestId);
this._attemptedAuthentications.delete(request._interceptionId);
this._forgetRequest(request, true);
this.emit(NetworkManagerEmittedEvents.RequestFinished, request);
}
@ -383,8 +444,7 @@ export class NetworkManager extends EventEmitter {
request._failureText = event.errorText;
const response = request.response();
if (response) response._resolveBody(null);
this._requestIdToRequest.delete(request._requestId);
this._attemptedAuthentications.delete(request._interceptionId);
this._forgetRequest(request, true);
this.emit(NetworkManagerEmittedEvents.RequestFailed, request);
}
}

Просмотреть файл

@ -488,8 +488,16 @@ export class Page extends EventEmitter {
this._viewport = null;
client.on('Target.attachedToTarget', (event) => {
if (event.targetInfo.type !== 'worker') {
if (
event.targetInfo.type !== 'worker' &&
event.targetInfo.type !== 'iframe'
) {
// If we don't detach from service workers, they will never die.
// We still want to attach to workers for emitting events.
// We still want to attach to iframes so sessions may interact with them.
// We detach from all other types out of an abundance of caution.
// See https://source.chromium.org/chromium/chromium/src/+/master:content/browser/devtools/devtools_agent_host_impl.cc?q=f:devtools%20-f:out%20%22::kTypePage%5B%5D%22&ss=chromium
// for the complete list of available types.
client
.send('Target.detachFromTarget', {
sessionId: event.sessionId,
@ -758,8 +766,6 @@ export class Page extends EventEmitter {
/**
* @param value - Whether to enable request interception.
* @param cacheSafe - Whether to trust browser caching. If set to false,
* enabling request interception disables page caching. Defaults to false.
*
* @remarks
* Activating request interception enables {@link HTTPRequest.abort},
@ -789,13 +795,8 @@ export class Page extends EventEmitter {
* })();
* ```
*/
async setRequestInterception(
value: boolean,
cacheSafe = false
): Promise<void> {
return this._frameManager
.networkManager()
.setRequestInterception(value, cacheSafe);
async setRequestInterception(value: boolean): Promise<void> {
return this._frameManager.networkManager().setRequestInterception(value);
}
/**
@ -834,7 +835,7 @@ export class Page extends EventEmitter {
* @remarks
* Shortcut for {@link Frame.$ | Page.mainFrame().$(selector) }.
*
* @param selector - A
* @param selector - A `selector` to query page for
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector}
* to query page for.
*/
@ -1819,11 +1820,15 @@ export class Page extends EventEmitter {
clip = { x: 0, y: 0, width, height, scale: 1 };
if (!captureBeyondViewport) {
const { isMobile = false, deviceScaleFactor = 1, isLandscape = false } =
this._viewport || {};
const screenOrientation: Protocol.Emulation.ScreenOrientation = isLandscape
? { angle: 90, type: 'landscapePrimary' }
: { angle: 0, type: 'portraitPrimary' };
const {
isMobile = false,
deviceScaleFactor = 1,
isLandscape = false,
} = this._viewport || {};
const screenOrientation: Protocol.Emulation.ScreenOrientation =
isLandscape
? { angle: 90, type: 'landscapePrimary' }
: { angle: 0, type: 'portraitPrimary' };
await this._client.send('Emulation.setDeviceMetricsOverride', {
mobile: isMobile,
width,

Просмотреть файл

@ -215,9 +215,10 @@ export function clearCustomQueryHandlers(): void {
/**
* @internal
*/
export function getQueryHandlerAndSelector(
selector: string
): { updatedSelector: string; queryHandler: InternalQueryHandler } {
export function getQueryHandlerAndSelector(selector: string): {
updatedSelector: string;
queryHandler: InternalQueryHandler;
} {
const hasCustomQueryHandler = /^[a-zA-Z]+\//.test(selector);
if (!hasCustomQueryHandler)
return { updatedSelector: selector, queryHandler: _defaultHandler };

Просмотреть файл

@ -191,6 +191,9 @@ export class Target {
return this._browserContext.browser();
}
/**
* Get the browser context the target belongs to.
*/
browserContext(): BrowserContext {
return this._browserContext;
}

Просмотреть файл

@ -95,7 +95,7 @@ export class WebWorker extends EventEmitter {
this._executionContextCallback(executionContext);
});
// This might fail if the target is closed before we recieve 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.on('Runtime.consoleAPICalled', (event) =>
consoleAPICalled(
@ -151,7 +151,7 @@ export class WebWorker extends EventEmitter {
/**
* The only difference between `worker.evaluate` and `worker.evaluateHandle`
* is that `worker.evaluateHandle` returns in-page object (JSHandle). If the
* function passed to the `worker.evaluateHandle` returns a [Promise], then
* function passed to the `worker.evaluateHandle` returns a `Promise`, then
* `worker.evaluateHandle` would wait for the promise to resolve and return
* its value. Shortcut for
* `await worker.executionContext()).evaluateHandle(pageFunction, ...args)`

Просмотреть файл

@ -58,8 +58,7 @@ const browserConfig = {
destination: '.local-chromium',
},
firefox: {
host:
'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central',
host: 'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central',
destination: '.local-firefox',
},
} as const;
@ -221,14 +220,16 @@ export class BrowserFetcher {
}
/**
* @returns Returns the current `Platform`.
* @returns Returns the current `Platform`, which is one of `mac`, `linux`,
* `win32` or `win64`.
*/
platform(): Platform {
return this._platform;
}
/**
* @returns Returns the current `Product`.
* @returns Returns the current `Product`, which is one of `chrome` or
* `firefox`.
*/
product(): Product {
return this._product;

Просмотреть файл

@ -62,14 +62,8 @@ export class BrowserRunner {
}
start(options: LaunchOptions): void {
const {
handleSIGINT,
handleSIGTERM,
handleSIGHUP,
dumpio,
env,
pipe,
} = options;
const { handleSIGINT, handleSIGTERM, handleSIGHUP, dumpio, env, pipe } =
options;
let stdio: Array<'ignore' | 'pipe'> = ['pipe', 'pipe', 'pipe'];
if (pipe) {
if (dumpio) stdio = ['ignore', 'pipe', 'pipe', 'pipe', 'pipe'];

Просмотреть файл

@ -110,6 +110,12 @@ export interface LaunchOptions {
* {@link https://developer.mozilla.org/en-US/docs/Mozilla/Preferences/Preference_reference | Additional preferences } that can be passed when launching with Firefox.
*/
extraPrefsFirefox?: Record<string, unknown>;
/**
* Whether to wait for the initial page to be ready.
* Useful when a user explicitly disables that (e.g. `--no-startup-window` for Chrome).
* @defaultValue true
*/
waitForInitialPage?: boolean;
}
/**

Просмотреть файл

@ -75,6 +75,7 @@ class ChromeLauncher implements ProductLauncher {
defaultViewport = { width: 800, height: 600 },
slowMo = 0,
timeout = 30000,
waitForInitialPage = true,
} = options;
const profilePath = path.join(os.tmpdir(), 'puppeteer_dev_chrome_profile-');
@ -147,7 +148,8 @@ class ChromeLauncher implements ProductLauncher {
runner.proc,
runner.close.bind(runner)
);
await browser.waitForTarget((t) => t.type() === 'page');
if (waitForInitialPage)
await browser.waitForTarget((t) => t.type() === 'page');
return browser;
} catch (error) {
runner.kill();
@ -245,6 +247,7 @@ class FirefoxLauncher implements ProductLauncher {
slowMo = 0,
timeout = 30000,
extraPrefsFirefox = {},
waitForInitialPage = true,
} = options;
const firefoxArguments = [];
@ -313,7 +316,8 @@ class FirefoxLauncher implements ProductLauncher {
runner.proc,
runner.close.bind(runner)
);
await browser.waitForTarget((t) => t.type() === 'page');
if (waitForInitialPage)
await browser.waitForTarget((t) => t.type() === 'page');
return browser;
} catch (error) {
runner.kill();
@ -583,9 +587,10 @@ class FirefoxLauncher implements ProductLauncher {
}
}
function resolveExecutablePath(
launcher: ChromeLauncher | FirefoxLauncher
): { executablePath: string; missingText?: string } {
function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
executablePath: string;
missingText?: string;
} {
let downloadPath: string;
// puppeteer-core doesn't take into account PUPPETEER_* env variables.
if (!launcher._isPuppeteerCore) {

Просмотреть файл

@ -84,12 +84,8 @@ export class PuppeteerNode extends Puppeteer {
productName?: Product;
} & CommonPuppeteerSettings
) {
const {
projectRoot,
preferredRevision,
productName,
...commonSettings
} = settings;
const { projectRoot, preferredRevision, productName, ...commonSettings } =
settings;
super(commonSettings);
this._projectRoot = projectRoot;
this.__productName = productName;

Просмотреть файл

@ -26,7 +26,7 @@ const supportedProducts = {
firefox: 'Firefox Nightly',
} as const;
export async function downloadBrowser() {
export async function downloadBrowser(): Promise<void> {
const downloadHost =
process.env.PUPPETEER_DOWNLOAD_HOST ||
process.env.npm_config_puppeteer_download_host ||
@ -178,7 +178,7 @@ export async function downloadBrowser() {
}
}
export function logPolitely(toBeLogged) {
export function logPolitely(toBeLogged: unknown): void {
const logLevel = process.env.npm_config_loglevel;
const logLevelDisplay = ['silent', 'error', 'warn'].indexOf(logLevel) > -1;

Просмотреть файл

@ -20,6 +20,6 @@ type Revisions = Readonly<{
}>;
export const PUPPETEER_REVISIONS: Revisions = {
chromium: '869685',
chromium: '884014',
firefox: 'latest',
};

Просмотреть файл

@ -7,7 +7,7 @@
"compile": "../../node_modules/.bin/tsc"
},
"devDependencies": {
"typescript": "^4.1.3"
"typescript": "4.2.4"
},
"dependencies": {
"puppeteer": "file:../../puppeteer.tgz"

Просмотреть файл

@ -14,5 +14,12 @@ async function run() {
*/
const div = await page.$('div');
console.log('got a div!', div);
const contentsOfDiv = await div.evaluate(
/**
* @param {number} divElem
* @returns number
*/
(divElem) => divElem.innerText
);
}
run();

Просмотреть файл

@ -7,7 +7,7 @@
"compile": "../../node_modules/.bin/tsc"
},
"devDependencies": {
"typescript": "^4.1.3"
"typescript": "4.2.4"
},
"dependencies": {
"puppeteer": "file:../../puppeteer.tgz"

Просмотреть файл

@ -7,7 +7,7 @@
"compile": "../../node_modules/.bin/tsc"
},
"devDependencies": {
"typescript": "^4.1.3"
"typescript": "4.2.4"
},
"dependencies": {
"puppeteer": "file:../../puppeteer.tgz"

Просмотреть файл

@ -7,7 +7,7 @@
"compile": "../../node_modules/.bin/tsc"
},
"devDependencies": {
"typescript": "^4.1.3"
"typescript": "4.2.4"
},
"dependencies": {
"puppeteer": "file:../../puppeteer.tgz"

Просмотреть файл

@ -7,7 +7,7 @@
"compile": "../../node_modules/.bin/tsc"
},
"devDependencies": {
"typescript": "^4.1.3"
"typescript": "4.2.4"
},
"dependencies": {
"puppeteer": "file:../../puppeteer.tgz"

Просмотреть файл

@ -10,9 +10,21 @@ async function run() {
const browser2 = await puppeteer.launch();
// 'foo' is invalid argument
const page = await browser2.newPage('foo');
const div = (await page.$('div')) as puppeteer.ElementHandle<
HTMLAnchorElement
>;
const div = (await page.$(
'div'
)) as puppeteer.ElementHandle<HTMLAnchorElement>;
console.log('got a div!', div);
const contentsOfDiv = await div.evaluate(
// Bad: the type system will know here that divElem is an HTMLAnchorElement
// and won't let me tell it it's a number
(divElem: number) => divElem.innerText
);
// Bad: the type system will know here that divElem is an HTMLAnchorElement
// and won't let me tell it it's a number via the generic
const contentsOfDiv2 = await div.evaluate<(x: number) => string>(
// Bad: now I've forced it to be a number (which is an error also)
// I can't call `innerText` on it.
(divElem: number) => divElem.innerText
);
}
run();

Просмотреть файл

@ -9,5 +9,7 @@ async function run() {
const page = await browser.newPage();
const div = (await page.$('div')) as ElementHandle<HTMLAnchorElement>;
console.log('got a div!', div);
const contentsOfDiv = await div.evaluate((divElem) => divElem.innerText);
}
run();

Просмотреть файл

@ -7,7 +7,7 @@
"compile": "../../node_modules/.bin/tsc"
},
"devDependencies": {
"typescript": "^4.1.3"
"typescript": "4.2.4"
},
"dependencies": {
"puppeteer": "file:../../puppeteer.tgz"

Просмотреть файл

@ -103,4 +103,11 @@ describeChromeOnly('Target.createCDPSession', function () {
await client.send('ThisCommand.DoesNotExist');
}
});
it('should expose the underlying connection', async () => {
const { page } = getTestState();
const client = await page.target().createCDPSession();
expect(client.connection()).toBeTruthy();
});
});

Просмотреть файл

@ -87,10 +87,10 @@ describeFailsFirefox('Accessibility', function () {
],
}
: {
role: 'WebArea',
role: 'RootWebArea',
name: 'Accessibility Test',
children: [
{ role: 'text', name: 'Hello World' },
{ role: 'StaticText', name: 'Hello World' },
{ role: 'heading', name: 'Inputs', level: 1 },
{ role: 'textbox', name: 'Empty input', focused: true },
{ role: 'textbox', name: 'readonly input', readonly: true },
@ -148,7 +148,7 @@ describeFailsFirefox('Accessibility', function () {
name: '',
children: [
{
role: 'text',
role: 'StaticText',
name: 'hi',
},
],
@ -230,7 +230,7 @@ describeFailsFirefox('Accessibility', function () {
],
}
: {
role: 'WebArea',
role: 'RootWebArea',
name: '',
children: [
{
@ -263,7 +263,7 @@ describeFailsFirefox('Accessibility', function () {
name: 'Edit this image: ',
},
{
role: 'text',
role: 'StaticText',
name: 'my fake image',
},
],
@ -274,7 +274,7 @@ describeFailsFirefox('Accessibility', function () {
value: 'Edit this image: ',
children: [
{
role: 'text',
role: 'StaticText',
name: 'Edit this image:',
},
{
@ -300,7 +300,7 @@ describeFailsFirefox('Accessibility', function () {
value: 'Edit this image: my fake image',
children: [
{
role: 'text',
role: 'StaticText',
name: 'my fake image',
},
],
@ -309,9 +309,10 @@ describeFailsFirefox('Accessibility', function () {
role: 'textbox',
name: '',
value: 'Edit this image: ',
multiline: true,
children: [
{
role: 'text',
role: 'StaticText',
name: 'Edit this image:',
},
{
@ -336,28 +337,7 @@ describeFailsFirefox('Accessibility', function () {
role: 'textbox',
name: '',
value: 'Edit this image:',
});
});
it('plain text field without role should not have content', async () => {
const { page } = getTestState();
await page.setContent(`
<div contenteditable="plaintext-only">Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`);
const snapshot = await page.accessibility.snapshot();
expect(snapshot.children[0]).toEqual({
role: 'generic',
name: '',
});
});
it('plain text field with tabindex and without role should not have content', async () => {
const { page } = getTestState();
await page.setContent(`
<div contenteditable="plaintext-only" tabIndex=0>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`);
const snapshot = await page.accessibility.snapshot();
expect(snapshot.children[0]).toEqual({
role: 'generic',
name: '',
multiline: true,
});
});
});
@ -502,7 +482,7 @@ describeFailsFirefox('Accessibility', function () {
{
role: 'button',
name: 'My Button',
children: [{ role: 'text', name: 'My Button' }],
children: [{ role: 'StaticText', name: 'My Button' }],
},
],
});

Просмотреть файл

@ -0,0 +1,9 @@
@font-face {
font-family: 'one-style';
src: url('./one-style.woff') format('woff');
}
body {
background-color: pink;
font-family: 'one-style', sans-serif;
}

Просмотреть файл

@ -0,0 +1,2 @@
<link rel='stylesheet' href='./one-style-font.css'>
<div>hello, world!</div>

Просмотреть файл

@ -74,10 +74,9 @@ describe('Page.click', function () {
const { page } = getTestState();
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(
() => {}
);
});
it('should click the button after navigation ', async () => {
const { page, server } = getTestState();

Просмотреть файл

@ -231,13 +231,12 @@ describe('Cookie specs', () => {
value: 'bar',
}
);
expectCookieEquals(
await page.evaluate(() => {
const cookies = document.cookie.split(';');
return cookies.map((cookie) => cookie.trim()).sort();
}),
['foo=bar', 'password=123456']
);
const cookieStrings = await page.evaluate(() => {
const cookies = document.cookie.split(';');
return cookies.map((cookie) => cookie.trim()).sort();
});
expect(cookieStrings).toEqual(['foo=bar', 'password=123456']);
});
it('should have |expires| set to |-1| for session cookies', async () => {
const { page, server } = getTestState();
@ -475,11 +474,8 @@ describe('Cookie specs', () => {
it(
'should set secure same-site cookies from a frame',
async () => {
const {
httpsServer,
puppeteer,
defaultBrowserOptions,
} = getTestState();
const { httpsServer, puppeteer, defaultBrowserOptions } =
getTestState();
const browser = await puppeteer.launch({
...defaultBrowserOptions,

Просмотреть файл

@ -125,6 +125,17 @@ describe('Coverage specs', function () {
JSON.stringify(coverage, null, 2).replace(/:\d{4}\//g, ':<PORT>/')
).toBeGolden('jscoverage-involved.txt');
});
// @see https://crbug.com/990945
xit('should not hang when there is a debugger statement', async () => {
const { page, server } = getTestState();
await page.coverage.startJSCoverage();
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => {
debugger; // eslint-disable-line no-debugger
});
await page.coverage.stopJSCoverage();
});
describe('resetOnNavigation', function () {
it('should report scripts across navigations when disabled', async () => {
const { page, server } = getTestState();
@ -146,17 +157,6 @@ describe('Coverage specs', function () {
expect(coverage.length).toBe(0);
});
});
// @see https://crbug.com/990945
xit('should not hang when there is a debugger statement', async () => {
const { page, server } = getTestState();
await page.coverage.startJSCoverage();
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => {
debugger; // eslint-disable-line no-debugger
});
await page.coverage.stopJSCoverage();
});
});
describeChromeOnly('CSSCoverage', function () {

Просмотреть файл

@ -171,6 +171,7 @@ describe('ElementHandle specs', function () {
});
describe('ElementHandle.click', function () {
// See https://github.com/puppeteer/puppeteer/issues/7175
it('should work', async () => {
const { page, server } = getTestState();
@ -319,7 +320,8 @@ describe('ElementHandle specs', function () {
)
);
}
const handlerNamesAfterUnregistering = puppeteer.customQueryHandlerNames();
const handlerNamesAfterUnregistering =
puppeteer.customQueryHandlerNames();
expect(handlerNamesAfterUnregistering.includes('getById')).toBeFalsy();
});
it('should throw with invalid query names', () => {

Просмотреть файл

@ -386,4 +386,26 @@ describe('Emulation', () => {
expect(error.message).toBe('Unsupported vision deficiency: invalid');
});
});
describe('Page.emulateNetworkConditions', function () {
it('should change navigator.connection.effectiveType', async () => {
const { page, puppeteer } = getTestState();
const slow3G = puppeteer.networkConditions['Slow 3G'];
const fast3G = puppeteer.networkConditions['Fast 3G'];
expect(
await page.evaluate('window.navigator.connection.effectiveType')
).toBe('4g');
await page.emulateNetworkConditions(fast3G);
expect(
await page.evaluate('window.navigator.connection.effectiveType')
).toBe('3g');
await page.emulateNetworkConditions(slow3G);
expect(
await page.evaluate('window.navigator.connection.effectiveType')
).toBe('2g');
await page.emulateNetworkConditions(null);
});
});
});

Просмотреть файл

@ -42,9 +42,11 @@ describeChromeOnly('headful tests', function () {
let headfulOptions;
let headlessOptions;
let extensionOptions;
let forcedOopifOptions;
const browsers = [];
beforeEach(() => {
const { defaultBrowserOptions } = getTestState();
const { server, defaultBrowserOptions } = getTestState();
headfulOptions = Object.assign({}, defaultBrowserOptions, {
headless: false,
});
@ -59,12 +61,43 @@ describeChromeOnly('headful tests', function () {
`--load-extension=${extensionPath}`,
],
});
forcedOopifOptions = Object.assign({}, defaultBrowserOptions, {
headless: false,
devtools: true,
args: [
`--host-rules=MAP oopifdomain 127.0.0.1`,
`--isolate-origins=${server.PREFIX.replace(
'localhost',
'oopifdomain'
)}`,
],
});
});
async function launchBrowser(puppeteer, options) {
const browser = await puppeteer.launch(options);
browsers.push(browser);
return browser;
}
afterEach(() => {
for (const i in browsers) {
const browser = browsers[i];
if (browser.isConnected()) {
browser.close();
}
delete browsers[i];
}
});
describe('HEADFUL', function () {
it('background_page target type should be available', async () => {
const { puppeteer } = getTestState();
const browserWithExtension = await puppeteer.launch(extensionOptions);
const browserWithExtension = await launchBrowser(
puppeteer,
extensionOptions
);
const page = await browserWithExtension.newPage();
const backgroundPageTarget = await browserWithExtension.waitForTarget(
(target) => target.type() === 'background_page'
@ -75,7 +108,10 @@ describeChromeOnly('headful tests', function () {
});
it('target.page() should return a background_page', async function () {
const { puppeteer } = getTestState();
const browserWithExtension = await puppeteer.launch(extensionOptions);
const browserWithExtension = await launchBrowser(
puppeteer,
extensionOptions
);
const backgroundPageTarget = await browserWithExtension.waitForTarget(
(target) => target.type() === 'background_page'
);
@ -86,7 +122,7 @@ describeChromeOnly('headful tests', function () {
});
it('should have default url when launching browser', async function () {
const { puppeteer } = getTestState();
const browser = await puppeteer.launch(extensionOptions);
const browser = await launchBrowser(puppeteer, extensionOptions);
const pages = (await browser.pages()).map((page) => page.url());
expect(pages).toEqual(['about:blank']);
await browser.close();
@ -99,7 +135,8 @@ describeChromeOnly('headful tests', function () {
const userDataDir = await mkdtempAsync(TMP_FOLDER);
// Write a cookie in headful chrome
const headfulBrowser = await puppeteer.launch(
const headfulBrowser = await launchBrowser(
puppeteer,
Object.assign({ userDataDir }, headfulOptions)
);
const headfulPage = await headfulBrowser.newPage();
@ -111,7 +148,8 @@ describeChromeOnly('headful tests', function () {
);
await headfulBrowser.close();
// Read the cookie from headless chrome
const headlessBrowser = await puppeteer.launch(
const headlessBrowser = await launchBrowser(
puppeteer,
Object.assign({ userDataDir }, headlessOptions)
);
const headlessPage = await headlessBrowser.newPage();
@ -128,7 +166,7 @@ describeChromeOnly('headful tests', function () {
const { server, puppeteer } = getTestState();
// https://google.com is isolated by default in Chromium embedder.
const browser = await puppeteer.launch(headfulOptions);
const browser = await launchBrowser(puppeteer, headfulOptions);
const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(true);
@ -147,10 +185,62 @@ describeChromeOnly('headful tests', function () {
expect(urls).toEqual([server.EMPTY_PAGE, 'https://google.com/']);
await browser.close();
});
it('OOPIF: should expose events within OOPIFs', async () => {
const { server, puppeteer } = getTestState();
const browser = await launchBrowser(puppeteer, forcedOopifOptions);
const page = await browser.newPage();
// Setup our session listeners to observe OOPIF activity.
const session = await page.target().createCDPSession();
const networkEvents = [];
const otherSessions = [];
await session.send('Target.setAutoAttach', {
autoAttach: true,
flatten: true,
waitForDebuggerOnStart: true,
});
session.on('sessionattached', async (session) => {
otherSessions.push(session);
session.on('Network.requestWillBeSent', (params) =>
networkEvents.push(params)
);
await session.send('Network.enable');
await session.send('Runtime.runIfWaitingForDebugger');
});
// Navigate to the empty page and add an OOPIF iframe with at least one request.
await page.goto(server.EMPTY_PAGE);
await page.evaluate((frameUrl) => {
const frame = document.createElement('iframe');
frame.setAttribute('src', frameUrl);
document.body.appendChild(frame);
return new Promise((x, y) => {
frame.onload = x;
frame.onerror = y;
});
}, server.PREFIX.replace('localhost', 'oopifdomain') + '/one-style.html');
await page.waitForSelector('iframe');
// Ensure we found the iframe session.
expect(otherSessions).toHaveLength(1);
// Resume the iframe and trigger another request.
const iframeSession = otherSessions[0];
await iframeSession.send('Runtime.evaluate', {
expression: `fetch('/fetch')`,
awaitPromise: true,
});
await browser.close();
const requests = networkEvents.map((event) => event.request.url);
expect(requests).toContain(`http://oopifdomain:${server.PORT}/fetch`);
});
it('should close browser with beforeunload page', async () => {
const { server, puppeteer } = getTestState();
const browser = await puppeteer.launch(headfulOptions);
const browser = await launchBrowser(puppeteer, headfulOptions);
const page = await browser.newPage();
await page.goto(server.PREFIX + '/beforeunload.html');
// We have to interact with a page so that 'beforeunload' handlers
@ -161,13 +251,14 @@ describeChromeOnly('headful tests', function () {
it('should open devtools when "devtools: true" option is given', async () => {
const { puppeteer } = getTestState();
const browser = await puppeteer.launch(
const browser = await launchBrowser(
puppeteer,
Object.assign({ devtools: true }, headfulOptions)
);
const context = await browser.createIncognitoBrowserContext();
await Promise.all([
context.newPage(),
context.waitForTarget((target) => target.url().includes('devtools://')),
browser.waitForTarget((target) => target.url().includes('devtools://')),
]);
await browser.close();
});
@ -176,7 +267,7 @@ describeChromeOnly('headful tests', function () {
describe('Page.bringToFront', function () {
it('should work', async () => {
const { puppeteer } = getTestState();
const browser = await puppeteer.launch(headfulOptions);
const browser = await launchBrowser(puppeteer, headfulOptions);
const page1 = await browser.newPage();
const page2 = await browser.newPage();

Просмотреть файл

@ -21,6 +21,7 @@ import { promisify } from 'util';
import Protocol from 'devtools-protocol';
import {
getTestState,
itChromeOnly,
itFailsFirefox,
itOnlyRegularInstall,
} from './mocha-utils'; // eslint-disable-line import/extensions
@ -430,6 +431,24 @@ describe('Launcher specs', function () {
expect(screenshot).toBeInstanceOf(Buffer);
await browser.close();
});
itChromeOnly(
'should launch Chrome properly with --no-startup-window and waitForInitialPage=false',
async () => {
const { defaultBrowserOptions, puppeteer } = getTestState();
const options = {
args: ['--no-startup-window'],
waitForInitialPage: false,
// This is needed to prevent Puppeteer from adding an initial blank page.
// See also https://github.com/puppeteer/puppeteer/blob/ad6b736039436fcc5c0a262e5b575aa041427be3/src/node/Launcher.ts#L200
ignoreDefaultArgs: true,
...defaultBrowserOptions,
};
const browser = await puppeteer.launch(options);
const pages = await browser.pages();
expect(pages.length).toBe(0);
await browser.close();
}
);
});
describe('Puppeteer.launch', function () {
@ -512,11 +531,8 @@ describe('Launcher specs', function () {
]);
});
it('should support ignoreHTTPSErrors option', async () => {
const {
httpsServer,
puppeteer,
defaultBrowserOptions,
} = getTestState();
const { httpsServer, puppeteer, defaultBrowserOptions } =
getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint();

Просмотреть файл

@ -31,6 +31,7 @@ import rimraf from 'rimraf';
import expect from 'expect';
import { trackCoverage } from './coverage-utils.js';
import Protocol from 'devtools-protocol';
const setupServer = async () => {
const assetsPath = path.join(__dirname, 'assets');
@ -177,7 +178,10 @@ export const itFailsWindowsUntilDate = (
return it(description, body);
};
export const itFailsWindows = (description: string, body: Mocha.Func) => {
export const itFailsWindows = (
description: string,
body: Mocha.Func
): Mocha.Test => {
if (os.platform() === 'win32') {
return xit(description, body);
}
@ -217,7 +221,7 @@ console.log(
}`
);
export const setupTestBrowserHooks = () => {
export const setupTestBrowserHooks = (): void => {
before(async () => {
const browser = await puppeteer.launch(defaultBrowserOptions);
state.browser = browser;
@ -229,7 +233,7 @@ export const setupTestBrowserHooks = () => {
});
};
export const setupTestPageAndContextHooks = () => {
export const setupTestPageAndContextHooks = (): void => {
beforeEach(async () => {
state.context = await state.browser.createIncognitoBrowserContext();
state.page = await state.context.newPage();
@ -244,7 +248,7 @@ export const setupTestPageAndContextHooks = () => {
export const mochaHooks = {
beforeAll: [
async () => {
async (): Promise<void> => {
const { server, httpsServer } = await setupServer();
state.puppeteer = puppeteer;
@ -259,13 +263,13 @@ export const mochaHooks = {
coverageHooks.beforeAll,
],
beforeEach: async () => {
beforeEach: async (): Promise<void> => {
state.server.reset();
state.httpsServer.reset();
},
afterAll: [
async () => {
async (): Promise<void> => {
await state.server.stop();
state.server = null;
await state.httpsServer.stop();
@ -274,12 +278,15 @@ export const mochaHooks = {
coverageHooks.afterAll,
],
afterEach: () => {
afterEach: (): void => {
sinon.restore();
},
};
export const expectCookieEquals = (cookies, expectedCookies) => {
export const expectCookieEquals = (
cookies: Protocol.Network.Cookie[],
expectedCookies: Array<Partial<Protocol.Network.Cookie>>
): void => {
const { isChrome } = getTestState();
if (!isChrome) {
// Only keep standard properties when testing on a browser other than Chrome.

Просмотреть файл

@ -314,7 +314,7 @@ describe('Page', function () {
]);
});
it(
'should isolate permissions between browser contexs',
'should isolate permissions between browser contexts',
async () => {
const { page, server, context, browser } = getTestState();
@ -400,28 +400,6 @@ describe('Page', function () {
});
});
describe('Page.emulateNetworkConditions', function () {
it('should change navigator.connection.effectiveType', async () => {
const { page, puppeteer } = getTestState();
const slow3G = puppeteer.networkConditions['Slow 3G'];
const fast3G = puppeteer.networkConditions['Fast 3G'];
expect(
await page.evaluate('window.navigator.connection.effectiveType')
).toBe('4g');
await page.emulateNetworkConditions(fast3G);
expect(
await page.evaluate('window.navigator.connection.effectiveType')
).toBe('3g');
await page.emulateNetworkConditions(slow3G);
expect(
await page.evaluate('window.navigator.connection.effectiveType')
).toBe('2g');
await page.emulateNetworkConditions(null);
});
});
describe('ExecutionContext.queryObjects', function () {
it('should work', async () => {
const { page } = getTestState();
@ -751,7 +729,6 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
const [response] = await Promise.all([
page.waitForResponse(async (response) => {
console.log(response.url());
return response.url() === server.PREFIX + '/digits/2.png';
}),
page.evaluate(() => {
@ -1762,7 +1739,7 @@ describe('Page', function () {
});
describe('Page.browserContext', function () {
it('should return the correct browser instance', async () => {
it('should return the correct browser context instance', async () => {
const { page, context } = getTestState();
expect(page.browserContext()).toBe(context);

Просмотреть файл

@ -495,13 +495,14 @@ describe('request interception', function () {
expect(urls.has('one-style.html')).toBe(true);
expect(urls.has('one-style.css')).toBe(true);
});
it('should not cache if not cache-safe', async () => {
it('should not cache if cache disabled', async () => {
const { page, server } = getTestState();
// Load and re-load to make sure it's cached.
await page.goto(server.PREFIX + '/cached/one-style.html');
await page.setRequestInterception(true, false);
await page.setRequestInterception(true);
await page.setCacheEnabled(false);
page.on('request', (request) => request.continue());
const cached = [];
@ -510,13 +511,14 @@ describe('request interception', function () {
await page.reload();
expect(cached.length).toBe(0);
});
it('should cache if cache-safe', async () => {
it('should cache if cache enabled', async () => {
const { page, server } = getTestState();
// Load and re-load to make sure it's cached.
await page.goto(server.PREFIX + '/cached/one-style.html');
await page.setRequestInterception(true, true);
await page.setRequestInterception(true);
await page.setCacheEnabled(true);
page.on('request', (request) => request.continue());
const cached = [];
@ -525,6 +527,16 @@ describe('request interception', function () {
await page.reload();
expect(cached.length).toBe(1);
});
it('should load fonts if cache enabled', async () => {
const { page, server } = getTestState();
await page.setRequestInterception(true);
await page.setCacheEnabled(true);
page.on('request', (request) => request.continue());
await page.goto(server.PREFIX + '/cached/one-style-font.html');
await page.waitForResponse((r) => r.url().endsWith('/one-style.woff'));
});
});
describe('Request.continue', function () {

Просмотреть файл

@ -358,11 +358,10 @@ describe('waittask specs', function () {
const endTime = Date.now();
/* In a perfect world endTime - startTime would be exactly 1000 but we
* expect some fluctuations and for it to be off by a little bit. So to
* avoid a flaky test we'll make sure it waited for roughly 1 second by
* ensuring 900 < endTime - startTime < 1100
* avoid a flaky test we'll make sure it waited for roughly 1 second.
*/
expect(endTime - startTime).toBeGreaterThan(900);
expect(endTime - startTime).toBeLessThan(1100);
expect(endTime - startTime).toBeGreaterThan(700);
expect(endTime - startTime).toBeLessThan(1300);
});
});
@ -376,11 +375,10 @@ describe('waittask specs', function () {
const endTime = Date.now();
/* In a perfect world endTime - startTime would be exactly 1000 but we
* expect some fluctuations and for it to be off by a little bit. So to
* avoid a flaky test we'll make sure it waited for roughly 1 second by
* ensuring 900 < endTime - startTime < 1100
* avoid a flaky test we'll make sure it waited for roughly 1 second
*/
expect(endTime - startTime).toBeGreaterThan(900);
expect(endTime - startTime).toBeLessThan(1100);
expect(endTime - startTime).toBeGreaterThan(700);
expect(endTime - startTime).toBeLessThan(1300);
});
});

Просмотреть файл

@ -3,9 +3,8 @@
"esModuleInterop": true,
"allowJs": true,
"checkJs": true,
"target": "ESNext",
"target": "ES2019",
"moduleResolution": "node",
"module": "ESNext",
"declaration": true,
"declarationMap": true,
"resolveJsonModule": true,

Просмотреть файл

@ -1,11 +1,16 @@
/**
* This configuration only exists for the API Extractor tool. See the details in
* CONTRIBUTING.md that describes our TypeScript setup.
*/
* This configuration only exists for the API Extractor tool and for VSCode to use. It is NOT the tsconfig used for compilation.
* For CJS builds, `tsconfig.cjs.json` is used, and for ESM, it's `tsconfig.esm.json`.
* See the details in CONTRIBUTING.md that describes our TypeScript setup.
*/
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": true
"noEmit": true,
/* This module setting is just for VSCode so it doesn't throw error when we
use dynamic imports.
*/
"module": "esnext"
},
"include": ["src"]
}

Просмотреть файл

@ -18,8 +18,8 @@
const assert = require('assert');
const https = require('https');
// run `npm run dev-install` if lib dir is missing
const BrowserFetcher = require('../lib/cjs/puppeteer/node/BrowserFetcher.js')
.BrowserFetcher;
const BrowserFetcher =
require('../lib/cjs/puppeteer/node/BrowserFetcher.js').BrowserFetcher;
const SUPPORTER_PLATFORMS = ['linux', 'mac', 'win32', 'win64'];
const fetchers = SUPPORTER_PLATFORMS.map(

Просмотреть файл

@ -28,10 +28,12 @@ const EXCLUDE_PROPERTIES = new Set([
'Page.create',
'JSHandle.toString',
'TimeoutError.name',
/* This isn't an actual property, but a TypeScript generic.
/* These are not actual properties, but a TypeScript generic.
* DocLint incorrectly parses it as a property.
*/
'ElementHandle.ElementType',
'ElementHandle.HandleObjectType',
'JSHandle.HandleObjectType',
]);
/**
@ -685,7 +687,8 @@ function compareDocumentations(actual, expected) {
'Method Page.emulateVisionDeficiency() type',
{
actualName: 'string',
expectedName: 'Object',
expectedName:
'"none"|"achromatopsia"|"blurredVision"|"deuteranopia"|"protanopia"|"tritanopia"',
},
],
[
@ -849,14 +852,6 @@ function compareDocumentations(actual, expected) {
expectedName: '...DeleteCookiesRequest',
},
],
[
'Method Page.emulateVisionDeficiency() type',
{
actualName: 'string',
expectedName:
'"none"|"achromatopsia"|"blurredVision"|"deuteranopia"|"protanopia"|"tritanopia"',
},
],
[
'Method BrowserContext.overridePermissions() permissions',
{
@ -885,6 +880,27 @@ function compareDocumentations(actual, expected) {
expectedName: 'Object',
},
],
[
'Method EventEmitter.emit() eventData',
{
actualName: 'Object',
expectedName: 'unknown',
},
],
[
'Method Page.queryObjects() prototypeHandle',
{
actualName: 'JSHandle',
expectedName: 'JSHandle<unknown>',
},
],
[
'Method ExecutionContext.queryObjects() prototypeHandle',
{
actualName: 'JSHandle',
expectedName: 'JSHandle<unknown>',
},
],
]);
const expectedForSource = expectedNamingMismatches.get(source);

Просмотреть файл

@ -20,7 +20,8 @@ const IS_RELEASE = Boolean(process.env.IS_RELEASE);
module.exports.ensureReleasedAPILinks = function (sources, version) {
// Release version is everything that doesn't include "-".
const apiLinkRegex = /https:\/\/github.com\/puppeteer\/puppeteer\/blob\/v[^/]*\/docs\/api.md/gi;
const apiLinkRegex =
/https:\/\/github.com\/puppeteer\/puppeteer\/blob\/v[^/]*\/docs\/api.md/gi;
const lastReleasedAPI = `https://github.com/puppeteer/puppeteer/blob/v${
version.split('-')[0]
}/docs/api.md`;

Просмотреть файл

@ -222,11 +222,9 @@ function loadFromJSONV1(json) {
const result = {};
result.type = /** @type {string} */ (parseValue(json, 'type', 'string'));
result.userAgent = /** @type {string} */ (parseValue(
json,
'user-agent',
'string'
));
result.userAgent = /** @type {string} */ (
parseValue(json, 'user-agent', 'string')
);
const capabilities = parseValue(json, 'capabilities', 'object', []);
if (!Array.isArray(capabilities))
@ -238,11 +236,9 @@ function loadFromJSONV1(json) {
result.capabilities.push(capabilities[i]);
}
result.deviceScaleFactor = /** @type {number} */ (parseValue(
json['screen'],
'device-pixel-ratio',
'number'
));
result.deviceScaleFactor = /** @type {number} */ (
parseValue(json['screen'], 'device-pixel-ratio', 'number')
);
if (result.deviceScaleFactor < 0 || result.deviceScaleFactor > 100)
throw new Error(
'Emulated device has wrong deviceScaleFactor: ' + result.deviceScaleFactor

Просмотреть файл

@ -17,6 +17,7 @@
const versionsPerRelease = new Map([
// This is a mapping from Chromium version => Puppeteer version.
// In Chromium roll patches, use 'NEXT' for the Puppeteer version.
['92.0.4512.0', 'v10.0.0'],
['91.0.4469.0', 'v9.0.0'],
['90.0.4427.0', 'v8.0.0'],
['90.0.4403.0', 'v7.0.0'],