Bug 1707588 - [puppeteer] Sync vendored puppeteer to v9.1.1 r=webdriver-reviewers,whimboo

PR to upstream the comment update: https://github.com/puppeteer/puppeteer/pull/7324

Differential Revision: https://phabricator.services.mozilla.com/D117539
This commit is contained in:
Julian Descottes 2021-06-15 07:35:20 +00:00
Родитель 952b525e6f
Коммит a128c5a742
71 изменённых файлов: 1278 добавлений и 711 удалений

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

@ -156,7 +156,7 @@
"PASS"
],
"Page.click should double click the button (click.spec.ts)": [
"PASS"
"FAIL", "PASS"
],
"Page.click should click a partially obscured button (click.spec.ts)": [
"PASS"
@ -171,13 +171,13 @@
"PASS"
],
"Page.click should click the button inside an iframe (click.spec.ts)": [
"PASS"
"FAIL", "PASS"
],
"Page.click should click the button with fixed position inside an iframe (click.spec.ts)": [
"SKIP"
],
"Page.click should click the button with deviceScaleFactor set (click.spec.ts)": [
"PASS"
"FAIL", "PASS"
],
"Cookie specs Page.cookies should return no cookies in pristine browser context (cookies.spec.ts)": [
"PASS"
@ -914,6 +914,9 @@
"Launcher specs Puppeteer Puppeteer.connect should support ignoreHTTPSErrors option (launcher.spec.ts)": [
"PASS"
],
"Launcher specs Puppeteer Puppeteer.connect should support targetFilter option (launcher.spec.ts)": [
"PASS"
],
"Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser (launcher.spec.ts)": [
"PASS"
],
@ -1175,6 +1178,9 @@
"network Network Events Page.Events.Request (network.spec.ts)": [
"FAIL", "PASS"
],
"network Network Events Page.Events.RequestServedFromCache (network.spec.ts)": [
"FAIL"
],
"network Network Events Page.Events.Response (network.spec.ts)": [
"PASS", "FAIL"
],
@ -1214,6 +1220,9 @@
"network Page.authenticate should allow disable authentication (network.spec.ts)": [
"FAIL"
],
"network Page.authenticate should not disable caching (network.spec.ts)": [
"FAIL"
],
"Page Page.close should reject all promises when page is closed (page.spec.ts)": [
"PASS"
],
@ -1772,6 +1781,12 @@
"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)": [
"FAIL"
],
"request interception Page.setRequestInterception should cache if cache-safe (requestinterception.spec.ts)": [
"FAIL"
],
"request interception Request.continue should work (requestinterception.spec.ts)": [
"FAIL"
],

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

@ -0,0 +1,8 @@
node_modules/
lib/
third_party/
vendor/
package-lock.json
yarn.lock
package.json

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

@ -2,6 +2,54 @@
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.
### [9.1.1](https://github.com/puppeteer/puppeteer/compare/v9.1.0...v9.1.1) (2021-05-05)
### Bug Fixes
* make targetFilter synchronous ([#7203](https://github.com/puppeteer/puppeteer/issues/7203)) ([bcc85a0](https://github.com/puppeteer/puppeteer/commit/bcc85a0969077d122e5d8d2fb5c1061999a8ae48))
## [9.1.0](https://github.com/puppeteer/puppeteer/compare/v9.0.0...v9.1.0) (2021-05-03)
### Features
* add option to filter targets ([#7192](https://github.com/puppeteer/puppeteer/issues/7192)) ([ec3fc2e](https://github.com/puppeteer/puppeteer/commit/ec3fc2e035bb5ca14a576180fff612e1ecf6bad7))
### Bug Fixes
* change rm -rf to rimraf ([#7168](https://github.com/puppeteer/puppeteer/issues/7168)) ([ad6b736](https://github.com/puppeteer/puppeteer/commit/ad6b736039436fcc5c0a262e5b575aa041427be3))
## [9.0.0](https://github.com/puppeteer/puppeteer/compare/v8.0.0...v9.0.0) (2021-04-21)
### ⚠ BREAKING CHANGES
* **filechooser:** FileChooser.cancel() is now synchronous.
### Features
* **chromium:** roll to Chromium 91.0.4469.0 (r869685) ([#7110](https://github.com/puppeteer/puppeteer/issues/7110)) ([715e7a8](https://github.com/puppeteer/puppeteer/commit/715e7a8d62901d1c7ec602425c2fce8d8148b742))
* **launcher:** fix installation error on Apple M1 chips ([#7099](https://github.com/puppeteer/puppeteer/issues/7099)) ([c239d9e](https://github.com/puppeteer/puppeteer/commit/c239d9edc72d85697b4875c98fff3ec592848082)), closes [#6622](https://github.com/puppeteer/puppeteer/issues/6622)
* **network:** request interception and caching compatibility ([#6996](https://github.com/puppeteer/puppeteer/issues/6996)) ([8695759](https://github.com/puppeteer/puppeteer/commit/8695759a223bc1bd31baecb00dc28721216e4c6f))
* **page:** emit the event after removing the Worker ([#7080](https://github.com/puppeteer/puppeteer/issues/7080)) ([e34a6d5](https://github.com/puppeteer/puppeteer/commit/e34a6d53183c3e1f63a375ba6a26bee0dcfcf542))
* **types:** improve type of predicate function ([#6997](https://github.com/puppeteer/puppeteer/issues/6997)) ([943477c](https://github.com/puppeteer/puppeteer/commit/943477cc1eb4b129870142873b3554737d5ef252)), closes [/github.com/DefinitelyTyped/DefinitelyTyped/blob/c43191a8f7a7d2a47bbff0bc3a7d95ecc64d2269/types/puppeteer/index.d.ts#L1883-L1885](https://github.com/puppeteer//github.com/DefinitelyTyped/DefinitelyTyped/blob/c43191a8f7a7d2a47bbff0bc3a7d95ecc64d2269/types/puppeteer/index.d.ts/issues/L1883-L1885)
* accept captureBeyondViewport as optional screenshot param ([#7063](https://github.com/puppeteer/puppeteer/issues/7063)) ([0e092d2](https://github.com/puppeteer/puppeteer/commit/0e092d2ea0ec18ad7f07ad3507deb80f96086e7a))
* **page:** add omitBackground option for page.pdf method ([#6981](https://github.com/puppeteer/puppeteer/issues/6981)) ([dc8ab6d](https://github.com/puppeteer/puppeteer/commit/dc8ab6d8ca1661f8e56d329e6d9c49c891e8b975))
### Bug Fixes
* **aria:** fix parsing of ARIA selectors ([#7037](https://github.com/puppeteer/puppeteer/issues/7037)) ([4426135](https://github.com/puppeteer/puppeteer/commit/4426135692ae3ee7ed2841569dd9375e7ca8286c))
* **page:** fix mouse.click method ([#7097](https://github.com/puppeteer/puppeteer/issues/7097)) ([ba7c367](https://github.com/puppeteer/puppeteer/commit/ba7c367de33ace7753fd9d8b8cc894b2c14ab6c2)), closes [#6462](https://github.com/puppeteer/puppeteer/issues/6462) [#3347](https://github.com/puppeteer/puppeteer/issues/3347)
* make `$` and `$$` selectors generic ([#6883](https://github.com/puppeteer/puppeteer/issues/6883)) ([b349c91](https://github.com/puppeteer/puppeteer/commit/b349c91e7df76630b7411d6645e649945c4609bd))
* type page event listeners correctly ([#6891](https://github.com/puppeteer/puppeteer/issues/6891)) ([866d34e](https://github.com/puppeteer/puppeteer/commit/866d34ee1122e89eab00743246676845bb065968))
* **typescript:** allow defaultViewport to be 'null' ([#6942](https://github.com/puppeteer/puppeteer/issues/6942)) ([e31e68d](https://github.com/puppeteer/puppeteer/commit/e31e68dfa12dd50482b700472bc98876b9031829)), closes [#6885](https://github.com/puppeteer/puppeteer/issues/6885)
* make screenshots work in puppeteer-web ([#6936](https://github.com/puppeteer/puppeteer/issues/6936)) ([5f24f60](https://github.com/puppeteer/puppeteer/commit/5f24f608194fd4252da7b288461427cabc9dabb3))
* **filechooser:** cancel is sync ([#6937](https://github.com/puppeteer/puppeteer/issues/6937)) ([2ba61e0](https://github.com/puppeteer/puppeteer/commit/2ba61e04e923edaac09c92315212552f2d4ce676))
* **network:** don't disable cache for auth challenge ([#6962](https://github.com/puppeteer/puppeteer/issues/6962)) ([1c2479a](https://github.com/puppeteer/puppeteer/commit/1c2479a6cd4bd09a577175ffd31c40ca6f4279b8))
## [8.0.0](https://github.com/puppeteer/puppeteer/compare/v7.1.0...v8.0.0) (2021-02-26)

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

@ -1,3 +1,4 @@
<!-- prettier-ignore-start -->
<!-- gen:toc -->
- [How to Contribute](#how-to-contribute)
* [Contributor License Agreement](#contributor-license-agreement)
@ -21,7 +22,7 @@
- [Bisecting upstream changes](#bisecting-upstream-changes)
* [Releasing to npm](#releasing-to-npm)
<!-- gen:stop -->
<!-- prettier-ignore-end -->
# How to Contribute
First of all, thank you for your interest in Puppeteer!
@ -164,6 +165,12 @@ To run the documentation linter, use:
npm run doc
```
To format the documentation markdown and its code snippets, use:
```bash
npm run markdownlint-fix
```
## Adding New Dependencies
For all dependencies (both installation and development):
@ -255,13 +262,15 @@ The following steps are needed to update the Chromium version.
1. Find a suitable Chromium revision
Not all revisions have builds for all platforms, so we need to find one that does.
To do so, run `utils/check_availability.js -rb` to find the latest suitable beta Chromium revision (see `utils/check_availability.js -help` for more options).
To do so, run `utils/check_availability.js -rd` to find the latest suitable `dev` Chromium revision (see `utils/check_availability.js -help` for more options).
1. Update `src/revisions.ts` with the found revision number.
1. Update `versions.js` with the new Chromium-to-Puppeteer version mapping.
1. Run `npm run ensure-correct-devtools-protocol-revision`.
If it fails, update `package.json` with the expected `devtools-protocol` version.
1. Run `npm run tsc` and `npm install` and ensure that all tests pass. If a test fails, [bisect](#bisecting-upstream-changes) the upstream cause of the failure, and either update the test expectations accordingly (if it was an intended change) or work around the changes in Puppeteer (if its not desirable to change Puppeteers observable behavior).
1. Update `versions.js` with the new Chromium-to-Puppeteer version mapping.
1. Run `npm run tsc` and `npm install`.
1. Run `npm run unit` and ensure that all tests pass. If a test fails, [bisect](#bisecting-upstream-changes) the upstream cause of the failure, and either update the test expectations accordingly (if it was an intended change) or work around the changes in Puppeteer (if its not desirable to change Puppeteers observable behavior).
1. Commit and push your changes and open a pull request.
The commit message must contain the version in `Chromium <version> (<revision>)` format to ensure that [pptr.dev](https://pptr.dev/) can parse it correctly, e.g. `'feat(chromium): roll to Chromium 90.0.4427.0 (r856583)'`.
### Bisecting upstream changes

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

@ -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/v8.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)
###### [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)
> 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/v8.0.0/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/v9.1.1/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/v8.0.0/docs/api.md#).
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v9.1.1/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/v8.0.0/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/v9.1.1/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/v8.0.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.
See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v9.1.1/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/v8.0.0/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/v9.1.1/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/v8.0.0/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/v8.0.0/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/v9.1.1/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/v8.0.0/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/v9.1.1/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/v8.0.0/docs/api.md)
- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v9.1.1/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/v8.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.
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.
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/v8.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.)
- 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.)
- 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?
@ -456,7 +456,6 @@ There are many ways to get help on Puppeteer:
- [bugtracker](https://github.com/puppeteer/puppeteer/issues)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/puppeteer)
- [slack channel](https://join.slack.com/t/puppeteer/shared_invite/enQtMzU4MjIyMDA5NTM4LWI0YTE0MjM0NWQzYmE2MTRmNjM1ZTBkN2MxNmJmNTIwNTJjMmFhOWFjMGExMDViYjk2YjU2ZmYzMmE1NmExYzc)
Make sure to search these channels before posting your question.

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

@ -17,7 +17,7 @@ More complex and use case driven examples can be found at [github.com/GoogleChro
## Rendering and web scraping
- [Puppetron](https://github.com/cheeaun/puppetron) - Demo site that shows how to use Puppeteer and Headless Chrome to render pages. Inspired by [GoogleChrome/rendertron](https://github.com/GoogleChrome/rendertron).
- [Thal](https://medium.com/@e_mad_ehsan/getting-started-with-puppeteer-and-chrome-headless-for-web-scrapping-6bf5979dee3e "An article on medium") - Getting started with Puppeteer and Chrome Headless for Web Scraping.
- [Thal](https://medium.com/@e_mad_ehsan/getting-started-with-puppeteer-and-chrome-headless-for-web-scrapping-6bf5979dee3e 'An article on medium') - Getting started with Puppeteer and Chrome Headless for Web Scraping.
- [pupperender](https://github.com/LasaleFamine/pupperender) - Express middleware that checks the User-Agent header of incoming requests, and if it matches one of a configurable set of bots, render the page using Puppeteer. Useful for PWA rendering.
- [headless-chrome-crawler](https://github.com/yujiosaka/headless-chrome-crawler) - Crawler that provides simple APIs to manipulate Headless Chrome and allows you to crawl dynamic websites.
- [puppeteer-examples](https://github.com/checkly/puppeteer-examples) - Puppeteer Headless Chrome examples for real life use cases such as getting useful info from the web pages or common login scenarios.
@ -35,4 +35,5 @@ More complex and use case driven examples can be found at [github.com/GoogleChro
- [cucumber-puppeteer-example](https://github.com/mlampedx/cucumber-puppeteer-example) - Example repository demonstrating how to use Puppeeteer and Cucumber for integration testing.
## Services
- [Checkly](https://checklyhq.com) - Monitoring SaaS that uses Puppeteer to check availability and correctness of web pages and apps.

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

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

1018
remote/test/puppeteer/package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,6 +1,6 @@
{
"name": "puppeteer",
"version": "8.0.0",
"version": "9.1.1",
"description": "A high-level API to control headless Chrome over the DevTools Protocol",
"main": "./cjs-entry.js",
"types": "lib/types.d.ts",
@ -24,9 +24,11 @@
"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",
"lint": "npm run eslint && npm run build && npm run doc && npm run commitlint",
"markdownlint": "prettier --check **/README.md docs/api.md docs/troubleshooting.md",
"markdownlint-fix": "prettier --write **/README.md docs/api.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": "rm -rf lib",
"clean-lib": "rimraf lib",
"build": "npm run tsc && npm run generate-d-ts",
"tsc": "npm run clean-lib && tsc --version && npm run tsc-cjs && npm run tsc-esm",
"tsc-cjs": "tsc -b src/tsconfig.cjs.json",
@ -53,61 +55,61 @@
"author": "The Chromium Authors",
"license": "Apache-2.0",
"dependencies": {
"debug": "^4.1.0",
"devtools-protocol": "0.0.854822",
"extract-zip": "^2.0.0",
"https-proxy-agent": "^5.0.0",
"node-fetch": "^2.6.1",
"pkg-dir": "^4.2.0",
"progress": "^2.0.1",
"proxy-from-env": "^1.1.0",
"rimraf": "^3.0.2",
"tar-fs": "^2.0.0",
"unbzip2-stream": "^1.3.3",
"ws": "^7.2.3"
"debug": "4.3.1",
"devtools-protocol": "0.0.869402",
"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",
"proxy-from-env": "1.1.0",
"rimraf": "3.0.2",
"tar-fs": "2.1.1",
"unbzip2-stream": "1.4.3",
"ws": "7.4.4"
},
"devDependencies": {
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@microsoft/api-documenter": "^7.12.7",
"@microsoft/api-extractor": "^7.13.1",
"@commitlint/cli": "11.0.0",
"@commitlint/config-conventional": "11.0.0",
"@microsoft/api-documenter": "7.12.11",
"@microsoft/api-extractor": "7.13.2",
"@types/debug": "0.0.31",
"@types/mime": "^2.0.0",
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.13",
"@types/proxy-from-env": "^1.0.1",
"@types/rimraf": "^2.0.2",
"@types/sinon": "^9.0.4",
"@types/tar-fs": "^1.16.2",
"@types/ws": "^7.2.4",
"@typescript-eslint/eslint-plugin": "^4.4.0",
"@typescript-eslint/parser": "^4.4.0",
"@web/test-runner": "^0.12.15",
"commonmark": "^0.28.1",
"cross-env": "^7.0.2",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.12.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-unicorn": "^22.0.0",
"esprima": "^4.0.0",
"expect": "^25.2.7",
"husky": "^4.3.0",
"jpeg-js": "^0.3.7",
"mime": "^2.0.3",
"minimist": "^1.2.0",
"mocha": "^8.2.0",
"ncp": "^2.0.0",
"pixelmatch": "^4.0.2",
"pngjs": "^5.0.0",
"prettier": "^2.1.2",
"sinon": "^9.0.2",
"source-map-support": "^0.5.19",
"standard-version": "^9.0.0",
"text-diff": "^1.0.1",
"ts-node": "^9.0.0",
"typescript": "^4.1.5"
"@types/mime": "2.0.3",
"@types/mocha": "7.0.2",
"@types/node": "14.14.33",
"@types/proxy-from-env": "1.0.1",
"@types/rimraf": "2.0.4",
"@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",
"cross-env": "7.0.3",
"eslint": "7.21.0",
"eslint-config-prettier": "6.15.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-mocha": "8.1.0",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-unicorn": "22.0.0",
"esprima": "4.0.1",
"expect": "25.5.0",
"husky": "4.3.8",
"jpeg-js": "0.3.7",
"mime": "2.5.2",
"minimist": "1.2.5",
"mocha": "8.3.1",
"ncp": "2.0.0",
"pixelmatch": "4.0.2",
"pngjs": "5.0.0",
"prettier": "2.2.1",
"sinon": "9.2.4",
"source-map-support": "0.5.19",
"standard-version": "9.1.1",
"text-diff": "1.0.1",
"ts-node": "9.1.1",
"typescript": "4.2.3"
},
"husky": {
"hooks": {

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

@ -34,7 +34,7 @@ const EXPECTED_ERRORS = new Map<string, string[]>([
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
"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<Element> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
],
],
[
@ -43,7 +43,7 @@ const EXPECTED_ERRORS = new Map<string, string[]>([
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
"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<Element> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
],
],
[
@ -52,7 +52,7 @@ const EXPECTED_ERRORS = new Map<string, string[]>([
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
"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<Element> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
],
],
[
@ -61,7 +61,7 @@ const EXPECTED_ERRORS = new Map<string, string[]>([
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
"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<Element> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
],
],
]);

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

@ -52,15 +52,13 @@ 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*\]/;
const attributeRegexp = /\[\s*(?<attribute>\w+)\s*=\s*"(?<value>\\.|[^"\\]*)"\s*\]/g;
const defaultName = selector.replace(
attributeRegexp,
(_, attribute: string, value: string) => {
attribute = attribute.trim();
if (!knownAttributes.has(attribute))
throw new Error(
'Unkown aria attribute "${groups.attribute}" in selector'
);
throw new Error(`Unknown aria attribute "${attribute}" in selector`);
queryOptions[attribute] = normalize(value);
return '';
}

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

@ -24,7 +24,17 @@ import { Page } from './Page.js';
import { ChildProcess } from 'child_process';
import { Viewport } from './PuppeteerViewport.js';
type BrowserCloseCallback = () => Promise<void> | void;
/**
* @internal
*/
export type BrowserCloseCallback = () => Promise<void> | void;
/**
* @public
*/
export type TargetFilterCallback = (
target: Protocol.Target.TargetInfo
) => boolean;
const WEB_PERMISSION_TO_PROTOCOL_PERMISSION = new Map<
Permission,
@ -184,9 +194,10 @@ export class Browser extends EventEmitter {
connection: Connection,
contextIds: string[],
ignoreHTTPSErrors: boolean,
defaultViewport?: Viewport,
defaultViewport?: Viewport | null,
process?: ChildProcess,
closeCallback?: BrowserCloseCallback
closeCallback?: BrowserCloseCallback,
targetFilterCallback?: TargetFilterCallback
): Promise<Browser> {
const browser = new Browser(
connection,
@ -194,16 +205,18 @@ export class Browser extends EventEmitter {
ignoreHTTPSErrors,
defaultViewport,
process,
closeCallback
closeCallback,
targetFilterCallback
);
await connection.send('Target.setDiscoverTargets', { discover: true });
return browser;
}
private _ignoreHTTPSErrors: boolean;
private _defaultViewport?: Viewport;
private _defaultViewport?: Viewport | null;
private _process?: ChildProcess;
private _connection: Connection;
private _closeCallback: BrowserCloseCallback;
private _targetFilterCallback: TargetFilterCallback;
private _defaultContext: BrowserContext;
private _contexts: Map<string, BrowserContext>;
/**
@ -219,9 +232,10 @@ export class Browser extends EventEmitter {
connection: Connection,
contextIds: string[],
ignoreHTTPSErrors: boolean,
defaultViewport?: Viewport,
defaultViewport?: Viewport | null,
process?: ChildProcess,
closeCallback?: BrowserCloseCallback
closeCallback?: BrowserCloseCallback,
targetFilterCallback?: TargetFilterCallback
) {
super();
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
@ -229,6 +243,7 @@ export class Browser extends EventEmitter {
this._process = process;
this._connection = connection;
this._closeCallback = closeCallback || function (): void {};
this._targetFilterCallback = targetFilterCallback || ((): boolean => true);
this._defaultContext = new BrowserContext(this._connection, this, null);
this._contexts = new Map();
@ -327,6 +342,11 @@ export class Browser extends EventEmitter {
? this._contexts.get(browserContextId)
: this._defaultContext;
const shouldAttachToTarget = this._targetFilterCallback(targetInfo);
if (!shouldAttachToTarget) {
return;
}
const target = new Target(
targetInfo,
context,
@ -550,7 +570,9 @@ export class Browser extends EventEmitter {
return this._connection.send('Browser.getVersion');
}
}
/**
* @public
*/
export const enum BrowserContextEmittedEvents {
/**
* Emitted when the url of a target inside the browser context changes.
@ -604,6 +626,7 @@ export const enum BrowserContextEmittedEvents {
* // Dispose context once it's no longer needed.
* await context.close();
* ```
* @public
*/
export class BrowserContext extends EventEmitter {
private _connection: Connection;

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

@ -15,7 +15,7 @@
*/
import { ConnectionTransport } from './ConnectionTransport.js';
import { Browser } from './Browser.js';
import { Browser, TargetFilterCallback } from './Browser.js';
import { assert } from './assert.js';
import { debugError } from '../common/helper.js';
import { Connection } from './Connection.js';
@ -37,12 +37,16 @@ export interface BrowserConnectOptions {
/**
* Sets the viewport for each page.
*/
defaultViewport?: Viewport;
defaultViewport?: Viewport | null;
/**
* Slows down Puppeteer operations by the specified amount of milliseconds to
* aid debugging.
*/
slowMo?: number;
/**
* Callback to decide if Puppeteer should connect to a given target or not.
*/
targetFilter?: TargetFilterCallback;
}
const getWebSocketTransportClass = async () => {
@ -71,6 +75,7 @@ export const connectToBrowser = async (
defaultViewport = { width: 800, height: 600 },
transport,
slowMo = 0,
targetFilter,
} = options;
assert(
@ -106,7 +111,8 @@ export const connectToBrowser = async (
ignoreHTTPSErrors,
defaultViewport,
null,
() => connection.send('Browser.close').catch(debugError)
() => connection.send('Browser.close').catch(debugError),
targetFilter
);
};

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

@ -23,7 +23,15 @@ import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { ConnectionTransport } from './ConnectionTransport.js';
import { EventEmitter } from './EventEmitter.js';
interface ConnectionCallback {
/**
* @public
*/
export { ConnectionTransport, ProtocolMapping };
/**
* @public
*/
export interface ConnectionCallback {
resolve: Function;
reject: Function;
error: Error;
@ -67,8 +75,8 @@ export class Connection extends EventEmitter {
}
/**
* @param {string} sessionId
* @returns {?CDPSession}
* @param sessionId - The session id
* @returns The current CDP session if it exists
*/
session(sessionId: string): CDPSession | null {
return this._sessions.get(sessionId) || null;
@ -167,8 +175,8 @@ export class Connection extends EventEmitter {
}
/**
* @param {Protocol.Target.TargetInfo} targetInfo
* @returns {!Promise<!CDPSession>}
* @param targetInfo - The target info
* @returns The CDP session that is created
*/
async createSession(
targetInfo: Protocol.Target.TargetInfo
@ -181,7 +189,10 @@ export class Connection extends EventEmitter {
}
}
interface CDPSessionOnMessageObject {
/**
* @public
*/
export interface CDPSessionOnMessageObject {
id?: number;
method: string;
params: Record<string, unknown>;

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

@ -14,6 +14,9 @@
* limitations under the License.
*/
/**
* @public
*/
export interface ConnectionTransport {
send(string);
close();

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

@ -38,6 +38,7 @@ export interface ConsoleMessageLocation {
/**
* The supported types for console messages.
* @public
*/
export type ConsoleMessageType =
| 'log'

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

@ -21,6 +21,11 @@ import { CDPSession } from './Connection.js';
import { EVALUATION_SCRIPT_URL } from './ExecutionContext.js';
/**
* @internal
*/
export { PuppeteerEventListener };
/**
* The CoverageEntry class represents one entry of the coverage report.
* @public
@ -164,7 +169,10 @@ export class Coverage {
}
}
class JSCoverage {
/**
* @public
*/
export class JSCoverage {
_client: CDPSession;
_enabled = false;
_scriptURLs = new Map<string, string>();
@ -277,7 +285,10 @@ class JSCoverage {
}
}
class CSSCoverage {
/**
* @public
*/
export class CSSCoverage {
_client: CDPSession;
_enabled = false;
_stylesheetURLs = new Map<string, string>();

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

@ -166,9 +166,11 @@ export class DOMWorld {
);
}
async $(selector: string): Promise<ElementHandle | null> {
async $<T extends Element = Element>(
selector: string
): Promise<ElementHandle<T> | null> {
const document = await this._document();
const value = await document.$(selector);
const value = await document.$<T>(selector);
return value;
}
@ -216,9 +218,11 @@ export class DOMWorld {
return value;
}
async $$(selector: string): Promise<ElementHandle[]> {
async $$<T extends Element = Element>(
selector: string
): Promise<Array<ElementHandle<T>>> {
const document = await this._document();
const value = await document.$$(selector);
const value = await document.$$<T>(selector);
return value;
}

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

@ -14,7 +14,10 @@
* limitations under the License.
*/
interface Device {
/**
* @public
*/
export interface Device {
name: string;
userAgent: string;
viewport: {
@ -1030,13 +1033,16 @@ const devices: Device[] = [
},
},
];
/**
* @public
*/
export type DevicesMap = {
[name: string]: Device;
};
const devicesMap: DevicesMap = {};
/**
* @internal
*/
export const devicesMap: DevicesMap = {};
for (const device of devices) devicesMap[device.name] = device;
export { devicesMap };

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

@ -38,6 +38,7 @@ import { Protocol } from 'devtools-protocol';
* page.evaluate(() => alert('1'));
* })();
* ```
* @public
*/
export class Dialog {
private _client: CDPSession;

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

@ -14,7 +14,10 @@
* limitations under the License.
*/
class CustomError extends Error {
/**
* @public
*/
export class CustomError extends Error {
constructor(message: string) {
super(message);
this.name = this.constructor.name;
@ -33,9 +36,13 @@ class CustomError extends Error {
* @public
*/
export class TimeoutError extends CustomError {}
/**
* @public
*/
export type PuppeteerErrors = Record<string, typeof CustomError>;
/**
* @public
*/
export const puppeteerErrors: PuppeteerErrors = {
TimeoutError,
};

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

@ -20,7 +20,9 @@ import { JSHandle, ElementHandle } from './JSHandle.js';
* @public
*/
export type EvaluateFn<T = any> = string | ((arg1: T, ...args: any[]) => any);
/**
* @public
*/
export type UnwrapPromiseLike<T> = T extends PromiseLike<infer U> ? U : T;
/**

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

@ -5,7 +5,12 @@ import mitt, {
} from '../../vendor/mitt/src/index.js';
/**
* @internal
* @public
*/
export { EventType, Handler };
/**
* @public
*/
export interface CommonEventEmitter {
on(event: EventType, handler: Handler): CommonEventEmitter;

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

@ -22,7 +22,9 @@ import { DOMWorld } from './DOMWorld.js';
import { Frame } from './FrameManager.js';
import { Protocol } from 'devtools-protocol';
import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes.js';
/**
* @public
*/
export const EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__';
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
@ -33,7 +35,7 @@ const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe |
* frame } has "default" execution context that is always created after frame is
* attached to DOM. This context is returned by the
* {@link frame.executionContext()} method.
* {@link Frame.executionContext} method.
* - {@link https://developer.chrome.com/extensions | Extension}'s content scripts
* create additional execution contexts.
*
@ -126,8 +128,8 @@ export class ExecutionContext {
* await twoHandle.dispose();
* console.log(result); // prints '3'.
* ```
* @param pageFunction a function to be evaluated in the `executionContext`
* @param args argument to pass to the page function
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function.
*/
@ -178,8 +180,8 @@ export class ExecutionContext {
* await resultHandle.dispose();
* ```
*
* @param pageFunction a function to be evaluated in the `executionContext`
* @param args argument to pass to the page function
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function
* as an in-page object (a {@link JSHandle}).
@ -344,7 +346,7 @@ export class ExecutionContext {
* await mapPrototype.dispose();
* ```
*
* @param prototypeHandle a handle to the object prototype
* @param prototypeHandle - a handle to the object prototype
*
* @returns A handle to an array of objects with the given prototype.
*/

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

@ -34,6 +34,7 @@ import { assert } from './assert.js';
* **NOTE** In browsers, only one file chooser can be opened at a time.
* All file choosers must be accepted or canceled. Not doing so will prevent
* subsequent file choosers from appearing.
* @public
*/
export class FileChooser {
private _element: ElementHandle;
@ -75,7 +76,7 @@ export class FileChooser {
/**
* Closes the file chooser without selecting any files.
*/
async cancel(): Promise<void> {
cancel() {
assert(
!this._handled,
'Cannot cancel FileChooser which is already handled!'

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

@ -722,8 +722,10 @@ export class Frame {
* @returns A promise which resolves to an `ElementHandle` pointing at the
* element, or `null` if it was not found.
*/
async $(selector: string): Promise<ElementHandle | null> {
return this._mainWorld.$(selector);
async $<T extends Element = Element>(
selector: string
): Promise<ElementHandle<T> | null> {
return this._mainWorld.$<T>(selector);
}
/**
@ -801,8 +803,10 @@ export class Frame {
* @param selector - a selector to search for
* @returns An array of element handles pointing to the found frame elements.
*/
async $$(selector: string): Promise<ElementHandle[]> {
return this._mainWorld.$$(selector);
async $$<T extends Element = Element>(
selector: string
): Promise<Array<ElementHandle<T>>> {
return this._mainWorld.$$<T>(selector);
}
/**

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

@ -40,7 +40,10 @@ export interface ContinueRequestOverrides {
*/
export interface ResponseForRequest {
status: number;
headers: Record<string, string>;
/**
* Optional response headers. All values are converted to strings.
*/
headers: Record<string, unknown>;
contentType: string;
body: string | Buffer;
}
@ -346,7 +349,7 @@ export class HTTPRequest {
*
* @param response - the response to fulfill the request with.
*/
async respond(response: ResponseForRequest): Promise<void> {
async respond(response: Partial<ResponseForRequest>): Promise<void> {
// Mocking responses for dataURL requests is not currently supported.
if (this._url.startsWith('data:')) return;
assert(this._allowInterception, 'Request Interception is not enabled!');
@ -361,7 +364,9 @@ export class HTTPRequest {
const responseHeaders: Record<string, string> = {};
if (response.headers) {
for (const header of Object.keys(response.headers))
responseHeaders[header.toLowerCase()] = response.headers[header];
responseHeaders[header.toLowerCase()] = String(
response.headers[header]
);
}
if (response.contentType)
responseHeaders['content-type'] = response.contentType;

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

@ -409,15 +409,14 @@ export class Mouse {
): Promise<void> {
const { delay = null } = options;
if (delay !== null) {
await Promise.all([this.move(x, y), this.down(options)]);
await this.move(x, y);
await this.down(options);
await new Promise((f) => setTimeout(f, delay));
await this.up(options);
} else {
await Promise.all([
this.move(x, y),
this.down(options),
this.up(options),
]);
await this.move(x, y);
await this.down(options);
await this.up(options);
}
}

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

@ -32,7 +32,9 @@ import {
UnwrapPromiseLike,
} from './EvalTypes.js';
import { isNode } from '../environment.js';
/**
* @public
*/
export interface BoxModel {
content: Array<{ x: number; y: number }>;
padding: Array<{ x: number; y: number }>;
@ -771,7 +773,9 @@ export class ElementHandle<
* Runs `element.querySelector` within the page. If no element matches the selector,
* the return value resolves to `null`.
*/
async $(selector: string): Promise<ElementHandle | null> {
async $<T extends Element = Element>(
selector: string
): Promise<ElementHandle<T> | null> {
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(
selector
);
@ -782,7 +786,9 @@ export class ElementHandle<
* Runs `element.querySelectorAll` within the page. If no elements match the selector,
* the return value resolves to `[]`.
*/
async $$(selector: string): Promise<ElementHandle[]> {
async $$<T extends Element = Element>(
selector: string
): Promise<Array<ElementHandle<T>>> {
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(
selector
);

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

@ -26,13 +26,19 @@ import { HTTPRequest } from './HTTPRequest.js';
import { HTTPResponse } from './HTTPResponse.js';
import { NetworkManagerEmittedEvents } from './NetworkManager.js';
import { CDPSessionEmittedEvents } from './Connection.js';
/**
* @public
*/
export type PuppeteerLifeCycleEvent =
| 'load'
| 'domcontentloaded'
| 'networkidle0'
| 'networkidle2';
type ProtocolLifeCycleEvent =
/**
* @public
*/
export type ProtocolLifeCycleEvent =
| 'load'
| 'DOMContentLoaded'
| 'networkIdle'

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

@ -41,7 +41,9 @@ export interface NetworkConditions {
// Latency (ms)
latency: number;
}
/**
* @public
*/
export interface InternalNetworkConditions extends NetworkConditions {
offline: boolean;
}
@ -54,6 +56,7 @@ export interface InternalNetworkConditions extends NetworkConditions {
*/
export const NetworkManagerEmittedEvents = {
Request: Symbol('NetworkManager.Request'),
RequestServedFromCache: Symbol('NetworkManager.RequestServedFromCache'),
Response: Symbol('NetworkManager.Response'),
RequestFailed: Symbol('NetworkManager.RequestFailed'),
RequestFinished: Symbol('NetworkManager.RequestFinished'),
@ -75,6 +78,7 @@ export class NetworkManager extends EventEmitter {
_credentials?: Credentials = null;
_attemptedAuthentications = new Set<string>();
_userRequestInterceptionEnabled = false;
_userRequestInterceptionCacheSafe = false;
_protocolRequestInterceptionEnabled = false;
_userCacheDisabled = false;
_requestIdToInterceptionId = new Map<string, string>();
@ -189,8 +193,12 @@ export class NetworkManager extends EventEmitter {
await this._updateProtocolCacheDisabled();
}
async setRequestInterception(value: boolean): Promise<void> {
async setRequestInterception(
value: boolean,
cacheSafe = false
): Promise<void> {
this._userRequestInterceptionEnabled = value;
this._userRequestInterceptionCacheSafe = cacheSafe;
await this._updateProtocolRequestInterception();
}
@ -217,14 +225,16 @@ export class NetworkManager extends EventEmitter {
async _updateProtocolCacheDisabled(): Promise<void> {
await this._client.send('Network.setCacheDisabled', {
cacheDisabled:
this._userCacheDisabled || this._protocolRequestInterceptionEnabled,
this._userCacheDisabled ||
(this._userRequestInterceptionEnabled &&
!this._userRequestInterceptionCacheSafe),
});
}
_onRequestWillBeSent(event: Protocol.Network.RequestWillBeSentEvent): void {
// Request interception doesn't happen for data URLs with Network Service.
if (
this._protocolRequestInterceptionEnabled &&
this._userRequestInterceptionEnabled &&
!event.request.url.startsWith('data:')
) {
const requestId = event.requestId;
@ -323,6 +333,7 @@ export class NetworkManager extends EventEmitter {
): void {
const request = this._requestIdToRequest.get(event.requestId);
if (request) request._fromMemoryCache = true;
this.emit(NetworkManagerEmittedEvents.RequestServedFromCache, request);
}
_handleRequestRedirect(

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

@ -151,6 +151,11 @@ export interface PDFOptions {
* @defaultValue the empty string, which means the PDF will not be written to disk.
*/
path?: string;
/**
* Hides default white background and allows generating pdfs with transparency.
* @defaultValue false
*/
omitBackground?: boolean;
}
/**

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

@ -130,7 +130,10 @@ export interface GeolocationOptions {
accuracy?: number;
}
interface MediaFeature {
/**
* @public
*/
export interface MediaFeature {
name: string;
value: string;
}
@ -183,6 +186,11 @@ export interface ScreenshotOptions {
* @defaultValue 'binary'
*/
encoding?: 'base64' | 'binary';
/**
* If you need a screenshot bigger than the Viewport
* @defaultValue true
*/
captureBeyondViewport?: boolean;
}
/**
@ -283,10 +291,18 @@ export const enum PageEmittedEvents {
* Emitted when a page issues a request and contains a {@link HTTPRequest}.
*
* @remarks
* The object is readonly. See {@Page.setRequestInterception} for intercepting
* The object is readonly. See {@link Page.setRequestInterception} for intercepting
* and mutating requests.
*/
Request = 'request',
/**
* Emitted when a request ended up loading from cache. Contains a {@link HTTPRequest}.
*
* @remarks
* For certain requests, might contain undefined.
* {@link https://crbug.com/750469}
*/
RequestServedFromCache = 'requestservedfromcache',
/**
* Emitted when a request fails, for example by timing out.
*
@ -321,6 +337,35 @@ export const enum PageEmittedEvents {
WorkerDestroyed = 'workerdestroyed',
}
/**
* Denotes the objects received by callback functions for page events.
*
* See {@link PageEmittedEvents} for more detail on the events and when they are
* emitted.
* @public
*/
export interface PageEventObject {
close: never;
console: ConsoleMessage;
dialog: Dialog;
domcontentloaded: never;
error: Error;
frameattached: Frame;
framedetached: Frame;
framenavigated: Frame;
load: never;
metrics: { title: string; metrics: Metrics };
pageerror: Error;
popup: Page;
request: HTTPRequest;
response: HTTPResponse;
requestfailed: HTTPRequest;
requestfinished: HTTPRequest;
requestservedfromcache: HTTPRequest;
workercreated: WebWorker;
workerdestroyed: WebWorker;
}
class ScreenshotTaskQueue {
_chain: Promise<Buffer | string | void>;
@ -465,8 +510,8 @@ export class Page extends EventEmitter {
client.on('Target.detachedFromTarget', (event) => {
const worker = this._workers.get(event.sessionId);
if (!worker) return;
this.emit(PageEmittedEvents.WorkerDestroyed, worker);
this._workers.delete(event.sessionId);
this.emit(PageEmittedEvents.WorkerDestroyed, worker);
});
this._frameManager.on(FrameManagerEmittedEvents.FrameAttached, (event) =>
@ -483,6 +528,10 @@ export class Page extends EventEmitter {
networkManager.on(NetworkManagerEmittedEvents.Request, (event) =>
this.emit(PageEmittedEvents.Request, event)
);
networkManager.on(
NetworkManagerEmittedEvents.RequestServedFromCache,
(event) => this.emit(PageEmittedEvents.RequestServedFromCache, event)
);
networkManager.on(NetworkManagerEmittedEvents.Response, (event) =>
this.emit(PageEmittedEvents.Response, event)
);
@ -547,6 +596,27 @@ export class Page extends EventEmitter {
return this._javascriptEnabled;
}
/**
* Listen to page events.
*/
public on<K extends keyof PageEventObject>(
eventName: K,
handler: (event: PageEventObject[K]) => void
): EventEmitter {
// Note: this method only exists to define the types; we delegate the impl
// to EventEmitter.
return super.on(eventName, handler);
}
public once<K extends keyof PageEventObject>(
eventName: K,
handler: (event: PageEventObject[K]) => void
): EventEmitter {
// Note: this method only exists to define the types; we delegate the impl
// to EventEmitter.
return super.once(eventName, handler);
}
/**
* @param options - Optional waiting parameters
* @returns Resolves after a page requests a file picker.
@ -688,6 +758,8 @@ 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},
@ -695,9 +767,7 @@ export class Page extends EventEmitter {
* provides the capability to modify network requests that are made by a page.
*
* Once request interception is enabled, every request will stall unless it's
* continued, responded or aborted.
*
* **NOTE** Enabling request interception disables page caching.
* continued, responded or aborted; or completed using the browser cache.
*
* @example
* An example of a naïve request interceptor that aborts all image requests:
@ -719,8 +789,13 @@ export class Page extends EventEmitter {
* })();
* ```
*/
async setRequestInterception(value: boolean): Promise<void> {
return this._frameManager.networkManager().setRequestInterception(value);
async setRequestInterception(
value: boolean,
cacheSafe = false
): Promise<void> {
return this._frameManager
.networkManager()
.setRequestInterception(value, cacheSafe);
}
/**
@ -763,8 +838,10 @@ export class Page extends EventEmitter {
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector}
* to query page for.
*/
async $(selector: string): Promise<ElementHandle | null> {
return this.mainFrame().$(selector);
async $<T extends Element = Element>(
selector: string
): Promise<ElementHandle<T> | null> {
return this.mainFrame().$<T>(selector);
}
/**
@ -980,13 +1057,13 @@ export class Page extends EventEmitter {
* );
* ```
*
* @param selector the
* @param selector - the
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector}
* to query for
* @param pageFunction the function to be evaluated in the page context. Will
* @param pageFunction - the function to be evaluated in the page context. Will
* be passed the result of `Array.from(document.querySelectorAll(selector))`
* as its first argument.
* @param args any additional arguments to pass through to `pageFunction`.
* @param args - any additional arguments to pass through to `pageFunction`.
*
* @returns The result of calling `pageFunction`. If it returns an element it
* is wrapped in an {@link ElementHandle}, else the raw value itself is
@ -1007,8 +1084,10 @@ export class Page extends EventEmitter {
return this.mainFrame().$$eval<ReturnType>(selector, pageFunction, ...args);
}
async $$(selector: string): Promise<ElementHandle[]> {
return this.mainFrame().$$(selector);
async $$<T extends Element = Element>(
selector: string
): Promise<Array<ElementHandle<T>>> {
return this.mainFrame().$$<T>(selector);
}
async $x(expression: string): Promise<ElementHandle[]> {
@ -1271,6 +1350,22 @@ export class Page extends EventEmitter {
this.emit(PageEmittedEvents.Dialog, dialog);
}
/**
* Resets default white background
*/
private async _resetDefaultBackgroundColor() {
await this._client.send('Emulation.setDefaultBackgroundColorOverride');
}
/**
* Hides default white background
*/
private async _setTransparentBackgroundColor(): Promise<void> {
await this._client.send('Emulation.setDefaultBackgroundColorOverride', {
color: { r: 0, g: 0, b: 0, a: 0 },
});
}
url(): string {
return this.mainFrame().url();
}
@ -1316,7 +1411,7 @@ export class Page extends EventEmitter {
}
async waitForRequest(
urlOrPredicate: string | Function,
urlOrPredicate: string | ((req: HTTPRequest) => boolean | Promise<boolean>),
options: { timeout?: number } = {}
): Promise<HTTPRequest> {
const { timeout = this._timeoutSettings.timeout() } = options;
@ -1336,7 +1431,9 @@ export class Page extends EventEmitter {
}
async waitForResponse(
urlOrPredicate: string | Function,
urlOrPredicate:
| string
| ((res: HTTPResponse) => boolean | Promise<boolean>),
options: { timeout?: number } = {}
): Promise<HTTPResponse> {
const { timeout = this._timeoutSettings.timeout() } = options;
@ -1461,9 +1558,9 @@ export class Page extends EventEmitter {
* await page.emulateIdleState();
* ```
*
* @param overrides Mock idle state. If not set, clears idle overrides
* @param isUserActive Mock isUserActive
* @param isScreenUnlocked Mock isScreenUnlocked
* @param overrides - Mock idle state. If not set, clears idle overrides
* @param isUserActive - Mock isUserActive
* @param isScreenUnlocked - Mock isScreenUnlocked
*/
async emulateIdleState(overrides?: {
isUserActive: boolean;
@ -1709,6 +1806,9 @@ export class Page extends EventEmitter {
targetId: this._target._targetId,
});
let clip = options.clip ? processClip(options.clip) : undefined;
let { captureBeyondViewport = true } = options;
captureBeyondViewport =
typeof captureBeyondViewport === 'boolean' ? captureBeyondViewport : true;
if (options.fullPage) {
const metrics = await this._client.send('Page.getLayoutMetrics');
@ -1717,21 +1817,37 @@ export class Page extends EventEmitter {
// Overwrite clip for full page.
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' };
await this._client.send('Emulation.setDeviceMetricsOverride', {
mobile: isMobile,
width,
height,
deviceScaleFactor,
screenOrientation,
});
}
}
const shouldSetDefaultBackground =
options.omitBackground && format === 'png';
if (shouldSetDefaultBackground)
await this._client.send('Emulation.setDefaultBackgroundColorOverride', {
color: { r: 0, g: 0, b: 0, a: 0 },
});
if (shouldSetDefaultBackground) {
await this._setTransparentBackgroundColor();
}
const result = await this._client.send('Page.captureScreenshot', {
format,
quality: options.quality,
clip,
captureBeyondViewport: true,
captureBeyondViewport,
});
if (shouldSetDefaultBackground)
await this._client.send('Emulation.setDefaultBackgroundColorOverride');
if (shouldSetDefaultBackground) {
await this._resetDefaultBackgroundColor();
}
if (options.fullPage && this._viewport)
await this.setViewport(this._viewport);
@ -1740,13 +1856,16 @@ export class Page extends EventEmitter {
options.encoding === 'base64'
? result.data
: Buffer.from(result.data, 'base64');
if (!isNode && options.path) {
throw new Error(
'Screenshots can only be written to a file path in a Node environment.'
);
if (options.path) {
if (!isNode) {
throw new Error(
'Screenshots can only be written to a file path in a Node environment.'
);
}
const fs = await helper.importFSModule();
await fs.promises.writeFile(options.path, buffer);
}
const fs = await helper.importFSModule();
if (options.path) await fs.promises.writeFile(options.path, buffer);
return buffer;
function processClip(
@ -1790,6 +1909,7 @@ export class Page extends EventEmitter {
preferCSSPageSize = false,
margin = {},
path = null,
omitBackground = false,
} = options;
let paperWidth = 8.5;
@ -1810,6 +1930,10 @@ export class Page extends EventEmitter {
const marginBottom = convertPrintParameterToInches(margin.bottom) || 0;
const marginRight = convertPrintParameterToInches(margin.right) || 0;
if (omitBackground) {
await this._setTransparentBackgroundColor();
}
const result = await this._client.send('Page.printToPDF', {
transferMode: 'ReturnAsStream',
landscape,
@ -1827,6 +1951,11 @@ export class Page extends EventEmitter {
pageRanges,
preferCSSPageSize,
});
if (omitBackground) {
await this._resetDefaultBackgroundColor();
}
return await helper.readProtocolStream(this._client, result.stream, path);
}

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

@ -38,7 +38,9 @@ import {
export interface CommonPuppeteerSettings {
isPuppeteerCore: boolean;
}
/**
* @public
*/
export interface ConnectOptions extends BrowserConnectOptions {
browserWSEndpoint?: string;
browserURL?: string;

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

@ -24,7 +24,7 @@ import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes.js';
/**
* @internal
*/
type ConsoleAPICalledCallback = (
export type ConsoleAPICalledCallback = (
eventType: string,
handles: JSHandle[],
trace: Protocol.Runtime.StackTrace
@ -33,7 +33,7 @@ type ConsoleAPICalledCallback = (
/**
* @internal
*/
type ExceptionThrownCallback = (
export type ExceptionThrownCallback = (
details: Protocol.Runtime.ExceptionDetails
) => void;
type JSHandleFactory = (obj: Protocol.Runtime.RemoteObject) => JSHandle;

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

@ -86,6 +86,9 @@ async function releaseObject(
});
}
/**
* @public
*/
export interface PuppeteerEventListener {
emitter: CommonEventEmitter;
eventName: string | symbol;

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

@ -293,7 +293,10 @@ export class BrowserFetcher {
if (await existsAsync(outputPath)) return this.revisionInfo(revision);
if (!(await existsAsync(this._downloadsFolder)))
await mkdirAsync(this._downloadsFolder);
if (os.arch() === 'arm64') {
// Use Intel x86 builds on Apple M1 until native macOS arm64
// Chromium builds are available.
if (os.platform() !== 'darwin' && os.arch() === 'arm64') {
handleArm64();
return;
}

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

@ -105,7 +105,9 @@ class ChromeLauncher implements ProductLauncher {
let chromeExecutable = executablePath;
if (!executablePath) {
if (os.arch() === 'arm64') {
// Use Intel x86 builds on Apple M1 until native macOS arm64
// Chromium builds are available.
if (os.platform() !== 'darwin' && os.arch() === 'arm64') {
chromeExecutable = '/usr/bin/chromium-browser';
} else {
const { missingText, executablePath } = resolveExecutablePath(this);
@ -502,6 +504,8 @@ class FirefoxLauncher implements ProductLauncher {
'geo.wifi.scan': false,
// No hang monitor
'hangmonitor.timeout': 0,
// Show chrome errors and warnings in the error console
'javascript.options.showInConsole': true,
// Disable download and usage of OpenH264: and Widevine plugins
'media.gmp-manager.updateEnabled': false,
@ -530,8 +534,8 @@ class FirefoxLauncher implements ProductLauncher {
'privacy.trackingprotection.enabled': false,
// Can be removed once Firefox 89 is no longer supported
// https://bugzilla.mozilla.org/show_bug.cgi?id=1710839
// Enable Remote Agent
// https://bugzilla.mozilla.org/show_bug.cgi?id=1544393
'remote.enabled': true,
// Don't do network connections for mitm priming

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

@ -90,7 +90,9 @@ export async function downloadBrowser() {
if (NPM_NO_PROXY) process.env.NO_PROXY = NPM_NO_PROXY;
function onSuccess(localRevisions: string[]): void {
if (os.arch() !== 'arm64') {
// Use Intel x86 builds on Apple M1 until native macOS arm64
// Chromium builds are available.
if (os.platform() !== 'darwin' && os.arch() !== 'arm64') {
logPolitely(
`${supportedProducts[product]} (${revisionInfo.revision}) downloaded to ${revisionInfo.folderPath}`
);

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

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

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

@ -5,6 +5,9 @@ async function run() {
const devices = puppeteer.devices;
console.log(devices);
const page = await browser.newPage();
page.on('request', (request) => {
const resourceType = request.resourceType();
});
const div = (await page.$('div')) as puppeteer.ElementHandle<
HTMLAnchorElement
>;

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

@ -4,19 +4,18 @@ Unit tests in Puppeteer are written using [Mocha] as the test runner and [Expect
## Test state
We have some common setup that runs before each test and is defined in `mocha-utils.js`.
You can use the `getTestState` function to read state. It exposes the following that you can use in your tests. These will be reset/tidied between tests automatically for you:
* `puppeteer`: an instance of the Puppeteer library. This is exactly what you'd get if you ran `require('puppeteer')`.
* `puppeteerPath`: the path to the root source file for Puppeteer.
* `defaultBrowserOptions`: the default options the Puppeteer browser is launched from in test mode, so tests can use them and override if required.
* `server`: a dummy test server instance (see `utils/testserver` for more).
* `httpsServer`: a dummy test server HTTPS instance (see `utils/testserver` for more).
* `isFirefox`: true if running in Firefox.
* `isChrome`: true if running Chromium.
* `isHeadless`: true if the test is in headless mode.
- `puppeteer`: an instance of the Puppeteer library. This is exactly what you'd get if you ran `require('puppeteer')`.
- `puppeteerPath`: the path to the root source file for Puppeteer.
- `defaultBrowserOptions`: the default options the Puppeteer browser is launched from in test mode, so tests can use them and override if required.
- `server`: a dummy test server instance (see `utils/testserver` for more).
- `httpsServer`: a dummy test server HTTPS instance (see `utils/testserver` for more).
- `isFirefox`: true if running in Firefox.
- `isChrome`: true if running Chromium.
- `isHeadless`: true if the test is in headless mode.
If your test needs a browser instance, you can use the `setupTestBrowserHooks()` function which will automatically configure a browser that will be cleaned between each test suite run. You access this via `getTestState()`.
@ -33,8 +32,8 @@ There is also `describeChromeOnly` and `itChromeOnly` which will only execute th
There are also tests that assume a normal install flow, with browser binaries ending up in `.local-<browser>`, for example. Such tests are skipped with
`itOnlyRegularInstall` which checks `BINARY` and `PUPPETEER_ALT_INSTALL` environment variables.
[Mocha]: https://mochajs.org/
[Expect]: https://www.npmjs.com/package/expect
[mocha]: https://mochajs.org/
[expect]: https://www.npmjs.com/package/expect
## Running tests
@ -46,7 +45,7 @@ Despite being named 'unit', these are integration tests, making sure public API
npm run unit
```
- __Important__: don't forget to first run TypeScript if you're testing local changes:
- **Important**: don't forget to first run TypeScript if you're testing local changes:
```bash
npm run tsc && npm run unit
@ -63,7 +62,7 @@ npm run tsc && npm run unit
});
```
- To disable a specific test, substitute the `it` with `xit` (mnemonic rule: '*cross it*'):
- To disable a specific test, substitute the `it` with `xit` (mnemonic rule: '_cross it_'):
```js
...

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

@ -434,7 +434,7 @@ describeFailsFirefox('Accessibility', function () {
await page.setContent(`<button>My Button</button>`);
const button = await page.$('button');
const button = await page.$<HTMLButtonElement>('button');
expect(await page.accessibility.snapshot({ root: button })).toEqual({
role: 'button',
name: 'My Button',

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

@ -74,6 +74,9 @@ describeChromeOnly('AriaQueryHandler', () => {
'aria/ignored[name="Submit button and some spaces"][role="button"]'
);
await expectFound(button);
await expect(page.$('aria/smth[smth="true"]')).rejects.toThrow(
'Unknown aria attribute "smth" in selector'
);
});
});
@ -571,7 +574,7 @@ describeChromeOnly('AriaQueryHandler', () => {
});
it('should find by role "button"', async () => {
const { page } = getTestState();
const found = await page.$$('aria/[role="button"]');
const found = await page.$$<HTMLButtonElement>('aria/[role="button"]');
const ids = await getIds(found);
expect(ids).toEqual(['node5', 'node6', 'node8', 'node10', 'node21']);
});

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

@ -18,6 +18,7 @@ import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
import utils from './utils.js';

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

@ -239,6 +239,7 @@ describe('Page.click', function () {
)
).toBe('clicked');
});
// See https://github.com/puppeteer/puppeteer/issues/7175
it('should double click the button', async () => {
const { page, server } = getTestState();

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

@ -240,6 +240,22 @@ describe('Coverage specs', function () {
const coverage = await page.coverage.stopCSSCoverage();
expect(coverage.length).toBe(0);
});
it('should work with a recently loaded stylesheet', async () => {
const { page, server } = getTestState();
await page.coverage.startCSSCoverage();
await page.evaluate<(url: string) => Promise<void>>(async (url) => {
document.body.textContent = 'hello, world';
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
document.head.appendChild(link);
await new Promise((x) => (link.onload = x));
}, server.PREFIX + '/csscoverage/stylesheet1.css');
const coverage = await page.coverage.stopCSSCoverage();
expect(coverage.length).toBe(1);
});
describe('resetOnNavigation', function () {
it('should report stylesheets across navigations', async () => {
const { page, server } = getTestState();
@ -260,21 +276,5 @@ describe('Coverage specs', function () {
expect(coverage.length).toBe(0);
});
});
it('should work with a recently loaded stylesheet', async () => {
const { page, server } = getTestState();
await page.coverage.startCSSCoverage();
await page.evaluate<(url: string) => Promise<void>>(async (url) => {
document.body.textContent = 'hello, world';
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
document.head.appendChild(link);
await new Promise((x) => (link.onload = x));
}, server.PREFIX + '/csscoverage/stylesheet1.css');
const coverage = await page.coverage.stopCSSCoverage();
expect(coverage.length).toBe(1);
});
});
});

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

@ -20,6 +20,7 @@ import {
getTestState,
setupTestPageAndContextHooks,
setupTestBrowserHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('Page.Events.Dialog', function () {

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

@ -20,6 +20,8 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
describeFailsFirefox,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
import utils from './utils.js';

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

@ -19,6 +19,8 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('Emulation', () => {

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

@ -20,6 +20,8 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
const bigint = typeof BigInt !== 'undefined';

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

@ -20,6 +20,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('Frame specs', function () {

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

@ -19,6 +19,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('Emulate idle state', () => {

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

@ -15,7 +15,11 @@
*/
import expect from 'expect';
import { getTestState } from './mocha-utils'; // eslint-disable-line import/extensions
import {
getTestState,
describeFailsFirefox,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('ignoreHTTPSErrors', function () {
/* Note that this test creates its own browser rather than use

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

@ -295,7 +295,13 @@ describe('input tests', function () {
]);
await fileChooser.cancel();
let error = null;
await fileChooser.cancel().catch((error_) => (error = error_));
try {
fileChooser.cancel();
} catch (error_) {
error = error_;
}
expect(error.message).toBe(
'Cannot cancel FileChooser which is already handled!'
);

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

@ -19,6 +19,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('JSHandle', function () {

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

@ -21,6 +21,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
import { KeyInput } from '../lib/cjs/puppeteer/common/USKeyboardLayout.js';

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

@ -18,8 +18,10 @@ import os from 'os';
import path from 'path';
import sinon from 'sinon';
import { promisify } from 'util';
import Protocol from 'devtools-protocol';
import {
getTestState,
itFailsFirefox,
itOnlyRegularInstall,
} from './mocha-utils'; // eslint-disable-line import/extensions
import utils from './utils.js';
@ -537,6 +539,35 @@ describe('Launcher specs', function () {
await page.close();
await browser.close();
});
it('should support targetFilter option', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint();
const page1 = await originalBrowser.newPage();
await page1.goto(server.EMPTY_PAGE);
const page2 = await originalBrowser.newPage();
await page2.goto(server.EMPTY_PAGE + '?should-be-ignored');
const browser = await puppeteer.connect({
browserWSEndpoint,
targetFilter: (targetInfo: Protocol.Target.TargetInfo) =>
!targetInfo.url.includes('should-be-ignored'),
});
const pages = await browser.pages();
await page2.close();
await page1.close();
await browser.close();
expect(pages.map((p: Page) => p.url()).sort()).toEqual([
'about:blank',
server.EMPTY_PAGE,
]);
});
it(
'should be able to reconnect to a disconnected browser',
async () => {
@ -586,7 +617,6 @@ describe('Launcher specs', function () {
await browserOne.close();
}
);
// @see https://github.com/puppeteer/puppeteer/issues/6527
it('should be able to reconnect', async () => {
const { puppeteer, server } = getTestState();
const browserOne = await puppeteer.launch();

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

@ -19,6 +19,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
import { KeyInput } from '../lib/cjs/puppeteer/common/USKeyboardLayout.js';

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

@ -20,6 +20,8 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
import os from 'os';

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

@ -22,6 +22,8 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('network', function () {
@ -353,6 +355,20 @@ describe('network', function () {
expect(requests[0].frame() === page.mainFrame()).toBe(true);
expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE);
});
it('Page.Events.RequestServedFromCache', async () => {
const { page, server } = getTestState();
const cached = [];
page.on('requestservedfromcache', (r) =>
cached.push(r.url().split('/').pop())
);
await page.goto(server.PREFIX + '/cached/one-style.html');
expect(cached).toEqual([]);
await page.reload();
expect(cached).toEqual(['one-style.css']);
});
it('Page.Events.Response', async () => {
const { page, server } = getTestState();
@ -567,5 +583,28 @@ describe('network', function () {
response = await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
expect(response.status()).toBe(401);
});
it('should not disable caching', async () => {
const { page, server } = getTestState();
// Use unique user/password since Chrome caches credentials per origin.
server.setAuth('/cached/one-style.css', 'user4', 'pass4');
server.setAuth('/cached/one-style.html', 'user4', 'pass4');
await page.authenticate({
username: 'user4',
password: 'pass4',
});
const responses = new Map();
page.on('response', (r) => responses.set(r.url().split('/').pop(), r));
// Load and re-load to make sure it's cached.
await page.goto(server.PREFIX + '/cached/one-style.html');
await page.reload();
expect(responses.get('one-style.css').status()).toBe(200);
expect(responses.get('one-style.css').fromCache()).toBe(true);
expect(responses.get('one-style.html').status()).toBe(304);
expect(responses.get('one-style.html').fromCache()).toBe(false);
});
});
});

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

@ -21,9 +21,10 @@ import expect from 'expect';
import sinon from 'sinon';
import {
getTestState,
itFailsFirefox,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
import { Page, Metrics } from '../lib/cjs/puppeteer/common/Page.js';
import { JSHandle } from '../lib/cjs/puppeteer/common/JSHandle.js';

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

@ -22,6 +22,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('request interception', function () {
@ -494,6 +495,36 @@ 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 () => {
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);
page.on('request', (request) => request.continue());
const cached = [];
page.on('requestservedfromcache', (r) => cached.push(r));
await page.reload();
expect(cached.length).toBe(0);
});
it('should cache if cache-safe', 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);
page.on('request', (request) => request.continue());
const cached = [];
page.on('requestservedfromcache', (r) => cached.push(r));
await page.reload();
expect(cached.length).toBe(1);
});
});
describe('Request.continue', function () {

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

@ -19,6 +19,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('Screenshots', function () {

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

@ -21,6 +21,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
import { Target } from '../lib/cjs/puppeteer/common/Target.js';
@ -47,7 +48,6 @@ describe('Target', function () {
const allPages = await context.pages();
expect(allPages.length).toBe(1);
expect(allPages).toContain(page);
expect(allPages[0]).not.toBe(allPages[1]);
});
it('should contain browser target', async () => {
const { browser } = getTestState();

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

@ -19,6 +19,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
describeFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('Touchscreen', function () {

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

@ -21,6 +21,7 @@ import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
itFailsFirefox,
} from './mocha-utils'; // eslint-disable-line import/extensions
describe('waittask specs', function () {

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

@ -1,18 +1,14 @@
# DocLint
**Doclint** is a small program that lints Puppeteer's documentation against
Puppeteer's source code.
**Doclint** is a small program that lints Puppeteer's documentation against Puppeteer's source code.
Doclint works in a few steps:
1. Read sources in `lib/` folder, parse AST trees and extract public API
- note that we run DocLint on the outputted JavaScript in `lib/` rather than the source code in `src/`. We will do this until we have migrated `src/` to be exclusively TypeScript and then we can update DocLint to support TypeScript.
2. Read sources in `docs/` folder, render markdown to HTML, use puppeteer to traverse the HTML
and extract described API
3. Compare one API to another
1. Read sources in `lib/` folder, parse AST trees and extract public API. Note that we run DocLint on the outputted JavaScript in `lib/` rather than the source code in `src/`. We will do this until we have migrated `src/` to be exclusively TypeScript and then we can update DocLint to support TypeScript.
2. Read sources in `docs/` folder, render markdown to HTML, use puppeteer to traverse the HTML and extract described API.
3. Compare one API to another.
Doclint is also responsible for general markdown checks, most notably for the table of contents
relevancy.
Doclint is also responsible for general markdown checks, most notably for the table of contents relevancy.
## Running

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

@ -864,6 +864,27 @@ function compareDocumentations(actual, expected) {
expectedName: 'Array<Permission>',
},
],
[
'Method HTTPRequest.respond() response.body',
{
actualName: 'string|Buffer',
expectedName: 'Object',
},
],
[
'Method HTTPRequest.respond() response.contentType',
{
actualName: 'string',
expectedName: 'Object',
},
],
[
'Method HTTPRequest.respond() response.status',
{
actualName: 'number',
expectedName: 'Object',
},
],
]);
const expectedForSource = expectedNamingMismatches.get(source);

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

@ -1,7 +1,14 @@
/**
* @public
*/
export type EventType = string | symbol;
// An event handler can take an optional event argument
// and should not return a value
/**
* @public
*/
export type Handler<T = any> = (event?: T) => void;
export type WildcardHandler = (type: EventType, event?: any) => void;

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

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