diff --git a/remote/puppeteer-expected.json b/remote/puppeteer-expected.json
index 7b4842daf2096..f4becc45e196f 100644
--- a/remote/puppeteer-expected.json
+++ b/remote/puppeteer-expected.json
@@ -332,6 +332,12 @@
"ElementHandle specs Custom queries should wait correctly with waitFor (elementhandle.spec.ts)": [
"PASS"
],
+ "ElementHandle specs Custom queries should work when both queryOne and queryAll are registered (elementhandle.spec.ts)": [
+ "PASS"
+ ],
+ "ElementHandle specs Custom queries should eval when both queryOne and queryAll are registered (elementhandle.spec.ts)": [
+ "PASS"
+ ],
"Emulation Page.viewport should get the proper viewport size (emulation.spec.ts)": [
"PASS"
],
@@ -632,6 +638,12 @@
"Frame specs Frame Management should report different frame instance when frame re-attaches (frame.spec.ts)": [
"PASS"
],
+ "Frame specs Frame Management should support url fragment (frame.spec.ts)": [
+ "PASS"
+ ],
+ "Emulate idle state changing idle state emulation causes change of the IdleDetector state (idle_override.spec.ts)": [
+ "FAIL"
+ ],
"ignoreHTTPSErrors should work (ignorehttpserrors.spec.ts)": [
"PASS"
],
@@ -929,6 +941,9 @@
"Mouse should set modifier keys on click (mouse.spec.ts)": [
"PASS"
],
+ "Mouse should send mouse wheel events (mouse.spec.ts)": [
+ "FAIL"
+ ],
"Mouse should tween mouse movement (mouse.spec.ts)": [
"PASS", "FAIL"
],
@@ -1211,9 +1226,6 @@
"Page Page.Events.Load should fire when expected (page.spec.ts)": [
"PASS"
],
- "Page Async stacks should work (page.spec.ts)": [
- "TIMEOUT"
- ],
"Page removing and adding event handlers should correctly fire event handlers as they are added and then removed (page.spec.ts)": [
"FAIL"
],
@@ -1295,7 +1307,7 @@
"Page Page.Events.Console should have location when fetch fails (page.spec.ts)": [
"FAIL"
],
- "Page Page.Events.Console should have location for console API calls (page.spec.ts)": [
+ "Page Page.Events.Console should have location and stack trace for console API calls (page.spec.ts)": [
"FAIL"
],
"Page Page.Events.Console should not throw when there are console messages in detached iframes (page.spec.ts)": [
@@ -1565,9 +1577,24 @@
"querySelector Page.$eval should throw error if no element is found (queryselector.spec.ts)": [
"PASS"
],
+ "querySelector pierceHandler should find first element in shadow (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector pierceHandler should find all elements in shadow (queryselector.spec.ts)": [
+ "PASS"
+ ],
"querySelector Page.$$eval should work (queryselector.spec.ts)": [
"PASS"
],
+ "querySelector Page.$$eval should accept extra arguments (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector Page.$$eval should accept ElementHandles as arguments (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector Page.$$eval should handle many elements (queryselector.spec.ts)": [
+ "PASS"
+ ],
"querySelector Page.$ should query existing element (queryselector.spec.ts)": [
"PASS"
],
@@ -1625,6 +1652,27 @@
"querySelector ElementHandle.$x should return null for non-existing element (queryselector.spec.ts)": [
"PASS"
],
+ "querySelector QueryAll should have registered handler (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector QueryAll $$ should query existing elements (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector QueryAll $$ should return empty array for non-existing elements (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector QueryAll $$eval should work (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector QueryAll $$eval should accept extra arguments (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector QueryAll $$eval should accept ElementHandles as arguments (queryselector.spec.ts)": [
+ "PASS"
+ ],
+ "querySelector QueryAll $$eval should handle many elements (queryselector.spec.ts)": [
+ "PASS"
+ ],
"request interception Page.setRequestInterception should intercept (requestinterception.spec.ts)": [
"FAIL"
],
@@ -1685,7 +1733,7 @@
"request interception Page.setRequestInterception should be able to fetch dataURL and fire dataURL requests (requestinterception.spec.ts)": [
"FAIL"
],
- "request interception Page.setRequestInterception should navigate to URL with hash and and fire requests without hash (requestinterception.spec.ts)": [
+ "request interception Page.setRequestInterception should navigate to URL with hash and fire requests without hash (requestinterception.spec.ts)": [
"FAIL"
],
"request interception Page.setRequestInterception should work with encoded server (requestinterception.spec.ts)": [
@@ -1868,6 +1916,9 @@
"waittask specs Page.waitFor should wait for predicate with arguments (waittask.spec.ts)": [
"PASS"
],
+ "waittask specs Page.waitFor should log a deprecation warning (waittask.spec.ts)": [
+ "PASS"
+ ],
"waittask specs Frame.waitForFunction should accept a string (waittask.spec.ts)": [
"PASS"
],
@@ -1925,6 +1976,12 @@
"waittask specs Frame.waitForFunction should survive navigations (waittask.spec.ts)": [
"PASS"
],
+ "waittask specs Page.waitForTimeout waits for the given timeout before resolving (waittask.spec.ts)": [
+ "PASS"
+ ],
+ "waittask specs Frame.waitForTimeout waits for the given timeout before resolving (waittask.spec.ts)": [
+ "PASS"
+ ],
"waittask specs Frame.waitForSelector should immediately resolve promise if node exists (waittask.spec.ts)": [
"PASS"
],
diff --git a/remote/test/puppeteer/.eslintignore b/remote/test/puppeteer/.eslintignore
index 54c6043ef961a..f4c17fcc0f25e 100644
--- a/remote/test/puppeteer/.eslintignore
+++ b/remote/test/puppeteer/.eslintignore
@@ -6,9 +6,9 @@ node6/*
node6-test/*
experimental/
lib/
-src/externs.d.ts
-src/protocol.d.ts
/index.d.ts
# We ignore this file because it uses ES imports which we don't yet use
# in the Puppeteer src, so it trips up the ESLint-TypeScript parser.
utils/doclint/generate_types/test/test.ts
+vendor/
+web-test-runner.config.mjs
diff --git a/remote/test/puppeteer/.eslintrc.js b/remote/test/puppeteer/.eslintrc.js
index 32b5d16114941..a1de9853eeffd 100644
--- a/remote/test/puppeteer/.eslintrc.js
+++ b/remote/test/puppeteer/.eslintrc.js
@@ -1,118 +1,183 @@
module.exports = {
- "root": true,
- "env": {
- "node": true,
- "es6": true
- },
+ root: true,
+ env: {
+ node: true,
+ es6: true,
+ },
- "parser": "@typescript-eslint/parser",
+ parser: '@typescript-eslint/parser',
- "plugins": [
- "mocha",
- "@typescript-eslint",
- "unicorn"
- ],
+ plugins: ['mocha', '@typescript-eslint', 'unicorn', 'import'],
+
+ extends: ['plugin:prettier/recommended'],
- "extends": [
- "plugin:prettier/recommended"
+ rules: {
+ // Error if files are not formatted with Prettier correctly.
+ 'prettier/prettier': 2,
+ // syntax preferences
+ quotes: [
+ 2,
+ 'single',
+ {
+ avoidEscape: true,
+ allowTemplateLiterals: true,
+ },
+ ],
+ 'spaced-comment': [
+ 2,
+ 'always',
+ {
+ markers: ['*'],
+ },
+ ],
+ eqeqeq: [2],
+ 'accessor-pairs': [
+ 2,
+ {
+ getWithoutSet: false,
+ setWithoutGet: false,
+ },
],
+ 'new-parens': 2,
+ 'func-call-spacing': 2,
+ 'prefer-const': 2,
- "rules": {
- // Error if files are not formatted with Prettier correctly.
- "prettier/prettier": 2,
- // syntax preferences
- "quotes": [2, "single", {
- "avoidEscape": true,
- "allowTemplateLiterals": true
- }],
- "spaced-comment": [2, "always", {
- "markers": ["*"]
- }],
- "eqeqeq": [2],
- "accessor-pairs": [2, {
- "getWithoutSet": false,
- "setWithoutGet": false
- }],
- "new-parens": 2,
- "func-call-spacing": 2,
- "prefer-const": 2,
+ 'max-len': [
+ 2,
+ {
+ /* this setting doesn't impact things as we use Prettier to format
+ * our code and hence dictate the line length.
+ * Prettier aims for 80 but sometimes makes the decision to go just
+ * over 80 chars as it decides that's better than wrapping. ESLint's
+ * rule defaults to 80 but therefore conflicts with Prettier. So we
+ * set it to something far higher than Prettier would allow to avoid
+ * it causing issues and conflicting with Prettier.
+ */
+ code: 200,
+ comments: 90,
+ ignoreTemplateLiterals: true,
+ ignoreUrls: true,
+ ignoreStrings: true,
+ ignoreRegExpLiterals: true,
+ },
+ ],
+ // anti-patterns
+ 'no-var': 2,
+ 'no-with': 2,
+ 'no-multi-str': 2,
+ 'no-caller': 2,
+ 'no-implied-eval': 2,
+ 'no-labels': 2,
+ 'no-new-object': 2,
+ 'no-octal-escape': 2,
+ 'no-self-compare': 2,
+ 'no-shadow-restricted-names': 2,
+ 'no-cond-assign': 2,
+ 'no-debugger': 2,
+ 'no-dupe-keys': 2,
+ 'no-duplicate-case': 2,
+ 'no-empty-character-class': 2,
+ 'no-unreachable': 2,
+ 'no-unsafe-negation': 2,
+ radix: 2,
+ 'valid-typeof': 2,
+ 'no-unused-vars': [
+ 2,
+ {
+ args: 'none',
+ vars: 'local',
+ varsIgnorePattern:
+ '([fx]?describe|[fx]?it|beforeAll|beforeEach|afterAll|afterEach)',
+ },
+ ],
+ 'no-implicit-globals': [2],
- "max-len": [2, {
- /* this setting doesn't impact things as we use Prettier to format
- * our code and hence dictate the line length.
- * Prettier aims for 80 but sometimes makes the decision to go just
- * over 80 chars as it decides that's better than wrapping. ESLint's
- * rule defaults to 80 but therefore conflicts with Prettier. So we
- * set it to something far higher than Prettier would allow to avoid
- * it causing issues and conflicting with Prettier.
- */
- "code": 200,
- "comments": 90,
- "ignoreTemplateLiterals": true,
- "ignoreUrls": true,
- "ignoreStrings": true,
- "ignoreRegExpLiterals": true
- }],
- // anti-patterns
- "no-var": 2,
- "no-with": 2,
- "no-multi-str": 2,
- "no-caller": 2,
- "no-implied-eval": 2,
- "no-labels": 2,
- "no-new-object": 2,
- "no-octal-escape": 2,
- "no-self-compare": 2,
- "no-shadow-restricted-names": 2,
- "no-cond-assign": 2,
- "no-debugger": 2,
- "no-dupe-keys": 2,
- "no-duplicate-case": 2,
- "no-empty-character-class": 2,
- "no-unreachable": 2,
- "no-unsafe-negation": 2,
- "radix": 2,
- "valid-typeof": 2,
- "no-unused-vars": [2, { "args": "none", "vars": "local", "varsIgnorePattern": "([fx]?describe|[fx]?it|beforeAll|beforeEach|afterAll|afterEach)" }],
- "no-implicit-globals": [2],
+ // es2015 features
+ 'require-yield': 2,
+ 'template-curly-spacing': [2, 'never'],
- // es2015 features
- "require-yield": 2,
- "template-curly-spacing": [2, "never"],
+ // ensure we don't have any it.only or describe.only in prod
+ 'mocha/no-exclusive-tests': 'error',
- // ensure we don't have any it.only or describe.only in prod
- "mocha/no-exclusive-tests": "error",
+ // enforce the variable in a catch block is named error
+ 'unicorn/catch-error-name': 'error',
- // enforce the variable in a catch block is named error
- "unicorn/catch-error-name": "error"
+ 'no-restricted-imports': [
+ 'error',
+ {
+ patterns: ['*Events'],
+ paths: [
+ {
+ name: 'mitt',
+ message:
+ 'Import Mitt from the vendored location: vendor/mitt/src/index.js',
+ },
+ ],
+ },
+ ],
+ 'import/extensions': ['error', 'ignorePackages'],
+ },
+ overrides: [
+ {
+ files: ['*.ts'],
+ extends: [
+ 'plugin:@typescript-eslint/eslint-recommended',
+ 'plugin:@typescript-eslint/recommended',
+ ],
+ rules: {
+ 'no-unused-vars': 0,
+ '@typescript-eslint/no-unused-vars': 2,
+ 'func-call-spacing': 0,
+ '@typescript-eslint/func-call-spacing': 2,
+ semi: 0,
+ '@typescript-eslint/semi': 2,
+ '@typescript-eslint/no-empty-function': 0,
+ '@typescript-eslint/no-use-before-define': 0,
+ // We have to use any on some types so the warning isn't valuable.
+ '@typescript-eslint/no-explicit-any': 0,
+ // We don't require explicit return types on basic functions or
+ // dummy functions in tests, for example
+ '@typescript-eslint/explicit-function-return-type': 0,
+ // We know it's bad and use it very sparingly but it's needed :(
+ '@typescript-eslint/ban-ts-ignore': 0,
+ /**
+ * This is the default options (as per
+ * https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-types.md),
+ *
+ * Unfortunately there's no way to
+ */
+ '@typescript-eslint/ban-types': [
+ 'error',
+ {
+ extendDefaults: true,
+ types: {
+ /*
+ * Puppeteer's API accepts generic functions in many places so it's
+ * not a useful linting rule to ban the `Function` type. This turns off
+ * the banning of the `Function` type which is a default rule.
+ */
+ Function: false,
+ },
+ },
+ ],
+ '@typescript-eslint/array-type': [
+ 2,
+ {
+ default: 'array-simple',
+ },
+ ],
+ },
+ },
+ {
+ files: ['test-browser/**/*.js'],
+ parserOptions: {
+ sourceType: 'module',
+ },
+ env: {
+ es6: true,
+ browser: true,
+ es2020: true,
+ },
},
- "overrides": [
- {
- "files": ["*.ts"],
- "extends": [
- 'plugin:@typescript-eslint/eslint-recommended',
- 'plugin:@typescript-eslint/recommended',
- ],
- "rules": {
- "no-unused-vars": 0,
- "@typescript-eslint/no-unused-vars": 2,
- "func-call-spacing": 0,
- "@typescript-eslint/func-call-spacing": 2,
- "semi": 0,
- "@typescript-eslint/semi": 2,
- "@typescript-eslint/no-empty-function": 0,
- "@typescript-eslint/no-use-before-define": 0,
- // We have to use any on some types so the warning isn't valuable.
- "@typescript-eslint/no-explicit-any": 0,
- // We don't require explicit return types on basic functions or
- // dummy functions in tests, for example
- "@typescript-eslint/explicit-function-return-type": 0,
- // We know it's bad and use it very sparingly but it's needed :(
- "@typescript-eslint/ban-ts-ignore": 0,
- "@typescript-eslint/array-type": [2, {
- "default": "array-simple"
- }]
- }
- }
- ]
+ ],
};
diff --git a/remote/test/puppeteer/.github/workflows/publish-on-tag.yml b/remote/test/puppeteer/.github/workflows/publish-on-tag.yml
new file mode 100644
index 0000000000000..b16c1be3fb57b
--- /dev/null
+++ b/remote/test/puppeteer/.github/workflows/publish-on-tag.yml
@@ -0,0 +1,30 @@
+name: publish-on-tag
+
+on:
+ push:
+ tags:
+ - '*'
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ - name: Install dependencies
+ run: npm install
+ - name: Build
+ run: npm run build
+ - name: Publish puppeteer
+ env:
+ NPM_TOKEN: ${{secrets.NPM_TOKEN_PUPPETEER}}
+ run: |
+ npm config set '//wombat-dressing-room.appspot.com/:_authToken' '${NPM_TOKEN}'
+ npm publish
+ - name: Publish puppeteer-core
+ env:
+ NPM_TOKEN: ${{secrets.NPM_TOKEN_PUPPETEER_CORE}}
+ run: |
+ utils/prepare_puppeteer_core.js
+ npm config set '//wombat-dressing-room.appspot.com/:_authToken' '${NPM_TOKEN}'
+ npm publish
diff --git a/remote/test/puppeteer/.npmrc b/remote/test/puppeteer/.npmrc
new file mode 100644
index 0000000000000..f4335b67c183f
--- /dev/null
+++ b/remote/test/puppeteer/.npmrc
@@ -0,0 +1,2 @@
+registry=https://wombat-dressing-room.appspot.com/
+access=public
diff --git a/remote/test/puppeteer/.travis.yml b/remote/test/puppeteer/.travis.yml
index 8da18b9a8579a..3dccb9acedfca 100644
--- a/remote/test/puppeteer/.travis.yml
+++ b/remote/test/puppeteer/.travis.yml
@@ -1,11 +1,17 @@
language: node_js
services: xvfb
+# Throughout this file, the following `node_js` versions are being used:
+#
+# - node_js: '10' # The maintenance LTS version.
+# - node_js: '12' # The oldest major active LTS version.
+# - node_js: '14' # The newest major active LTS version.
+
jobs:
include:
- - os: "osx"
+ - os: 'osx'
name: 'Unit tests: macOS/Chromium'
- node_js: "10.19.0"
+ node_js: '10' # The maintenance LTS version.
osx_image: xcode11.4
env:
- CHROMIUM=true
@@ -14,11 +20,11 @@ jobs:
script:
- ls .local-chromium .local-firefox
- npm run tsc
- - travis_retry npm run unit
+ - npm run unit
- - os: "windows"
+ - os: 'windows'
name: 'Unit tests: Windows/Chromium'
- node_js: "10.19.0"
+ node_js: '10' # The maintenance LTS version.
env:
- CHROMIUM=true
before_install:
@@ -28,8 +34,21 @@ jobs:
- npm run tsc
- travis_retry npm run unit
- # Runs unit tests on Linux + Chromium
- - node_js: "10.19.0"
+ # Node <10.17's fs.promises module was experimental and doesn't behave as
+ # expected. This problem was fixed in Node 10.19, but we run the unit tests
+ # through on 10.15 to make sure we don't cause any regressions when using
+ # fs.promises. See https://github.com/puppeteer/puppeteer/issues/6548 for an
+ # example.
+ - node_js: '10.15.0'
+ name: 'Node 10.15 Unit tests: Linux/Chromium'
+ env:
+ - CHROMIUM=true
+ before_install:
+ - PUPPETEER_PRODUCT=firefox npm install
+ script:
+ - npm run unit
+
+ - node_js: '10' # The maintenance LTS version.
name: 'Unit tests [with coverage]: Linux/Chromium'
env:
- CHROMIUM=true
@@ -39,53 +58,61 @@ jobs:
- travis_retry npm run unit-with-coverage
- npm run assert-unit-coverage
- - node_js: "12.16.3"
+ - node_js: '12' # The oldest major active LTS version.
name: 'Unit tests [Node 12]: Linux/Chromium'
env:
- CHROMIUM=true
before_install:
- PUPPETEER_PRODUCT=firefox npm install
script:
- - travis_retry npm run unit
+ - npm run unit
- - node_js: "14.2.0"
+ - node_js: '14' # The newest major active LTS version.
name: 'Unit tests [Node 14]: Linux/Chromium'
env:
- CHROMIUM=true
before_install:
- PUPPETEER_PRODUCT=firefox npm install
script:
- - travis_retry npm run unit
+ - npm run unit
+
+ - node_js: '12' # The oldest major active LTS version.
+ name: 'Browser tests: Linux/Chromium'
+ addons:
+ chrome: stable
+ env:
+ - CHROMIUM=true
+ script:
+ - npm run test-browser
- # This bot runs all the extra checks that aren't the main Puppeteer unit tests
- - node_js: "10.19.0"
+ # This bot runs all the extra checks that aren't the main Puppeteer unit tests.
+ - node_js: '10' # The maintenance LTS version.
name: 'Extra tests: Linux/Chromium'
env:
- CHROMIUM=true
script:
- - npm run compare-protocol-d-ts
- npm run lint
- - npm run test-doclint
- - npm run ensure-new-docs-up-to-date
+ # Ensure that we can generate the new docs without erroring
+ - npm run generate-docs
+ - npm run ensure-correct-devtools-protocol-revision
# This bot runs separately as it changes package.json to test puppeteer-core
# and we don't want that leaking into other bots and causing issues.
- - node_js: "10.19.0"
+ - node_js: '10' # The maintenance LTS version.
name: 'Test bundling and install of packages'
env:
- CHROMIUM=true
script:
- npm run test-install
- # Runs unit tests on Linux + Firefox
- - node_js: "10.19.0"
+ - node_js: '10' # The maintenance LTS version.
name: 'Unit tests: Linux/Firefox'
env:
- FIREFOX=true
before_install:
- PUPPETEER_PRODUCT=firefox npm install
script:
- - travis_retry npm run funit
+ - npm run funit
notifications:
email: false
diff --git a/remote/test/puppeteer/.versionrc b/remote/test/puppeteer/.versionrc
new file mode 100644
index 0000000000000..a0247ed4aba84
--- /dev/null
+++ b/remote/test/puppeteer/.versionrc
@@ -0,0 +1,3 @@
+{
+ "releaseCommitMessageFormat": "chore(release): mark v{{currentTag}}"
+}
diff --git a/remote/test/puppeteer/CHANGELOG.md b/remote/test/puppeteer/CHANGELOG.md
new file mode 100644
index 0000000000000..35e3a06ddbcb1
--- /dev/null
+++ b/remote/test/puppeteer/CHANGELOG.md
@@ -0,0 +1,20 @@
+# Changelog
+
+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.
+
+## [5.5.0](https://github.com/puppeteer/puppeteer/compare/v5.4.1...v5.5.0) (2020-11-16)
+
+
+### Features
+
+* **chromium:** roll Chromium to r818858 ([#6526](https://github.com/puppeteer/puppeteer/issues/6526)) ([b549256](https://github.com/puppeteer/puppeteer/commit/b54925695200cad32f470f8eb407259606447a85))
+
+
+### Bug Fixes
+
+* **common:** fix generic type of `_isClosedPromise` ([#6579](https://github.com/puppeteer/puppeteer/issues/6579)) ([122f074](https://github.com/puppeteer/puppeteer/commit/122f074f92f47a7b9aa08091851e51a07632d23b))
+* **domworld:** fix missing binding for waittasks ([#6562](https://github.com/puppeteer/puppeteer/issues/6562)) ([67da1cf](https://github.com/puppeteer/puppeteer/commit/67da1cf866703f5f581c9cce4923697ac38129ef))
+
+# Changelog
+
+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.
diff --git a/remote/test/puppeteer/CONTRIBUTING.md b/remote/test/puppeteer/CONTRIBUTING.md
index 5cf0d56fce334..54bfb306eda6f 100644
--- a/remote/test/puppeteer/CONTRIBUTING.md
+++ b/remote/test/puppeteer/CONTRIBUTING.md
@@ -5,6 +5,10 @@
* [Code reviews](#code-reviews)
* [Code Style](#code-style)
* [TypeScript guidelines](#typescript-guidelines)
+ * [Project structure and TypeScript compilation](#project-structure-and-typescript-compilation)
+ - [Shipping CJS and ESM bundles](#shipping-cjs-and-esm-bundles)
+ - [tsconfig for the tests](#tsconfig-for-the-tests)
+ - [Root `tsconfig.json`](#root-tsconfigjson)
* [API guidelines](#api-guidelines)
* [Commit Messages](#commit-messages)
* [Writing Documentation](#writing-documentation)
@@ -13,8 +17,9 @@
* [Public API Coverage](#public-api-coverage)
* [Debugging Puppeteer](#debugging-puppeteer)
- [For Project Maintainers](#for-project-maintainers)
+ * [Rolling new Chromium version](#rolling-new-chromium-version)
+ - [Bisecting upstream changes](#bisecting-upstream-changes)
* [Releasing to npm](#releasing-to-npm)
- * [Updating npm dist tags](#updating-npm-dist-tags)
# How to Contribute
@@ -85,6 +90,42 @@ npm run tsc
- Try to avoid the use of `any` when possible. Consider `unknown` as a better alternative. You are able to use `any` if needbe, but it will generate an ESLint warning.
+## Project structure and TypeScript compilation
+
+The code in Puppeteer is split primarily into two folders:
+
+- `src` contains all source code
+- `vendor` contains all dependencies that we've vendored into the codebase. See the [`vendor/README.md`](https://github.com/puppeteer/puppeteer/blob/main/vendor/README.md) for details.
+
+We structure these using TypeScript's project references, which lets us treat each folder like a standalone TypeScript project.
+
+### Shipping CJS and ESM bundles
+
+Currently Puppeteer ships two bundles; a CommonJS version for Node and an ESM bundle for the browser. Therefore we maintain two `tsconfig` files for each project; `tsconfig.esm.json` and `tsconfig.cjs.json`. At build time we compile twice, once outputting to CJS and another time to output to ESM.
+
+We compile into the `lib` directory which is what we publish on the npm repository and it's structured like so:
+
+```
+lib
+- cjs
+ - puppeteer <== the output of compiling `src/tsconfig.cjs.json`
+ - vendor <== the output of compiling `vendor/tsconfig.cjs.json`
+- esm
+ - puppeteer <== the output of compiling `src/tsconfig.esm.json`
+ - vendor <== the output of compiling `vendor/tsconfig.esm.json`
+```
+
+The main entry point for the Node module Puppeteer is `cjs-entry.js`. This imports `lib/cjs/puppeteer/index.js` and exposes it to Node users.
+
+### tsconfig for the tests
+
+We also maintain `test/tsconfig.test.json`. This is **only used to compile the unit test `*.spec.ts` files**. When the tests are run, we first compile Puppeteer as normal before running the unit tests **against the compiled output**. Doing this lets the test run against the compiled code we ship to users so it gives us more confidence in our compiled output being correct.
+
+### Root `tsconfig.json`
+
+The root `tsconfig.json` exists for the API Extractor; it has to find a `tsconfig.json` in the project's root directory. It is _not_ used for anything else.
+
+
## API guidelines
When authoring new API methods, consider the following:
@@ -97,40 +138,19 @@ When authoring new API methods, consider the following:
## Commit Messages
-Commit messages should follow the Semantic Commit Messages format:
-
-```
-label(namespace): title
+Commit messages should follow [the Conventional Commits format](https://www.conventionalcommits.org/en/v1.0.0/#summary). This is enforced via `npm run lint`.
-description
-
-footer
-```
-
-1. *label* is one of the following:
- - `fix` - puppeteer bug fixes.
- - `feat` - puppeteer features.
- - `docs` - changes to docs, e.g. `docs(api.md): ..` to change documentation.
- - `test` - changes to puppeteer tests infrastructure.
- - `style` - puppeteer code style: spaces/alignment/wrapping etc.
- - `chore` - build-related work, e.g. doclint changes / travis / appveyor.
-2. *namespace* is put in parenthesis after label and is optional. Must be lowercase.
-3. *title* is a brief summary of changes.
-4. *description* is **optional**, new-line separated from title and is in present tense.
-5. *footer* is **optional**, new-line separated from *description* and contains "fixes" / "references" attribution to github issues.
-6. *footer* should also include "BREAKING CHANGE" if current API clients will break due to this change. It should explain what changed and how to get the old behavior.
-
-Example:
+In particular, breaking changes should clearly be noted as “BREAKING CHANGE:” in the commit message footer. Example:
```
fix(page): fix page.pizza method
This patch fixes page.pizza so that it works with iframes.
-Fixes #123, Fixes #234
+Issues: #123, #234
BREAKING CHANGE: page.pizza now delivers pizza at home by default.
-To deliver to a different location, use "deliver" option:
+To deliver to a different location, use the "deliver" option:
`page.pizza({deliver: 'work'})`.
```
@@ -153,6 +173,9 @@ For all dependencies (both installation and development):
A barrier for introducing new installation dependencies is especially high:
- **Do not add** installation dependency unless it's critical to project success.
+There are additional considerations for dependencies that are environment agonistic. See the [`vendor/README.md`](https://github.com/puppeteer/puppeteer/blob/main/vendor/README.md) for details.
+
+
## Running & Writing Tests
- Every feature should be accompanied by a test.
@@ -226,47 +249,42 @@ See [Debugging Tips](README.md#debugging-tips) in the readme.
# For Project Maintainers
+## Rolling new Chromium version
+
+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).
+1. Update `src/revisions.ts` with the found revision number.
+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 it’s not desirable to change Puppeteer’s observable behavior).
+1. Update `versions.js` with the new Chromium-to-Puppeteer version mapping.
+1. Commit and push your changes and open a pull request.
+
+### Bisecting upstream changes
+
+Sometimes, performing a Chromium roll causes tests to fail. To figure out the cause, you need to bisect Chromium revisions to figure out the earliest possible revision that changed the behavior. The script in `utils/bisect.js` can be helpful here. Given a Node.js script that calls `process.exit(1)` for bad revisions, run this from the Puppeteer repository’s root directory:
+
+```sh
+node utils/bisect.js --good 686378 --bad 706915 script.js
+```
+
## Releasing to npm
Releasing to npm consists of the following phases:
1. Source Code: mark a release.
- 1. Bump `package.json` version following the SEMVER rules.
- 2. Run `npm run doc` to update the docs accordingly.
- 3. Update the “Releases per Chromium Version” list in [`docs/api.md`](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md) to include the new version. Note: only do this when the Chrome revision is different from the previous release.
- 4. Send a PR titled `'chore: mark version vXXX.YYY.ZZZ'` ([example](https://github.com/puppeteer/puppeteer/pull/5078)).
- 5. Make sure the PR passes **all checks**.
+ 1. Run `npm run release` to bump the version number in `package.json` and populate the changelog.
+ 1. Run `npm run doc` to update the docs accordingly.
+ 1. Send a PR titled `'chore(release): mark vXXX.YYY.ZZZ'` ([example](https://github.com/puppeteer/puppeteer/pull/5078)).
+ 1. Make sure the PR passes **all checks**.
- **WHY**: there are linters in place that help to avoid unnecessary errors, e.g. [like this](https://github.com/puppeteer/puppeteer/pull/2446)
- 6. Merge the PR.
- 7. Once merged, publish the release notes using [GitHub's “draft new release tag” option](https://github.com/puppeteer/puppeteer/releases/new).
+ 1. Merge the PR.
+ 1. Once merged, publish the release notes from `CHANGELOG.md` using [GitHub’s “draft new release tag” option](https://github.com/puppeteer/puppeteer/releases/new).
- **NOTE**: tag names are prefixed with `'v'`, e.g. for version `1.4.0` the tag is `v1.4.0`.
- - For the “raw notes” section, use `git log --pretty="%h - %s" v2.0.0..HEAD`.
-2. Publish `puppeteer` to npm.
- 1. On your local machine, pull from [upstream](https://github.com/puppeteer/puppeteer) and make sure the last commit is the one just merged.
- 2. Run `git status` and make sure there are no untracked files.
- - **WHY**: this is to avoid adding unnecessary files to the npm package.
- 3. Run [`npx pkgfiles`](https://www.npmjs.com/package/pkgfiles) to make sure you don't publish anything unnecessary.
- 4. Run `npm publish`. This publishes the `puppeteer` package.
-3. Publish `puppeteer-core` to npm.
- 1. Run `./utils/prepare_puppeteer_core.js`. The script changes the name inside `package.json` to `puppeteer-core`.
- 2. Run `npm publish`. This publishes the `puppeteer-core` package.
- 3. Run `git reset --hard` to reset the changes to `package.json`.
-4. Source Code: mark post-release.
- 1. Bump `package.json` version to `-post` version, run `npm run doc` to update the “released APIs” section at the top of `docs/api.md` accordingly, and send a PR titled `'chore: bump version to vXXX.YYY.ZZZ-post'` ([example](https://github.com/puppeteer/puppeteer/commit/d02440d1eac98028e29f4e1cf55413062a259156))
+ 1. As soon as the Git tag is created by completing the previous step, our CI automatically `npm publish`es the new releases for both the `puppeteer` and `puppeteer-core` packages.
+1. Source Code: mark post-release.
+ 1. Bump `package.json` version to the `-post` version, run `npm run doc` to update the “released APIs” section at the top of `docs/api.md` accordingly, and send a PR titled `'chore: bump version to vXXX.YYY.ZZZ-post'` ([example](https://github.com/puppeteer/puppeteer/commit/d02440d1eac98028e29f4e1cf55413062a259156))
- **NOTE**: no other commits should be landed in-between release commit and bump commit.
-
-## Updating npm dist tags
-
-For both `puppeteer` and `puppeteer-core` we maintain `chrome-*` npm dist tags, e.g. `chrome-75` and so on. These tags match the Puppeteer version that corresponds to the `chrome-*` release.
-
-These tags are updated on every Puppeteer release.
-
-Managing tags 101:
-
-```bash
-# List tags
-$ npm dist-tag ls puppeteer
-# Add tags
-$ npm dist-tag add puppeteer@3.0.0 chrome-81
-$ npm dist-tag add puppeteer-core@3.0.0 chrome-81
-```
diff --git a/remote/test/puppeteer/LICENSE b/remote/test/puppeteer/LICENSE
index afdfe50e72e0e..d2c171df74e93 100644
--- a/remote/test/puppeteer/LICENSE
+++ b/remote/test/puppeteer/LICENSE
@@ -1,7 +1,7 @@
Apache License
Version 2.0, January 2004
- http://www.apache.org/licenses/
+ https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -193,7 +193,7 @@
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
+ https://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,
diff --git a/remote/test/puppeteer/README.md b/remote/test/puppeteer/README.md
index c76cbbbe24e2a..d50b8245e0b78 100644
--- a/remote/test/puppeteer/README.md
+++ b/remote/test/puppeteer/README.md
@@ -6,7 +6,7 @@
-###### [API](https://github.com/puppeteer/puppeteer/blob/v5.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/v5.5.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.
@@ -37,7 +37,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/v5.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/v5.5.0/docs/api.md#environment-variables).
### puppeteer-core
@@ -63,7 +63,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/v5.0.0/docs/api.md#).
+of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v5.5.0/docs/api.md#).
**Example** - navigating to https://example.com and saving a screenshot as *example.png*:
@@ -88,7 +88,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/v5.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/v5.5.0/docs/api.md#pagesetviewportviewport).
**Example** - create a PDF.
@@ -113,7 +113,7 @@ Execute script on the command line
node hn.js
```
-See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v5.0.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.
+See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v5.5.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.
**Example** - evaluate script in the context of the page
@@ -148,7 +148,7 @@ Execute script on the command line
node get-dimensions.js
```
-See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v5.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/v5.5.0/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.
@@ -157,7 +157,7 @@ See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v5.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/v5.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/v5.5.0/docs/api.md#puppeteerlaunchoptions) when launching a browser:
```js
const browser = await puppeteer.launch({headless: false}); // default is true
@@ -173,7 +173,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/v5.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/v5.5.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.
@@ -185,7 +185,7 @@ Puppeteer creates its own browser user profile which it **cleans up on every run
## Resources
-- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v5.0.0/docs/api.md)
+- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v5.5.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)
@@ -328,7 +328,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/v5.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/v5.5.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).
@@ -424,7 +424,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/v5.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/v5.5.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?
diff --git a/remote/test/puppeteer/api-extractor.json b/remote/test/puppeteer/api-extractor.json
index 8cc8240aa41e6..3e7b9e66f625e 100644
--- a/remote/test/puppeteer/api-extractor.json
+++ b/remote/test/puppeteer/api-extractor.json
@@ -1,7 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
- "mainEntryPointFilePath": "/lib/cjs/api-docs-entry.d.ts",
- "bundledPackages": [ ],
+ "mainEntryPointFilePath": "/lib/cjs/puppeteer/api-docs-entry.d.ts",
+ "bundledPackages": [ "devtools-protocol" ],
"apiReport": {
"enabled": false
diff --git a/remote/test/puppeteer/cjs-entry-core.js b/remote/test/puppeteer/cjs-entry-core.js
index efcdb39027f7e..446726fafa35a 100644
--- a/remote/test/puppeteer/cjs-entry-core.js
+++ b/remote/test/puppeteer/cjs-entry-core.js
@@ -25,5 +25,5 @@
* This means that we can publish to CJS and ESM whilst maintaining the expected
* import behaviour for CJS and ESM users.
*/
-const puppeteerExport = require('./lib/cjs/index-core');
+const puppeteerExport = require('./lib/cjs/puppeteer/node-puppeteer-core');
module.exports = puppeteerExport.default;
diff --git a/remote/test/puppeteer/cjs-entry.js b/remote/test/puppeteer/cjs-entry.js
index 424ffadf1a14e..d1840a9bea1bf 100644
--- a/remote/test/puppeteer/cjs-entry.js
+++ b/remote/test/puppeteer/cjs-entry.js
@@ -25,5 +25,5 @@
* This means that we can publish to CJS and ESM whilst maintaining the expected
* import behaviour for CJS and ESM users.
*/
-const puppeteerExport = require('./lib/cjs/index');
+const puppeteerExport = require('./lib/cjs/puppeteer/node');
module.exports = puppeteerExport.default;
diff --git a/remote/test/puppeteer/commitlint.config.js b/remote/test/puppeteer/commitlint.config.js
new file mode 100644
index 0000000000000..2e216cd897cd3
--- /dev/null
+++ b/remote/test/puppeteer/commitlint.config.js
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2020 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.
+ */
+module.exports = {
+ extends: ['@commitlint/config-conventional'],
+ rules: {
+ 'body-max-line-length': [0, 'always', 100],
+ 'footer-max-line-length': [0, 'always', 100],
+ },
+};
diff --git a/remote/test/puppeteer/docs/api.md b/remote/test/puppeteer/docs/api.md
deleted file mode 100644
index e3d2c8c198d20..0000000000000
--- a/remote/test/puppeteer/docs/api.md
+++ /dev/null
@@ -1,4099 +0,0 @@
-
-# Puppeteer API v5.0.0
-
-
-- Interactive Documentation: https://pptr.dev
-- API Translations: [中文|Chinese](https://zhaoqize.github.io/puppeteer-api-zh_CN/#/)
-- Troubleshooting: [troubleshooting.md](https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md)
-- Releases per Chromium Version:
- * Chromium 83.0.4103.0 - [Puppeteer v3.1.0](https://github.com/puppeteer/puppeteer/blob/v3.1.0/docs/api.md)
- * Chromium 81.0.4044.0 - [Puppeteer v3.0.0](https://github.com/puppeteer/puppeteer/blob/v3.0.0/docs/api.md)
- * Chromium 80.0.3987.0 - [Puppeteer v2.1.0](https://github.com/puppeteer/puppeteer/blob/v2.1.0/docs/api.md)
- * Chromium 79.0.3942.0 - [Puppeteer v2.0.0](https://github.com/puppeteer/puppeteer/blob/v2.0.0/docs/api.md)
- * Chromium 78.0.3882.0 - [Puppeteer v1.20.0](https://github.com/puppeteer/puppeteer/blob/v1.20.0/docs/api.md)
- * Chromium 77.0.3803.0 - [Puppeteer v1.19.0](https://github.com/puppeteer/puppeteer/blob/v1.19.0/docs/api.md)
- * Chromium 76.0.3803.0 - [Puppeteer v1.17.0](https://github.com/puppeteer/puppeteer/blob/v1.17.0/docs/api.md)
- * Chromium 75.0.3765.0 - [Puppeteer v1.15.0](https://github.com/puppeteer/puppeteer/blob/v1.15.0/docs/api.md)
- * Chromium 74.0.3723.0 - [Puppeteer v1.13.0](https://github.com/puppeteer/puppeteer/blob/v1.13.0/docs/api.md)
- * Chromium 73.0.3679.0 - [Puppeteer v1.12.2](https://github.com/puppeteer/puppeteer/blob/v1.12.2/docs/api.md)
- * [All releases](https://github.com/puppeteer/puppeteer/releases)
-
-
-##### Table of Contents
-
-
-- [Overview](#overview)
-- [puppeteer vs puppeteer-core](#puppeteer-vs-puppeteer-core)
-- [Environment Variables](#environment-variables)
-- [Working with Chrome Extensions](#working-with-chrome-extensions)
-- [class: Puppeteer](#class-puppeteer)
- * [puppeteer.connect(options)](#puppeteerconnectoptions)
- * [puppeteer.createBrowserFetcher([options])](#puppeteercreatebrowserfetcheroptions)
- * [puppeteer.defaultArgs([options])](#puppeteerdefaultargsoptions)
- * [puppeteer.devices](#puppeteerdevices)
- * [puppeteer.errors](#puppeteererrors)
- * [puppeteer.executablePath()](#puppeteerexecutablepath)
- * [puppeteer.launch([options])](#puppeteerlaunchoptions)
- * [puppeteer.product](#puppeteerproduct)
-- [class: BrowserFetcher](#class-browserfetcher)
- * [browserFetcher.canDownload(revision)](#browserfetchercandownloadrevision)
- * [browserFetcher.download(revision[, progressCallback])](#browserfetcherdownloadrevision-progresscallback)
- * [browserFetcher.host()](#browserfetcherhost)
- * [browserFetcher.localRevisions()](#browserfetcherlocalrevisions)
- * [browserFetcher.platform()](#browserfetcherplatform)
- * [browserFetcher.product()](#browserfetcherproduct)
- * [browserFetcher.remove(revision)](#browserfetcherremoverevision)
- * [browserFetcher.revisionInfo(revision)](#browserfetcherrevisioninforevision)
-- [class: Browser](#class-browser)
- * [event: 'disconnected'](#event-disconnected)
- * [event: 'targetchanged'](#event-targetchanged)
- * [event: 'targetcreated'](#event-targetcreated)
- * [event: 'targetdestroyed'](#event-targetdestroyed)
- * [browser.browserContexts()](#browserbrowsercontexts)
- * [browser.close()](#browserclose)
- * [browser.createIncognitoBrowserContext()](#browsercreateincognitobrowsercontext)
- * [browser.defaultBrowserContext()](#browserdefaultbrowsercontext)
- * [browser.disconnect()](#browserdisconnect)
- * [browser.isConnected()](#browserisconnected)
- * [browser.newPage()](#browsernewpage)
- * [browser.pages()](#browserpages)
- * [browser.process()](#browserprocess)
- * [browser.target()](#browsertarget)
- * [browser.targets()](#browsertargets)
- * [browser.userAgent()](#browseruseragent)
- * [browser.version()](#browserversion)
- * [browser.waitForTarget(predicate[, options])](#browserwaitfortargetpredicate-options)
- * [browser.wsEndpoint()](#browserwsendpoint)
-- [class: BrowserContext](#class-browsercontext)
- * [event: 'targetchanged'](#event-targetchanged-1)
- * [event: 'targetcreated'](#event-targetcreated-1)
- * [event: 'targetdestroyed'](#event-targetdestroyed-1)
- * [browserContext.browser()](#browsercontextbrowser)
- * [browserContext.clearPermissionOverrides()](#browsercontextclearpermissionoverrides)
- * [browserContext.close()](#browsercontextclose)
- * [browserContext.isIncognito()](#browsercontextisincognito)
- * [browserContext.newPage()](#browsercontextnewpage)
- * [browserContext.overridePermissions(origin, permissions)](#browsercontextoverridepermissionsorigin-permissions)
- * [browserContext.pages()](#browsercontextpages)
- * [browserContext.targets()](#browsercontexttargets)
- * [browserContext.waitForTarget(predicate[, options])](#browsercontextwaitfortargetpredicate-options)
-- [class: Page](#class-page)
- * [event: 'close'](#event-close)
- * [event: 'console'](#event-console)
- * [event: 'dialog'](#event-dialog)
- * [event: 'domcontentloaded'](#event-domcontentloaded)
- * [event: 'error'](#event-error)
- * [event: 'frameattached'](#event-frameattached)
- * [event: 'framedetached'](#event-framedetached)
- * [event: 'framenavigated'](#event-framenavigated)
- * [event: 'load'](#event-load)
- * [event: 'metrics'](#event-metrics)
- * [event: 'pageerror'](#event-pageerror)
- * [event: 'popup'](#event-popup)
- * [event: 'request'](#event-request)
- * [event: 'requestfailed'](#event-requestfailed)
- * [event: 'requestfinished'](#event-requestfinished)
- * [event: 'response'](#event-response)
- * [event: 'workercreated'](#event-workercreated)
- * [event: 'workerdestroyed'](#event-workerdestroyed)
- * [page.$(selector)](#pageselector)
- * [page.$$(selector)](#pageselector-1)
- * [page.$$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args)
- * [page.$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args-1)
- * [page.$x(expression)](#pagexexpression)
- * [page.accessibility](#pageaccessibility)
- * [page.addScriptTag(options)](#pageaddscripttagoptions)
- * [page.addStyleTag(options)](#pageaddstyletagoptions)
- * [page.authenticate(credentials)](#pageauthenticatecredentials)
- * [page.bringToFront()](#pagebringtofront)
- * [page.browser()](#pagebrowser)
- * [page.browserContext()](#pagebrowsercontext)
- * [page.click(selector[, options])](#pageclickselector-options)
- * [page.close([options])](#pagecloseoptions)
- * [page.content()](#pagecontent)
- * [page.cookies([...urls])](#pagecookiesurls)
- * [page.coverage](#pagecoverage)
- * [page.deleteCookie(...cookies)](#pagedeletecookiecookies)
- * [page.emulate(options)](#pageemulateoptions)
- * [page.emulateMediaFeatures(features)](#pageemulatemediafeaturesfeatures)
- * [page.emulateMediaType(type)](#pageemulatemediatypetype)
- * [page.emulateTimezone(timezoneId)](#pageemulatetimezonetimezoneid)
- * [page.emulateVisionDeficiency(type)](#pageemulatevisiondeficiencytype)
- * [page.evaluate(pageFunction[, ...args])](#pageevaluatepagefunction-args)
- * [page.evaluateHandle(pageFunction[, ...args])](#pageevaluatehandlepagefunction-args)
- * [page.evaluateOnNewDocument(pageFunction[, ...args])](#pageevaluateonnewdocumentpagefunction-args)
- * [page.exposeFunction(name, puppeteerFunction)](#pageexposefunctionname-puppeteerfunction)
- * [page.focus(selector)](#pagefocusselector)
- * [page.frames()](#pageframes)
- * [page.goBack([options])](#pagegobackoptions)
- * [page.goForward([options])](#pagegoforwardoptions)
- * [page.goto(url[, options])](#pagegotourl-options)
- * [page.hover(selector)](#pagehoverselector)
- * [page.isClosed()](#pageisclosed)
- * [page.isJavaScriptEnabled()](#pageisjavascriptenabled)
- * [page.keyboard](#pagekeyboard)
- * [page.mainFrame()](#pagemainframe)
- * [page.metrics()](#pagemetrics)
- * [page.mouse](#pagemouse)
- * [page.pdf([options])](#pagepdfoptions)
- * [page.queryObjects(prototypeHandle)](#pagequeryobjectsprototypehandle)
- * [page.reload([options])](#pagereloadoptions)
- * [page.screenshot([options])](#pagescreenshotoptions)
- * [page.select(selector, ...values)](#pageselectselector-values)
- * [page.setBypassCSP(enabled)](#pagesetbypasscspenabled)
- * [page.setCacheEnabled([enabled])](#pagesetcacheenabledenabled)
- * [page.setContent(html[, options])](#pagesetcontenthtml-options)
- * [page.setCookie(...cookies)](#pagesetcookiecookies)
- * [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout)
- * [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout)
- * [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
- * [page.setGeolocation(options)](#pagesetgeolocationoptions)
- * [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled)
- * [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled)
- * [page.setRequestInterception(value)](#pagesetrequestinterceptionvalue)
- * [page.setUserAgent(userAgent)](#pagesetuseragentuseragent)
- * [page.setViewport(viewport)](#pagesetviewportviewport)
- * [page.tap(selector)](#pagetapselector)
- * [page.target()](#pagetarget)
- * [page.title()](#pagetitle)
- * [page.touchscreen](#pagetouchscreen)
- * [page.tracing](#pagetracing)
- * [page.type(selector, text[, options])](#pagetypeselector-text-options)
- * [page.url()](#pageurl)
- * [page.viewport()](#pageviewport)
- * [page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])](#pagewaitforselectororfunctionortimeout-options-args)
- * [page.waitForFileChooser([options])](#pagewaitforfilechooseroptions)
- * [page.waitForFunction(pageFunction[, options[, ...args]])](#pagewaitforfunctionpagefunction-options-args)
- * [page.waitForNavigation([options])](#pagewaitfornavigationoptions)
- * [page.waitForRequest(urlOrPredicate[, options])](#pagewaitforrequesturlorpredicate-options)
- * [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options)
- * [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
- * [page.waitForXPath(xpath[, options])](#pagewaitforxpathxpath-options)
- * [page.workers()](#pageworkers)
- * [GeolocationOptions](#geolocationoptions)
- * [WaitTimeoutOptions](#waittimeoutoptions)
-- [class: WebWorker](#class-webworker)
- * [webWorker.evaluate(pageFunction[, ...args])](#webworkerevaluatepagefunction-args)
- * [webWorker.evaluateHandle(pageFunction[, ...args])](#webworkerevaluatehandlepagefunction-args)
- * [webWorker.executionContext()](#webworkerexecutioncontext)
- * [webWorker.url()](#webworkerurl)
-- [class: Accessibility](#class-accessibility)
- * [accessibility.snapshot([options])](#accessibilitysnapshotoptions)
-- [class: Keyboard](#class-keyboard)
- * [keyboard.down(key[, options])](#keyboarddownkey-options)
- * [keyboard.press(key[, options])](#keyboardpresskey-options)
- * [keyboard.sendCharacter(char)](#keyboardsendcharacterchar)
- * [keyboard.type(text[, options])](#keyboardtypetext-options)
- * [keyboard.up(key)](#keyboardupkey)
-- [class: Mouse](#class-mouse)
- * [mouse.click(x, y[, options])](#mouseclickx-y-options)
- * [mouse.down([options])](#mousedownoptions)
- * [mouse.move(x, y[, options])](#mousemovex-y-options)
- * [mouse.up([options])](#mouseupoptions)
-- [class: Touchscreen](#class-touchscreen)
- * [touchscreen.tap(x, y)](#touchscreentapx-y)
-- [class: Tracing](#class-tracing)
- * [tracing.start([options])](#tracingstartoptions)
- * [tracing.stop()](#tracingstop)
-- [class: FileChooser](#class-filechooser)
- * [fileChooser.accept(filePaths)](#filechooseracceptfilepaths)
- * [fileChooser.cancel()](#filechoosercancel)
- * [fileChooser.isMultiple()](#filechooserismultiple)
-- [class: Dialog](#class-dialog)
- * [dialog.accept([promptText])](#dialogacceptprompttext)
- * [dialog.defaultValue()](#dialogdefaultvalue)
- * [dialog.dismiss()](#dialogdismiss)
- * [dialog.message()](#dialogmessage)
- * [dialog.type()](#dialogtype)
-- [class: ConsoleMessage](#class-consolemessage)
- * [consoleMessage.args()](#consolemessageargs)
- * [consoleMessage.location()](#consolemessagelocation)
- * [consoleMessage.text()](#consolemessagetext)
- * [consoleMessage.type()](#consolemessagetype)
-- [class: Frame](#class-frame)
- * [frame.$(selector)](#frameselector)
- * [frame.$$(selector)](#frameselector-1)
- * [frame.$$eval(selector, pageFunction[, ...args])](#frameevalselector-pagefunction-args)
- * [frame.$eval(selector, pageFunction[, ...args])](#frameevalselector-pagefunction-args-1)
- * [frame.$x(expression)](#framexexpression)
- * [frame.addScriptTag(options)](#frameaddscripttagoptions)
- * [frame.addStyleTag(options)](#frameaddstyletagoptions)
- * [frame.childFrames()](#framechildframes)
- * [frame.click(selector[, options])](#frameclickselector-options)
- * [frame.content()](#framecontent)
- * [frame.evaluate(pageFunction[, ...args])](#frameevaluatepagefunction-args)
- * [frame.evaluateHandle(pageFunction[, ...args])](#frameevaluatehandlepagefunction-args)
- * [frame.executionContext()](#frameexecutioncontext)
- * [frame.focus(selector)](#framefocusselector)
- * [frame.goto(url[, options])](#framegotourl-options)
- * [frame.hover(selector)](#framehoverselector)
- * [frame.isDetached()](#frameisdetached)
- * [frame.name()](#framename)
- * [frame.parentFrame()](#frameparentframe)
- * [frame.select(selector, ...values)](#frameselectselector-values)
- * [frame.setContent(html[, options])](#framesetcontenthtml-options)
- * [frame.tap(selector)](#frametapselector)
- * [frame.title()](#frametitle)
- * [frame.type(selector, text[, options])](#frametypeselector-text-options)
- * [frame.url()](#frameurl)
- * [frame.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])](#framewaitforselectororfunctionortimeout-options-args)
- * [frame.waitForFunction(pageFunction[, options[, ...args]])](#framewaitforfunctionpagefunction-options-args)
- * [frame.waitForNavigation([options])](#framewaitfornavigationoptions)
- * [frame.waitForSelector(selector[, options])](#framewaitforselectorselector-options)
- * [frame.waitForXPath(xpath[, options])](#framewaitforxpathxpath-options)
-- [class: ExecutionContext](#class-executioncontext)
- * [executionContext.evaluate(pageFunction[, ...args])](#executioncontextevaluatepagefunction-args)
- * [executionContext.evaluateHandle(pageFunction[, ...args])](#executioncontextevaluatehandlepagefunction-args)
- * [executionContext.frame()](#executioncontextframe)
- * [executionContext.queryObjects(prototypeHandle)](#executioncontextqueryobjectsprototypehandle)
-- [class: JSHandle](#class-jshandle)
- * [jsHandle.asElement()](#jshandleaselement)
- * [jsHandle.dispose()](#jshandledispose)
- * [jsHandle.evaluate(pageFunction[, ...args])](#jshandleevaluatepagefunction-args)
- * [jsHandle.evaluateHandle(pageFunction[, ...args])](#jshandleevaluatehandlepagefunction-args)
- * [jsHandle.executionContext()](#jshandleexecutioncontext)
- * [jsHandle.getProperties()](#jshandlegetproperties)
- * [jsHandle.getProperty(propertyName)](#jshandlegetpropertypropertyname)
- * [jsHandle.jsonValue()](#jshandlejsonvalue)
-- [class: ElementHandle](#class-elementhandle)
- * [elementHandle.$(selector)](#elementhandleselector)
- * [elementHandle.$$(selector)](#elementhandleselector-1)
- * [elementHandle.$$eval(selector, pageFunction[, ...args])](#elementhandleevalselector-pagefunction-args)
- * [elementHandle.$eval(selector, pageFunction[, ...args])](#elementhandleevalselector-pagefunction-args-1)
- * [elementHandle.$x(expression)](#elementhandlexexpression)
- * [elementHandle.asElement()](#elementhandleaselement)
- * [elementHandle.boundingBox()](#elementhandleboundingbox)
- * [elementHandle.boxModel()](#elementhandleboxmodel)
- * [elementHandle.click([options])](#elementhandleclickoptions)
- * [elementHandle.contentFrame()](#elementhandlecontentframe)
- * [elementHandle.dispose()](#elementhandledispose)
- * [elementHandle.evaluate(pageFunction[, ...args])](#elementhandleevaluatepagefunction-args)
- * [elementHandle.evaluateHandle(pageFunction[, ...args])](#elementhandleevaluatehandlepagefunction-args)
- * [elementHandle.executionContext()](#elementhandleexecutioncontext)
- * [elementHandle.focus()](#elementhandlefocus)
- * [elementHandle.getProperties()](#elementhandlegetproperties)
- * [elementHandle.getProperty(propertyName)](#elementhandlegetpropertypropertyname)
- * [elementHandle.hover()](#elementhandlehover)
- * [elementHandle.isIntersectingViewport()](#elementhandleisintersectingviewport)
- * [elementHandle.jsonValue()](#elementhandlejsonvalue)
- * [elementHandle.press(key[, options])](#elementhandlepresskey-options)
- * [elementHandle.screenshot([options])](#elementhandlescreenshotoptions)
- * [elementHandle.select(...values)](#elementhandleselectvalues)
- * [elementHandle.tap()](#elementhandletap)
- * [elementHandle.toString()](#elementhandletostring)
- * [elementHandle.type(text[, options])](#elementhandletypetext-options)
- * [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths)
-- [class: HTTPRequest](#class-httprequest)
- * [httpRequest.abort([errorCode])](#httprequestaborterrorcode)
- * [httpRequest.continue([overrides])](#httprequestcontinueoverrides)
- * [httpRequest.failure()](#httprequestfailure)
- * [httpRequest.frame()](#httprequestframe)
- * [httpRequest.headers()](#httprequestheaders)
- * [httpRequest.isNavigationRequest()](#httprequestisnavigationrequest)
- * [httpRequest.method()](#httprequestmethod)
- * [httpRequest.postData()](#httprequestpostdata)
- * [httpRequest.redirectChain()](#httprequestredirectchain)
- * [httpRequest.resourceType()](#httprequestresourcetype)
- * [httpRequest.respond(response)](#httprequestrespondresponse)
- * [httpRequest.response()](#httprequestresponse)
- * [httpRequest.url()](#httprequesturl)
-- [class: HTTPResponse](#class-httpresponse)
- * [httpResponse.buffer()](#httpresponsebuffer)
- * [httpResponse.frame()](#httpresponseframe)
- * [httpResponse.fromCache()](#httpresponsefromcache)
- * [httpResponse.fromServiceWorker()](#httpresponsefromserviceworker)
- * [httpResponse.headers()](#httpresponseheaders)
- * [httpResponse.json()](#httpresponsejson)
- * [httpResponse.ok()](#httpresponseok)
- * [httpResponse.remoteAddress()](#httpresponseremoteaddress)
- * [httpResponse.request()](#httpresponserequest)
- * [httpResponse.securityDetails()](#httpresponsesecuritydetails)
- * [httpResponse.status()](#httpresponsestatus)
- * [httpResponse.statusText()](#httpresponsestatustext)
- * [httpResponse.text()](#httpresponsetext)
- * [httpResponse.url()](#httpresponseurl)
-- [class: SecurityDetails](#class-securitydetails)
- * [securityDetails.issuer()](#securitydetailsissuer)
- * [securityDetails.protocol()](#securitydetailsprotocol)
- * [securityDetails.subjectAlternativeNames()](#securitydetailssubjectalternativenames)
- * [securityDetails.subjectName()](#securitydetailssubjectname)
- * [securityDetails.validFrom()](#securitydetailsvalidfrom)
- * [securityDetails.validTo()](#securitydetailsvalidto)
-- [class: Target](#class-target)
- * [target.browser()](#targetbrowser)
- * [target.browserContext()](#targetbrowsercontext)
- * [target.createCDPSession()](#targetcreatecdpsession)
- * [target.opener()](#targetopener)
- * [target.page()](#targetpage)
- * [target.type()](#targettype)
- * [target.url()](#targeturl)
- * [target.worker()](#targetworker)
-- [class: CDPSession](#class-cdpsession)
- * [cdpSession.detach()](#cdpsessiondetach)
- * [cdpSession.send(method[, params])](#cdpsessionsendmethod-params)
-- [class: Coverage](#class-coverage)
- * [coverage.startCSSCoverage([options])](#coveragestartcsscoverageoptions)
- * [coverage.startJSCoverage([options])](#coveragestartjscoverageoptions)
- * [coverage.stopCSSCoverage()](#coveragestopcsscoverage)
- * [coverage.stopJSCoverage()](#coveragestopjscoverage)
-- [class: TimeoutError](#class-timeouterror)
-- [class: EventEmitter](#class-eventemitter)
- * [eventEmitter.addListener(event, handler)](#eventemitteraddlistenerevent-handler)
- * [eventEmitter.emit(event, [eventData])](#eventemitteremitevent-eventdata)
- * [eventEmitter.listenerCount(event)](#eventemitterlistenercountevent)
- * [eventEmitter.off(event, handler)](#eventemitteroffevent-handler)
- * [eventEmitter.on(event, handler)](#eventemitteronevent-handler)
- * [eventEmitter.once(event, handler)](#eventemitteronceevent-handler)
- * [eventEmitter.removeAllListeners([event])](#eventemitterremovealllistenersevent)
- * [eventEmitter.removeListener(event, handler)](#eventemitterremovelistenerevent-handler)
-
-
-### Overview
-
-Puppeteer is a Node library which provides a high-level API to control Chromium or Chrome over the DevTools Protocol.
-
-The Puppeteer API is hierarchical and mirrors the browser structure.
-
-> **NOTE** On the following diagram, faded entities are not currently represented in Puppeteer.
-
-![puppeteer overview](https://user-images.githubusercontent.com/81942/86137523-ab2ba080-baed-11ea-9d4b-30eda784585a.png)
-
-- [`Puppeteer`](#class-puppeteer) communicates with the browser using [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/).
-- [`Browser`](#class-browser) instance can own multiple browser contexts.
-- [`BrowserContext`](#class-browsercontext) instance defines a browsing session and can own multiple pages.
-- [`Page`](#class-page) has at least one frame: main frame. There might be other frames created by [iframe](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) or [frame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/frame) tags.
-- [`Frame`](#class-frame) has at least one execution context - the default execution context - where the frame's JavaScript is executed. A Frame might have additional execution contexts that are associated with [extensions](https://developer.chrome.com/extensions).
-- [`Worker`](#class-worker) has a single execution context and facilitates interacting with [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).
-
-(Diagram source: [link](https://docs.google.com/drawings/d/1Q_AM6KYs9kbyLZF-Lpp5mtpAWth73Cq8IKCsWYgi8MM/edit?usp=sharing))
-
-### puppeteer vs puppeteer-core
-
-Every release since v1.7.0 we publish two packages:
-- [puppeteer](https://www.npmjs.com/package/puppeteer)
-- [puppeteer-core](https://www.npmjs.com/package/puppeteer-core)
-
-`puppeteer` is a *product* for browser automation. When installed, it downloads a version of
-Chromium, which it then drives using `puppeteer-core`. Being an end-user product, `puppeteer` supports a bunch of convenient `PUPPETEER_*` env variables to tweak its behavior.
-
-`puppeteer-core` is a *library* to help drive anything that supports DevTools protocol. `puppeteer-core` doesn't download Chromium when installed. Being a library, `puppeteer-core` is fully driven
-through its programmatic interface and disregards all the `PUPPETEER_*` env variables.
-
-To sum up, the only differences between `puppeteer-core` and `puppeteer` are:
-- `puppeteer-core` doesn't automatically download Chromium when installed.
-- `puppeteer-core` ignores all `PUPPETEER_*` env variables.
-
-In most cases, you'll be fine using the `puppeteer` package.
-
-However, you should use `puppeteer-core` if:
-- you're building another end-user product or library atop of DevTools protocol. For example, one might build a PDF generator using `puppeteer-core` and write a custom `install.js` script that downloads [`headless_shell`](https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md) instead of Chromium to save disk space.
-- you're bundling Puppeteer to use in Chrome Extension / browser with the DevTools protocol where downloading an additional Chromium binary is unnecessary.
-- you're building a set of tools where `puppeteer-core` is one of the ingredients and you want to postpone `install.js` script execution until Chromium is about to be used.
-
-When using `puppeteer-core`, remember to change the *include* line:
-
-```js
-const puppeteer = require('puppeteer-core');
-```
-
-You will then need to call [`puppeteer.connect([options])`](#puppeteerconnectoptions) or [`puppeteer.launch([options])`](#puppeteerlaunchoptions) with an explicit `executablePath` option.
-
-### Environment Variables
-
-Puppeteer looks for certain [environment variables](https://en.wikipedia.org/wiki/Environment_variable) to aid its operations.
-If Puppeteer doesn't find them in the environment during the installation step, a lowercased variant of these variables will be used from the [npm config](https://docs.npmjs.com/cli/config).
-
-- `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` - defines HTTP proxy settings that are used to download and run Chromium.
-- `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` - do not download bundled Chromium during installation step.
-- `PUPPETEER_DOWNLOAD_HOST` - overwrite URL prefix that is used to download Chromium. Note: this includes protocol and might even include path prefix. Defaults to `https://storage.googleapis.com`.
-- `PUPPETEER_CHROMIUM_REVISION` - specify a certain version of Chromium you'd like Puppeteer to use. See [puppeteer.launch([options])](#puppeteerlaunchoptions) on how executable path is inferred. **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/puppeteer/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
-- `PUPPETEER_EXECUTABLE_PATH` - specify an executable path to be used in `puppeteer.launch`. See [puppeteer.launch([options])](#puppeteerlaunchoptions) on how the executable path is inferred. **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/puppeteer/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
-- `PUPPETEER_PRODUCT` - specify which browser you'd like Puppeteer to use. Must be one of `chrome` or `firefox`. This can also be used during installation to fetch the recommended browser binary. Setting `product` programmatically in [puppeteer.launch([options])](#puppeteerlaunchoptions) supersedes this environment variable. The product is exposed in [`puppeteer.product`](#puppeteerproduct)
-
-> **NOTE** PUPPETEER_* env variables are not accounted for in the [`puppeteer-core`](https://www.npmjs.com/package/puppeteer-core) package.
-
-
-### Working with Chrome Extensions
-
-Puppeteer can be used for testing Chrome Extensions.
-
-> **NOTE** Extensions in Chrome / Chromium currently only work in non-headless mode.
-
-The following is code for getting a handle to the [background page](https://developer.chrome.com/extensions/background_pages) of an extension whose source is located in `./my-extension`:
-```js
-const puppeteer = require('puppeteer');
-
-(async () => {
- const pathToExtension = require('path').join(__dirname, 'my-extension');
- const browser = await puppeteer.launch({
- headless: false,
- args: [
- `--disable-extensions-except=${pathToExtension}`,
- `--load-extension=${pathToExtension}`
- ]
- });
- const targets = await browser.targets();
- const backgroundPageTarget = targets.find(target => target.type() === 'background_page');
- const backgroundPage = await backgroundPageTarget.page();
- // Test the background page as you would any other page.
- await browser.close();
-})();
-```
-
-> **NOTE** It is not yet possible to test extension popups or content scripts.
-
-### class: Puppeteer
-
-Puppeteer module provides a method to launch a Chromium instance.
-The following is a typical example of using Puppeteer to drive automation:
-```js
-const puppeteer = require('puppeteer');
-
-(async () => {
- const browser = await puppeteer.launch();
- const page = await browser.newPage();
- await page.goto('https://www.google.com');
- // other actions...
- await browser.close();
-})();
-```
-
-#### puppeteer.connect(options)
-- `options` <[Object]>
- - `browserWSEndpoint` [string]> a [browser websocket endpoint](#browserwsendpoint) to connect to.
- - `browserURL` [string]> a browser url to connect to, in format `http://${host}:${port}`. Use interchangeably with `browserWSEndpoint` to let Puppeteer fetch it from [metadata endpoint](https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target).
- - `ignoreHTTPSErrors` <[boolean]> Whether to ignore HTTPS errors during navigation. Defaults to `false`.
- - `defaultViewport` [Object]> Sets a consistent viewport for each page. Defaults to an 800x600 viewport. `null` disables the default viewport.
- - `width` <[number]> page width in pixels.
- - `height` <[number]> page height in pixels.
- - `deviceScaleFactor` <[number]> Specify device scale factor (can be thought of as dpr). Defaults to `1`.
- - `isMobile` <[boolean]> Whether the `meta viewport` tag is taken into account. Defaults to `false`.
- - `hasTouch`<[boolean]> Specifies if viewport supports touch events. Defaults to `false`
- - `isLandscape` <[boolean]> Specifies if viewport is in landscape mode. Defaults to `false`.
- - `slowMo` <[number]> Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.
- - `transport` <[ConnectionTransport]> **Experimental** Specify a custom transport object for Puppeteer to use.
- - `product` <[string]> Possible values are: `chrome`, `firefox`. Defaults to `chrome`.
-- returns: <[Promise]<[Browser]>>
-
-This methods attaches Puppeteer to an existing browser instance.
-
-#### puppeteer.createBrowserFetcher([options])
-- `options` <[Object]>
- - `host` <[string]> A download host to be used. Defaults to `https://storage.googleapis.com`. If the `product` is `firefox`, this defaults to `https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central`.
- - `path` <[string]> A path for the downloads folder. Defaults to `/.local-chromium`, where `` is puppeteer's package root. If the `product` is `firefox`, this defaults to `/.local-firefox`.
- - `platform` <"linux"|"mac"|"win32"|"win64"> [string] for the current platform. Possible values are: `mac`, `win32`, `win64`, `linux`. Defaults to the current platform.
- - `product` <"chrome"|"firefox"> [string] for the product to run. Possible values are: `chrome`, `firefox`. Defaults to `chrome`.
-- returns: <[BrowserFetcher]>
-
-#### puppeteer.defaultArgs([options])
-- `options` <[Object]> Set of configurable options to set on the browser. Can have the following fields:
- - `headless` <[boolean]> Whether to run browser in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). Defaults to `true` unless the `devtools` option is `true`.
- - `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/).
- - `userDataDir` <[string]> Path to a [User Data Directory](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md).
- - `devtools` <[boolean]> Whether to auto-open a DevTools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
-- returns: <[Array]<[string]>>
-
-The default flags that Chromium will be launched with.
-
-#### puppeteer.devices
-- returns: <[Object]>
-
-Returns a list of devices to be used with [`page.emulate(options)`](#pageemulateoptions). Actual list of
-devices can be found in [src/common/DeviceDescriptors.js](https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts).
-
-```js
-const puppeteer = require('puppeteer');
-const iPhone = puppeteer.devices['iPhone 6'];
-
-(async () => {
- const browser = await puppeteer.launch();
- const page = await browser.newPage();
- await page.emulate(iPhone);
- await page.goto('https://www.google.com');
- // other actions...
- await browser.close();
-})();
-```
-
-#### puppeteer.errors
-- returns: <[Object]>
- - `TimeoutError` <[function]> A class of [TimeoutError].
-
-Puppeteer methods might throw errors if they are unable to fulfill a request. For example, [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
-might fail if the selector doesn't match any nodes during the given timeframe.
-
-For certain types of errors Puppeteer uses specific error classes.
-These classes are available via [`puppeteer.errors`](#puppeteererrors)
-
-An example of handling a timeout error:
-```js
-try {
- await page.waitForSelector('.foo');
-} catch (e) {
- if (e instanceof puppeteer.errors.TimeoutError) {
- // Do something if this is a timeout.
- }
-}
-```
-
-> **NOTE** The old way (Puppeteer versions <= v1.14.0) errors can be obtained with `require('puppeteer/Errors')`.
-
-#### puppeteer.executablePath()
-- returns: <[string]> A path where Puppeteer expects to find the bundled browser. The browser binary might not be there if the download was skipped with [`PUPPETEER_SKIP_DOWNLOAD`](#environment-variables).
-
-> **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH` and `PUPPETEER_CHROMIUM_REVISION` env variables. See [Environment Variables](#environment-variables) for details.
-
-
-#### puppeteer.launch([options])
-- `options` <[Object]> Set of configurable options to set on the browser. Can have the following fields:
- - `product` <[string]> Which browser to launch. At this time, this is either `chrome` or `firefox`. See also `PUPPETEER_PRODUCT`.
- - `ignoreHTTPSErrors` <[boolean]> Whether to ignore HTTPS errors during navigation. Defaults to `false`.
- - `headless` <[boolean]> Whether to run browser in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). Defaults to `true` unless the `devtools` option is `true`.
- - `executablePath` <[string]> Path to a browser executable to run instead of the bundled Chromium. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). **BEWARE**: Puppeteer is only [guaranteed to work](https://github.com/puppeteer/puppeteer/#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy) with the bundled Chromium, use at your own risk.
- - `slowMo` <[number]> Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.
- - `defaultViewport` [Object]> Sets a consistent viewport for each page. Defaults to an 800x600 viewport. `null` disables the default viewport.
- - `width` <[number]> page width in pixels.
- - `height` <[number]> page height in pixels.
- - `deviceScaleFactor` <[number]> Specify device scale factor (can be thought of as dpr). Defaults to `1`.
- - `isMobile` <[boolean]> Whether the `meta viewport` tag is taken into account. Defaults to `false`.
- - `hasTouch`<[boolean]> Specifies if viewport supports touch events. Defaults to `false`
- - `isLandscape` <[boolean]> Specifies if viewport is in landscape mode. Defaults to `false`.
- - `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/), and here is the list of [Firefox flags](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options).
- - `ignoreDefaultArgs` <[boolean]|[Array]<[string]>> If `true`, then do not use [`puppeteer.defaultArgs()`](#puppeteerdefaultargsoptions). If an array is given, then filter out the given default arguments. Dangerous option; use with care. Defaults to `false`.
- - `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
- - `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
- - `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
- - `timeout` <[number]> Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
- - `dumpio` <[boolean]> Whether to pipe the browser process stdout and stderr into `process.stdout` and `process.stderr`. Defaults to `false`.
- - `userDataDir` <[string]> Path to a [User Data Directory](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md).
- - `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
- - `devtools` <[boolean]> Whether to auto-open a DevTools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
- - `pipe` <[boolean]> Connects to the browser over a pipe instead of a WebSocket. Defaults to `false`.
- - `extraPrefsFirefox` <[Object]> Additional [preferences](https://developer.mozilla.org/en-US/docs/Mozilla/Preferences/Preference_reference) that can be passed to Firefox (see `PUPPETEER_PRODUCT`)
-- returns: <[Promise]<[Browser]>> Promise which resolves to browser instance.
-
-
-You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
-```js
-const browser = await puppeteer.launch({
- ignoreDefaultArgs: ['--mute-audio']
-});
-```
-
-> **NOTE** Puppeteer can also be used to control the Chrome browser, but it works best with the version of Chromium it is bundled with. There is no guarantee it will work with any other version. Use `executablePath` option with extreme caution.
->
-> If Google Chrome (rather than Chromium) is preferred, a [Chrome Canary](https://www.google.com/chrome/browser/canary.html) or [Dev Channel](https://www.chromium.org/getting-involved/dev-channel) build is suggested.
->
-> In [puppeteer.launch([options])](#puppeteerlaunchoptions) above, any mention of Chromium also applies to Chrome.
->
-> 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/+/lkgr/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.
-
-#### puppeteer.product
-- returns: <[string]> returns the name of the browser that is under automation (`"chrome"` or `"firefox"`)
-
-The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product` option in [puppeteer.launch([options])](#puppeteerlaunchoptions) and defaults to `chrome`. Firefox support is experimental.
-
-
-### class: BrowserFetcher
-
-BrowserFetcher can download and manage different versions of Chromium and Firefox.
-
-BrowserFetcher operates on revision strings that specify a precise version of Chromium, e.g. `"533271"`. Revision strings can be obtained from [omahaproxy.appspot.com](http://omahaproxy.appspot.com/).
-
-In the Firefox case, BrowserFetcher downloads Firefox Nightly and operates on version numbers such as `"75"`.
-
-An example of using BrowserFetcher to download a specific version of Chromium and running
-Puppeteer against it:
-
-```js
-const browserFetcher = puppeteer.createBrowserFetcher();
-const revisionInfo = await browserFetcher.download('533271');
-const browser = await puppeteer.launch({executablePath: revisionInfo.executablePath})
-```
-
-> **NOTE** BrowserFetcher is not designed to work concurrently with other
-> instances of BrowserFetcher that share the same downloads directory.
-
-#### browserFetcher.canDownload(revision)
-- `revision` <[string]> a revision to check availability.
-- returns: <[Promise]<[boolean]>> returns `true` if the revision could be downloaded from the host.
-
-The method initiates a HEAD request to check if the revision is available.
-
-#### browserFetcher.download(revision[, progressCallback])
-- `revision` <[string]> a revision to download.
-- `progressCallback` <[function]([number], [number])> A function that will be called with two arguments:
- - `downloadedBytes` <[number]> how many bytes have been downloaded
- - `totalBytes` <[number]> how large is the total download.
-- returns: <[Promise]<[Object]>> Resolves with revision information when the revision is downloaded and extracted
- - `revision` <[string]> the revision the info was created from
- - `folderPath` <[string]> path to the extracted revision folder
- - `executablePath` <[string]> path to the revision executable
- - `url` <[string]> URL this revision can be downloaded from
- - `local` <[boolean]> whether the revision is locally available on disk
-
-The method initiates a GET request to download the revision from the host.
-
-#### browserFetcher.host()
-- returns: <[string]> The download host being used.
-
-#### browserFetcher.localRevisions()
-- returns: <[Promise]<[Array]<[string]>>> A list of all revisions (for the current `product`) available locally on disk.
-
-#### browserFetcher.platform()
-- returns: <[string]> One of `mac`, `linux`, `win32` or `win64`.
-
-#### browserFetcher.product()
-- returns: <[string]> One of `chrome` or `firefox`.
-
-#### browserFetcher.remove(revision)
-- `revision` <[string]> a revision to remove for the current `product`. The method will throw if the revision has not been downloaded.
-- returns: <[Promise]> Resolves when the revision has been removed.
-
-#### browserFetcher.revisionInfo(revision)
-- `revision` <[string]> a revision to get info for.
-- returns: <[Object]>
- - `revision` <[string]> the revision the info was created from
- - `folderPath` <[string]> path to the extracted revision folder
- - `executablePath` <[string]> path to the revision executable
- - `url` <[string]> URL this revision can be downloaded from
- - `local` <[boolean]> whether the revision is locally available on disk
- - `product` <[string]> one of `chrome` or `firefox`
-
-> **NOTE** Many BrowserFetcher methods, like `remove` and `revisionInfo`
-> are affected by the choice of `product`. See [puppeteer.createBrowserFetcher([options])](#puppeteercreatebrowserfetcheroptions).
-
-### class: Browser
-
-* extends: [EventEmitter](#class-eventemitter)
-
-A Browser is created when Puppeteer connects to a Chromium instance, either through [`puppeteer.launch`](#puppeteerlaunchoptions) or [`puppeteer.connect`](#puppeteerconnectoptions).
-
-An example of using a [Browser] to create a [Page]:
-```js
-const puppeteer = require('puppeteer');
-
-(async () => {
- const browser = await puppeteer.launch();
- const page = await browser.newPage();
- await page.goto('https://example.com');
- await browser.close();
-})();
-```
-
-An example of disconnecting from and reconnecting to a [Browser]:
-```js
-const puppeteer = require('puppeteer');
-
-(async () => {
- const browser = await puppeteer.launch();
- // Store the endpoint to be able to reconnect to Chromium
- const browserWSEndpoint = browser.wsEndpoint();
- // Disconnect puppeteer from Chromium
- browser.disconnect();
-
- // Use the endpoint to reestablish a connection
- const browser2 = await puppeteer.connect({browserWSEndpoint});
- // Close Chromium
- await browser2.close();
-})();
-```
-#### event: 'disconnected'
-Emitted when Puppeteer gets disconnected from the Chromium instance. This might happen because of one of the following:
-- Chromium is closed or crashed
-- The [`browser.disconnect`](#browserdisconnect) method was called
-
-#### event: 'targetchanged'
-- <[Target]>
-
-Emitted when the url of a target changes.
-
-> **NOTE** This includes target changes in incognito browser contexts.
-
-
-#### event: 'targetcreated'
-- <[Target]>
-
-Emitted when a target is created, for example when a new page is opened by [`window.open`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) or [`browser.newPage`](#browsernewpage).
-
-> **NOTE** This includes target creations in incognito browser contexts.
-
-#### event: 'targetdestroyed'
-- <[Target]>
-
-Emitted when a target is destroyed, for example when a page is closed.
-
-> **NOTE** This includes target destructions in incognito browser contexts.
-
-#### browser.browserContexts()
-- returns: <[Array]<[BrowserContext]>>
-
-Returns an array of all open browser contexts. In a newly created browser, this will return
-a single instance of [BrowserContext].
-
-#### browser.close()
-- returns: <[Promise]>
-
-Closes Chromium and all of its pages (if any were opened). The [Browser] object itself is considered to be disposed and cannot be used anymore.
-
-#### browser.createIncognitoBrowserContext()
-- returns: <[Promise]<[BrowserContext]>>
-
-Creates a new incognito browser context. This won't share cookies/cache with other browser contexts.
-
-```js
-(async () => {
- const browser = await puppeteer.launch();
- // Create a new incognito browser context.
- const context = await browser.createIncognitoBrowserContext();
- // Create a new page in a pristine context.
- const page = await context.newPage();
- // Do stuff
- await page.goto('https://example.com');
-})();
-```
-
-#### browser.defaultBrowserContext()
-- returns: <[BrowserContext]>
-
-Returns the default browser context. The default browser context can not be closed.
-
-#### browser.disconnect()
-
-Disconnects Puppeteer from the browser, but leaves the Chromium process running. After calling `disconnect`, the [Browser] object is considered disposed and cannot be used anymore.
-
-#### browser.isConnected()
-
-- returns: <[boolean]>
-
-Indicates that the browser is connected.
-
-#### browser.newPage()
-- returns: <[Promise]<[Page]>>
-
-Promise which resolves to a new [Page] object. The [Page] is created in a default browser context.
-
-#### browser.pages()
-- returns: <[Promise]<[Array]<[Page]>>> Promise which resolves to an array of all open pages. Non visible pages, such as `"background_page"`, will not be listed here. You can find them using [target.page()](#targetpage).
-
-An array of all pages inside the Browser. In case of multiple browser contexts,
-the method will return an array with all the pages in all browser contexts.
-
-#### browser.process()
-- returns: [ChildProcess]> Spawned browser process. Returns `null` if the browser instance was created with [`puppeteer.connect`](#puppeteerconnectoptions) method.
-
-#### browser.target()
-- returns: <[Target]>
-
-A target associated with the browser.
-
-#### browser.targets()
-- returns: <[Array]<[Target]>>
-
-An array of all active targets inside the Browser. In case of multiple browser contexts,
-the method will return an array with all the targets in all browser contexts.
-
-#### browser.userAgent()
-- returns: <[Promise]<[string]>> Promise which resolves to the browser's original user agent.
-
-> **NOTE** Pages can override browser user agent with [page.setUserAgent](#pagesetuseragentuseragent)
-
-#### browser.version()
-- returns: <[Promise]<[string]>> For headless Chromium, this is similar to `HeadlessChrome/61.0.3153.0`. For non-headless, this is similar to `Chrome/61.0.3153.0`.
-
-> **NOTE** the format of browser.version() might change with future releases of Chromium.
-
-#### browser.waitForTarget(predicate[, options])
-- `predicate` <[function]\([Target]\):[boolean]> A function to be run for every target
-- `options` <[Object]>
- - `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
-- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
-
-This searches for a target in all browser contexts.
-
-An example of finding a target for a page opened via `window.open`:
-```js
-await page.evaluate(() => window.open('https://www.example.com/'));
-const newWindowTarget = await browser.waitForTarget(target => target.url() === 'https://www.example.com/');
-```
-
-#### browser.wsEndpoint()
-- returns: <[string]> Browser websocket url.
-
-Browser websocket endpoint which can be used as an argument to
-[puppeteer.connect](#puppeteerconnectoptions). The format is `ws://${host}:${port}/devtools/browser/`
-
-You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/version`. Learn more about the [devtools protocol](https://chromedevtools.github.io/devtools-protocol) and the [browser endpoint](https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target).
-
-### class: BrowserContext
-
-* extends: [EventEmitter](#class-eventemitter)
-
-BrowserContexts provide a way to operate multiple independent browser sessions. When a browser is launched, it has
-a single BrowserContext used by default. The method `browser.newPage()` creates a page in the default browser context.
-
-If a page opens another page, e.g. with a `window.open` call, the popup will belong to the parent page's browser
-context.
-
-Puppeteer allows creation of "incognito" browser contexts with `browser.createIncognitoBrowserContext()` method.
-"Incognito" browser contexts don't write any browsing data to disk.
-
-```js
-// Create a new incognito browser context
-const context = await browser.createIncognitoBrowserContext();
-// Create a new page inside context.
-const page = await context.newPage();
-// ... do stuff with page ...
-await page.goto('https://example.com');
-// Dispose context once it's no longer needed.
-await context.close();
-```
-
-#### event: 'targetchanged'
-- <[Target]>
-
-Emitted when the url of a target inside the browser context changes.
-
-#### event: 'targetcreated'
-- <[Target]>
-
-Emitted when a new target is created inside the browser context, for example when a new page is opened by [`window.open`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) or [`browserContext.newPage`](#browsercontextnewpage).
-
-#### event: 'targetdestroyed'
-- <[Target]>
-
-Emitted when a target inside the browser context is destroyed, for example when a page is closed.
-
-#### browserContext.browser()
-- returns: <[Browser]>
-
-The browser this browser context belongs to.
-
-#### browserContext.clearPermissionOverrides()
-- returns: <[Promise]>
-
-Clears all permission overrides for the browser context.
-
-```js
-const context = browser.defaultBrowserContext();
-context.overridePermissions('https://example.com', ['clipboard-read']);
-// do stuff ..
-context.clearPermissionOverrides();
-```
-
-#### browserContext.close()
-- returns: <[Promise]>
-
-Closes the browser context. All the targets that belong to the browser context
-will be closed.
-
-> **NOTE** only incognito browser contexts can be closed.
-
-#### browserContext.isIncognito()
-- returns: <[boolean]>
-
-Returns whether BrowserContext is incognito.
-The default browser context is the only non-incognito browser context.
-
-> **NOTE** the default browser context cannot be closed.
-
-#### browserContext.newPage()
-- returns: <[Promise]<[Page]>>
-
-Creates a new page in the browser context.
-
-
-#### browserContext.overridePermissions(origin, permissions)
-- `origin` <[string]> The [origin] to grant permissions to, e.g. "https://example.com".
-- `permissions` <[Array]<[string]>> An array of permissions to grant. All permissions that are not listed here will be automatically denied. Permissions can be one of the following values:
- - `'geolocation'`
- - `'midi'`
- - `'midi-sysex'` (system-exclusive midi)
- - `'notifications'`
- - `'push'`
- - `'camera'`
- - `'microphone'`
- - `'background-sync'`
- - `'ambient-light-sensor'`
- - `'accelerometer'`
- - `'gyroscope'`
- - `'magnetometer'`
- - `'accessibility-events'`
- - `'clipboard-read'`
- - `'clipboard-write'`
- - `'payment-handler'`
-- returns: <[Promise]>
-
-
-```js
-const context = browser.defaultBrowserContext();
-await context.overridePermissions('https://html5demos.com', ['geolocation']);
-```
-
-
-#### browserContext.pages()
-- returns: <[Promise]<[Array]<[Page]>>> Promise which resolves to an array of all open pages. Non visible pages, such as `"background_page"`, will not be listed here. You can find them using [target.page()](#targetpage).
-
-An array of all pages inside the browser context.
-
-#### browserContext.targets()
-- returns: <[Array]<[Target]>>
-
-An array of all active targets inside the browser context.
-
-#### browserContext.waitForTarget(predicate[, options])
-- `predicate` <[function]\([Target]\):[boolean]> A function to be run for every target
-- `options` <[Object]>
- - `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
-- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
-
-This searches for a target in this specific browser context.
-
-An example of finding a target for a page opened via `window.open`:
-```js
-await page.evaluate(() => window.open('https://www.example.com/'));
-const newWindowTarget = await browserContext.waitForTarget(target => target.url() === 'https://www.example.com/');
-```
-
-### class: Page
-
-* extends: [EventEmitter](#class-eventemitter)
-
-Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One [Browser] instance might have multiple [Page] instances.
-
-This example creates a page, navigates it to a URL, and then saves a screenshot:
-```js
-const puppeteer = require('puppeteer');
-
-(async () => {
- const browser = await puppeteer.launch();
- const page = await browser.newPage();
- await page.goto('https://example.com');
- await page.screenshot({path: 'screenshot.png'});
- await browser.close();
-})();
-```
-
-The Page class emits various events (described below) which can be handled using
-any of the [`EventEmitter`](#class-eventemitter) methods, such as `on`, `once`
-or `off`.
-
-This example logs a message for a single page `load` event:
-```js
-page.once('load', () => console.log('Page loaded!'));
-```
-
-To unsubscribe from events use the `off` method:
-
-```js
-function logRequest(interceptedRequest) {
- console.log('A request was made:', interceptedRequest.url());
-}
-page.on('request', logRequest);
-// Sometime later...
-page.off('request', logRequest);
-```
-
-#### event: 'close'
-
-Emitted when the page closes.
-
-#### event: 'console'
-- <[ConsoleMessage]>
-
-Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also emitted if the page throws an error or a warning.
-
-The arguments passed into `console.log` appear as arguments on the event handler.
-
-An example of handling `console` event:
-```js
-page.on('console', msg => {
- for (let i = 0; i < msg.args().length; ++i)
- console.log(`${i}: ${msg.args()[i]}`);
-});
-page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
-```
-
-#### event: 'dialog'
-- <[Dialog]>
-
-Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Puppeteer can respond to the dialog via [Dialog]'s [accept](#dialogacceptprompttext) or [dismiss](#dialogdismiss) methods.
-
-#### event: 'domcontentloaded'
-
-Emitted when the JavaScript [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event is dispatched.
-
-#### event: 'error'
-- <[Error]>
-
-Emitted when the page crashes.
-
-> **NOTE** `error` event has a special meaning in Node, see [error events](https://nodejs.org/api/events.html#events_error_events) for details.
-
-#### event: 'frameattached'
-- <[Frame]>
-
-Emitted when a frame is attached.
-
-#### event: 'framedetached'
-- <[Frame]>
-
-Emitted when a frame is detached.
-
-#### event: 'framenavigated'
-- <[Frame]>
-
-Emitted when a frame is navigated to a new url.
-
-#### event: 'load'
-
-Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched.
-
-#### event: 'metrics'
-- <[Object]>
- - `title` <[string]> The title passed to `console.timeStamp`.
- - `metrics` <[Object]> Object containing metrics as key/value pairs. The values
- of metrics are of <[number]> type.
-
-Emitted when the JavaScript code makes a call to `console.timeStamp`. For the list
-of metrics see `page.metrics`.
-
-#### event: 'pageerror'
-- <[Error]> The exception message
-
-Emitted when an uncaught exception happens within the page.
-
-#### event: 'popup'
-- <[Page]> Page corresponding to "popup" window
-
-Emitted when the page opens a new tab or window.
-
-```js
-const [popup] = await Promise.all([
- new Promise(resolve => page.once('popup', resolve)),
- page.click('a[target=_blank]'),
-]);
-```
-
-```js
-const [popup] = await Promise.all([
- new Promise(resolve => page.once('popup', resolve)),
- page.evaluate(() => window.open('https://example.com')),
-]);
-```
-
-#### event: 'request'
-- <[HTTPRequest]>
-
-Emitted when a page issues a request. The [request] object is read-only.
-In order to intercept and mutate requests, see `page.setRequestInterception`.
-
-#### event: 'requestfailed'
-- <[HTTPRequest]>
-
-Emitted when a request fails, for example by timing out.
-
-> **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will complete with [`'requestfinished'`](#event-requestfinished) event and not with [`'requestfailed'`](#event-requestfailed).
-
-#### event: 'requestfinished'
-- <[HTTPRequest]>
-
-Emitted when a request finishes successfully.
-
-#### event: 'response'
-- <[HTTPResponse]>
-
-Emitted when a [response] is received.
-
-#### event: 'workercreated'
-- <[Worker]>
-
-Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned by the page.
-
-#### event: 'workerdestroyed'
-- <[Worker]>
-
-Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is terminated.
-
-#### page.$(selector)
-- `selector` <[string]> A [selector] to query page for
-- returns: <[Promise][ElementHandle]>>
-
-The method runs `document.querySelector` within the page. If no element matches the selector, the return value resolves to `null`.
-
-Shortcut for [page.mainFrame().$(selector)](#frameselector).
-
-#### page.$$(selector)
-- `selector` <[string]> A [selector] to query page for
-- returns: <[Promise]<[Array]<[ElementHandle]>>>
-
-The method runs `document.querySelectorAll` within the page. If no elements match the selector, the return value resolves to `[]`.
-
-Shortcut for [page.mainFrame().$$(selector)](#frameselector-1).
-
-#### page.$$eval(selector, pageFunction[, ...args])
-- `selector` <[string]> A [selector] to query page for
-- `pageFunction` <[function]\([Array]<[Element]>\)> Function to be evaluated in browser context
-- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
-- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
-
-This method runs `Array.from(document.querySelectorAll(selector))` within the page and passes it as the first argument to `pageFunction`.
-
-If `pageFunction` returns a [Promise], then `page.$$eval` would wait for the promise to resolve and return its value.
-
-Examples:
-```js
-const divCount = await page.$$eval('div', divs => divs.length);
-```
-
-```js
-const options = await page.$$eval('div > span.options', options => options.map(option => option.textContent));
-```
-
-#### page.$eval(selector, pageFunction[, ...args])
-- `selector` <[string]> A [selector] to query page for
-- `pageFunction` <[function]\([Element]\)> Function to be evaluated in browser context
-- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
-- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
-
-This method runs `document.querySelector` within the page and passes it as the first argument to `pageFunction`. If there's no element matching `selector`, the method throws an error.
-
-If `pageFunction` returns a [Promise], then `page.$eval` would wait for the promise to resolve and return its value.
-
-Examples:
-```js
-const searchValue = await page.$eval('#search', el => el.value);
-const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
-const html = await page.$eval('.main-container', e => e.outerHTML);
-```
-
-Shortcut for [page.mainFrame().$eval(selector, pageFunction)](#frameevalselector-pagefunction-args).
-
-#### page.$x(expression)
-- `expression` <[string]> Expression to [evaluate](https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate).
-- returns: <[Promise]<[Array]<[ElementHandle]>>>
-
-The method evaluates the XPath expression.
-
-Shortcut for [page.mainFrame().$x(expression)](#framexexpression)
-
-#### page.accessibility
-- returns: <[Accessibility]>
-
-#### page.addScriptTag(options)
-- `options` <[Object]>
- - `url` <[string]> URL of a script to be added.
- - `path` <[string]> Path to the JavaScript file to be injected into frame. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
- - `content` <[string]> Raw JavaScript content to be injected into frame.
- - `type` <[string]> Script type. Use 'module' in order to load a Javascript ES6 module. See [script](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) for more details.
-- returns: <[Promise]<[ElementHandle]>> which resolves to the added tag when the script's onload fires or when the script content was injected into frame.
-
-Adds a `
+
+
+
+
+
+
+