From 907290b2fdc0f774ce636429ca74e14de5754c2c Mon Sep 17 00:00:00 2001 From: Vitalii Tverdokhlib Date: Sat, 11 Sep 2021 13:07:29 +0300 Subject: [PATCH 01/31] chore(docs): update alpine version (#5099) --- docs/troubleshooting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 87350bf62d9b3..95b6834aae7a0 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -332,7 +332,7 @@ The [newest Chromium package](https://pkgs.alpinelinux.org/package/edge/communit Example Dockerfile: ```Dockerfile -FROM alpine:edge +FROM alpine # Installs latest Chromium (89) package. RUN apk add --no-cache \ From fbd36a9705f64613255ef4dff223e4ddc8576253 Mon Sep 17 00:00:00 2001 From: Ondra Urban <23726914+mnmkng@users.noreply.github.com> Date: Sat, 11 Sep 2021 12:31:59 +0200 Subject: [PATCH 02/31] docs(examples): add Apify SDK to scraping section (#5338) --- examples/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/README.md b/examples/README.md index c23d9df64b5af..ed68e3fe12be5 100644 --- a/examples/README.md +++ b/examples/README.md @@ -23,6 +23,7 @@ More complex and use case driven examples can be found at [github.com/GoogleChro - [puppeteer-examples](https://github.com/checkly/puppeteer-examples) - Puppeteer Headless Chrome examples for real life use cases such as getting useful info from the web pages or common login scenarios. - [browserless](https://github.com/joelgriffith/browserless) - Headless Chrome as a service letting you execute Puppeteer scripts remotely. Provides a docker image with configuration for concurrency, launch arguments and more. - [Puppeteer Sandbox](https://puppeteersandbox.com) - Puppeteer sandbox environment as a service. Runs Puppeteer scripts and allows saving and embedding them in external sites and markdown files. +- [Apify SDK](https://github.com/apifytech/apify-js) - The scalable web crawling and scraping library for JavaScript. Automatically manages a pool of Puppeteer browsers and provides easy error handling, task management, proxy rotation and more. ## Testing From 8d1a697fc3ef10300d886beb961a45ea1451c427 Mon Sep 17 00:00:00 2001 From: Talendran <69163150+Talendran@users.noreply.github.com> Date: Sat, 11 Sep 2021 07:02:40 -0400 Subject: [PATCH 03/31] docs(examples): change searching for searchbox to .devsite class (#6301) --- examples/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/search.js b/examples/search.js index 828d15543815a..b5def52f733e7 100644 --- a/examples/search.js +++ b/examples/search.js @@ -30,7 +30,7 @@ const puppeteer = require('puppeteer'); await page.goto('https://developers.google.com/web/'); // Type into search box. - await page.type('.devsite-searchbox input', 'Headless Chrome'); + await page.type('.devsite-search-field', 'Headless Chrome'); // Wait for suggest overlay to appear and click "show all results". const allResultsSelector = '.devsite-suggest-all-results'; From b5020dc04121b265c77662237dfb177d6de06053 Mon Sep 17 00:00:00 2001 From: Michael Rienstra Date: Sat, 11 Sep 2021 10:50:35 -0700 Subject: [PATCH 04/31] feat: add more Android models to DeviceDescriptors (#7210) Adds device descriptions for: * Galaxy S8 * Galaxy S9+ * Galaxy Tab S4 * Pixel 3 * Pixel 4 These devices are regarded as worthy of targeting by [BrowserStack](https://www.browserstack.com/test-on-the-right-mobile-devices). Sources (both have identical data for these 5 devices): 1. https://github.com/aerokube/moon-deploy/blob/master/moon-local.yaml#L199 2. https://www.danhendricks.com/2018/04/adding-iphone-galaxy-chrome-mobile-emulated-devices/#heading_device_data --- src/common/DeviceDescriptors.ts | 130 ++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/src/common/DeviceDescriptors.ts b/src/common/DeviceDescriptors.ts index 783a947ae3592..7b5b54c96837d 100644 --- a/src/common/DeviceDescriptors.ts +++ b/src/common/DeviceDescriptors.ts @@ -187,6 +187,84 @@ const devices: Device[] = [ isLandscape: true, }, }, + { + name: 'Galaxy S8', + userAgent: + 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36', + viewport: { + width: 360, + height: 740, + deviceScaleFactor: 3, + isMobile: true, + hasTouch: true, + isLandscape: false, + }, + }, + { + name: 'Galaxy S8 landscape', + userAgent: + 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36', + viewport: { + width: 740, + height: 360, + deviceScaleFactor: 3, + isMobile: true, + hasTouch: true, + isLandscape: true, + }, + }, + { + name: 'Galaxy S9+', + userAgent: + 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36', + viewport: { + width: 320, + height: 658, + deviceScaleFactor: 4.5, + isMobile: true, + hasTouch: true, + isLandscape: false, + }, + }, + { + name: 'Galaxy S9+ landscape', + userAgent: + 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36', + viewport: { + width: 658, + height: 320, + deviceScaleFactor: 4.5, + isMobile: true, + hasTouch: true, + isLandscape: true, + }, + }, + { + name: 'Galaxy Tab S4', + userAgent: + 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36', + viewport: { + width: 712, + height: 1138, + deviceScaleFactor: 2.25, + isMobile: true, + hasTouch: true, + isLandscape: false, + }, + }, + { + name: 'Galaxy Tab S4 landscape', + userAgent: + 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36', + viewport: { + width: 1138, + height: 712, + deviceScaleFactor: 2.25, + isMobile: true, + hasTouch: true, + isLandscape: true, + }, + }, { name: 'iPad', userAgent: @@ -1032,6 +1110,58 @@ const devices: Device[] = [ isLandscape: true, }, }, + { + name: 'Pixel 3', + userAgent: + 'Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36', + viewport: { + width: 393, + height: 786, + deviceScaleFactor: 2.75, + isMobile: true, + hasTouch: true, + isLandscape: false, + }, + }, + { + name: 'Pixel 3 landscape', + userAgent: + 'Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36', + viewport: { + width: 786, + height: 393, + deviceScaleFactor: 2.75, + isMobile: true, + hasTouch: true, + isLandscape: true, + }, + }, + { + name: 'Pixel 4', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36', + viewport: { + width: 353, + height: 745, + deviceScaleFactor: 3, + isMobile: true, + hasTouch: true, + isLandscape: false, + }, + }, + { + name: 'Pixel 4 landscape', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36', + viewport: { + width: 745, + height: 353, + deviceScaleFactor: 3, + isMobile: true, + hasTouch: true, + isLandscape: true, + }, + }, ]; /** * @public From 3c6029c702291ca7ef637b66e78d72e03156fe58 Mon Sep 17 00:00:00 2001 From: Tom Jenkinson Date: Sat, 11 Sep 2021 21:28:12 +0100 Subject: [PATCH 05/31] feat(api): implement `Page.waitForNetworkIdle()` (#5140) which will wait for there to be no network requests in progress during the `idleTime` before resolving. --- docs/api.md | 12 ++++++ src/common/NetworkManager.ts | 6 +++ src/common/Page.ts | 73 ++++++++++++++++++++++++++++++++++++ test/page.spec.ts | 73 ++++++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) diff --git a/docs/api.md b/docs/api.md index ab1c2c6ec0d1e..6d73a1c2457be 100644 --- a/docs/api.md +++ b/docs/api.md @@ -197,6 +197,7 @@ * [page.waitForFileChooser([options])](#pagewaitforfilechooseroptions) * [page.waitForFunction(pageFunction[, options[, ...args]])](#pagewaitforfunctionpagefunction-options-args) * [page.waitForNavigation([options])](#pagewaitfornavigationoptions) + * [page.waitForNetworkIdle([options])](#pagewaitfornetworkidleoptions) * [page.waitForRequest(urlOrPredicate[, options])](#pagewaitforrequesturlorpredicate-options) * [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options) * [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options) @@ -2846,6 +2847,17 @@ const [response] = await Promise.all([ Shortcut for [page.mainFrame().waitForNavigation(options)](#framewaitfornavigationoptions). +#### page.waitForNetworkIdle([options]) +- `options` <[Object]> Optional waiting parameters + - `timeout` <[number]> Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method. + - `idleTime` <[number]> How long to wait for no network requests in milliseconds, defaults to 500 milliseconds. +- returns: <[Promise]> Promise which resolves when network is idle. + +```js +page.evaluate(() => fetch('some-url')); +page.waitForNetworkIdle(); // The promise resolves after fetch above finishes +``` + #### page.waitForRequest(urlOrPredicate[, options]) - `urlOrPredicate` <[string]|[Function]> A URL or predicate to wait for. diff --git a/src/common/NetworkManager.ts b/src/common/NetworkManager.ts index dda138e693fd9..73ae84a9d512e 100644 --- a/src/common/NetworkManager.ts +++ b/src/common/NetworkManager.ts @@ -188,6 +188,12 @@ export class NetworkManager extends EventEmitter { return Object.assign({}, this._extraHTTPHeaders); } + numRequestsInProgress(): number { + return [...this._requestIdToRequest].filter(([, request]) => { + return !request.response(); + }).length; + } + async setOfflineMode(value: boolean): Promise { this._emulatedNetworkConditions.offline = value; await this._updateNetworkConditions(); diff --git a/src/common/Page.ts b/src/common/Page.ts index c5caaaf57bacf..b2aa354d9eb30 100644 --- a/src/common/Page.ts +++ b/src/common/Page.ts @@ -1894,6 +1894,79 @@ export class Page extends EventEmitter { ); } + /** + * @param options - Optional waiting parameters + * @returns Promise which resolves when network is idle + */ + async waitForNetworkIdle( + options: { idleTime?: number; timeout?: number } = {} + ): Promise { + const { idleTime = 500, timeout = this._timeoutSettings.timeout() } = + options; + + const networkManager = this._frameManager.networkManager(); + + let idleResolveCallback; + const idlePromise = new Promise((resolve) => { + idleResolveCallback = resolve; + }); + + let abortRejectCallback; + const abortPromise = new Promise((_, reject) => { + abortRejectCallback = reject; + }); + + let idleTimer; + const onIdle = () => idleResolveCallback(); + + const cleanup = () => { + idleTimer && clearTimeout(idleTimer); + abortRejectCallback(new Error('abort')); + }; + + const evaluate = () => { + idleTimer && clearTimeout(idleTimer); + if (networkManager.numRequestsInProgress() === 0) + idleTimer = setTimeout(onIdle, idleTime); + }; + + evaluate(); + + const eventHandler = () => { + evaluate(); + return false; + }; + + const listenToEvent = (event) => + helper.waitForEvent( + networkManager, + event, + eventHandler, + timeout, + abortPromise + ); + + const eventPromises = [ + listenToEvent(NetworkManagerEmittedEvents.Request), + listenToEvent(NetworkManagerEmittedEvents.Response), + ]; + + await Promise.race([ + idlePromise, + ...eventPromises, + this._sessionClosePromise(), + ]).then( + (r) => { + cleanup(); + return r; + }, + (error) => { + cleanup(); + throw error; + } + ); + } + /** * This method navigate to the previous page in history. * @param options - Navigation parameters diff --git a/test/page.spec.ts b/test/page.spec.ts index f81851c5fad4b..5c9ef3a09af1d 100644 --- a/test/page.spec.ts +++ b/test/page.spec.ts @@ -825,6 +825,79 @@ describe('Page', function () { }); }); + describe('Page.waitForNetworkIdle', function () { + it('should work', async () => { + const { page, server } = getTestState(); + await page.goto(server.EMPTY_PAGE); + let res; + const [t1, t2] = await Promise.all([ + page.waitForNetworkIdle().then((r) => { + res = r; + return Date.now(); + }), + page + .evaluate(() => + (async () => { + await Promise.all([ + fetch('/digits/1.png'), + fetch('/digits/2.png'), + ]); + await new Promise((resolve) => setTimeout(resolve, 200)); + await fetch('/digits/3.png'); + await new Promise((resolve) => setTimeout(resolve, 400)); + await fetch('/digits/4.png'); + })() + ) + .then(() => Date.now()), + ]); + expect(res).toBe(undefined); + expect(t1).toBeGreaterThan(t2); + expect(t1 - t2).toBeGreaterThanOrEqual(400); + }); + it('should respect timeout', async () => { + const { page, puppeteer } = getTestState(); + let error = null; + await page + .waitForNetworkIdle({ timeout: 1 }) + .catch((error_) => (error = error_)); + expect(error).toBeInstanceOf(puppeteer.errors.TimeoutError); + }); + it('should respect idleTime', async () => { + const { page, server } = getTestState(); + await page.goto(server.EMPTY_PAGE); + const [t1, t2] = await Promise.all([ + page.waitForNetworkIdle({ idleTime: 10 }).then(() => Date.now()), + page + .evaluate(() => + (async () => { + await Promise.all([ + fetch('/digits/1.png'), + fetch('/digits/2.png'), + ]); + await new Promise((resolve) => setTimeout(resolve, 250)); + })() + ) + .then(() => Date.now()), + ]); + expect(t2).toBeGreaterThan(t1); + }); + it('should work with no timeout', async () => { + const { page, server } = getTestState(); + await page.goto(server.EMPTY_PAGE); + const [result] = await Promise.all([ + page.waitForNetworkIdle({ timeout: 0 }), + page.evaluate(() => + setTimeout(() => { + fetch('/digits/1.png'); + fetch('/digits/2.png'); + fetch('/digits/3.png'); + }, 50) + ), + ]); + expect(result).toBe(undefined); + }); + }); + describeFailsFirefox('Page.exposeFunction', function () { it('should work', async () => { const { page } = getTestState(); From 723052d5bb3c3d1d3908508467512bea4d8fdc80 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Sat, 11 Sep 2021 22:59:51 +0200 Subject: [PATCH 06/31] feat(typescript): allow using puppeteer without dom lib (#6998) The dom lib inserts all dom related types into the project, which is often undesirable when working on a NodeJS project. This change injects global stubs for the dom types required by puppeteer, so puppeteer can work without users having to add dom types to their project. Closes #6989 --- inject-global-type-stubs.js | 29 +++++++++++++++++++++++++++++ package.json | 2 +- src/global.ts | 20 ++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 inject-global-type-stubs.js create mode 100644 src/global.ts diff --git a/inject-global-type-stubs.js b/inject-global-type-stubs.js new file mode 100644 index 0000000000000..adc634990321c --- /dev/null +++ b/inject-global-type-stubs.js @@ -0,0 +1,29 @@ +/** + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This script is needed because of https://github.com/microsoft/rushstack/issues/1709 +const { promises: fs } = require('fs'); +const { join } = require('path'); + +async function injctGlobalTypeStubs() { + const typesPath = join(__dirname, 'lib', 'types.d.ts'); + const globalsPath = join(__dirname, 'lib', 'cjs', 'puppeteer', 'global.d.ts'); + const types = await fs.readFile(typesPath, 'utf-8'); + const globals = await fs.readFile(globalsPath, 'utf-8'); + await fs.writeFile(typesPath, `${globals}\n${types}`); +} + +injctGlobalTypeStubs(); diff --git a/package.json b/package.json index e960d7ab34cdd..61ae8dc256d05 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "apply-next-version": "node utils/apply_next_version.js", "test-install": "scripts/test-install.sh", "clean-docs": "rimraf website/docs && rimraf docs-api-json", - "generate-d-ts": "npm run clean-docs && api-extractor run --local --verbose", + "generate-d-ts": "npm run clean-docs && api-extractor run --local --verbose && node inject-global-type-stubs.js", "generate-docs": "npm run generate-d-ts && api-documenter markdown -i docs-api-json -o website/docs && node utils/remove-tag.js", "ensure-correct-devtools-protocol-revision": "ts-node -s scripts/ensure-correct-devtools-protocol-package", "ensure-pinned-deps": "ts-node -s scripts/ensure-pinned-deps", diff --git a/src/global.ts b/src/global.ts new file mode 100644 index 0000000000000..2dce058df26ee --- /dev/null +++ b/src/global.ts @@ -0,0 +1,20 @@ +/** + * These global declarations exist so puppeteer can work without the need to use `"dom"` + * types. + * + * To get full type information for these interfaces, add `"types": "dom"`in your + * `tsconfig.json` file. + */ +declare global { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface Document {} + + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface Element {} + + // eslint-disable-next-line max-len + // eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars + interface NodeListOf {} +} + +export {}; From 491614c7f8cfa50b902d0275064e611c2a48c3b2 Mon Sep 17 00:00:00 2001 From: Albert Nigmatzianov Date: Sat, 11 Sep 2021 23:31:08 +0200 Subject: [PATCH 07/31] fix(types): allow evaluate functions to take a readonly array as an argument (#7072) --- src/common/EvalTypes.ts | 2 +- test/frame.spec.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/common/EvalTypes.ts b/src/common/EvalTypes.ts index 200cf70129ab3..b400f44b5fb47 100644 --- a/src/common/EvalTypes.ts +++ b/src/common/EvalTypes.ts @@ -54,7 +54,7 @@ export type Serializable = /** * @public */ -export type JSONArray = Serializable[]; +export type JSONArray = readonly Serializable[]; /** * @public diff --git a/test/frame.spec.ts b/test/frame.spec.ts index 269da7d7f1be8..f1310f6905dfd 100644 --- a/test/frame.spec.ts +++ b/test/frame.spec.ts @@ -79,6 +79,17 @@ describe('Frame specs', function () { 'Execution context is not available in detached frame' ); }); + + it('allows readonly array to be an argument', async () => { + const { page, server } = getTestState(); + await page.goto(server.EMPTY_PAGE); + const mainFrame = page.mainFrame(); + + // This test checks if Frame.evaluate allows a readonly array to be an argument. + // See https://github.com/puppeteer/puppeteer/issues/6953. + const readonlyArray: readonly string[] = ['a', 'b', 'c']; + mainFrame.evaluate((arr) => arr, readonlyArray); + }); }); describe('Frame Management', function () { From 57d1bd4240aab8bdc702ba80cf43a01411414115 Mon Sep 17 00:00:00 2001 From: Voltrex Date: Mon, 13 Sep 2021 13:44:23 +0430 Subject: [PATCH 08/31] refactor(node): apply optimizations (#7557) Replaced unnecessary template strings and used less calls for optimization. --- src/node/BrowserFetcher.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/node/BrowserFetcher.ts b/src/node/BrowserFetcher.ts index 20301e2462142..d5f25708e1ff6 100644 --- a/src/node/BrowserFetcher.ts +++ b/src/node/BrowserFetcher.ts @@ -35,7 +35,7 @@ import createHttpsProxyAgent, { import { getProxyForUrl } from 'proxy-from-env'; import { assert } from '../common/assert.js'; -const debugFetcher = debug(`puppeteer:fetcher`); +const debugFetcher = debug('puppeteer:fetcher'); const downloadURLs = { chrome: { @@ -112,10 +112,12 @@ function handleArm64(): void { if (stats === undefined) { fs.stat('/usr/bin/chromium', function (err, stats) { if (stats === undefined) { - console.error(`The chromium binary is not available for arm64.`); - console.error(`If you are on Ubuntu, you can install with: `); - console.error(`\n sudo apt install chromium\n`); - console.error(`\n sudo apt install chromium-browser\n`); + console.error( + 'The chromium binary is not available for arm64.' + + '\nIf you are on Ubuntu, you can install with: ' + + '\n\n sudo apt install chromium\n' + + '\n\n sudo apt install chromium-browser\n' + ); throw new Error(); } }); @@ -216,7 +218,7 @@ export class BrowserFetcher { else if (platform === 'linux') this._platform = 'linux'; else if (platform === 'win32') this._platform = os.arch() === 'x64' ? 'win64' : 'win32'; - else assert(this._platform, 'Unsupported platform: ' + os.platform()); + else assert(this._platform, 'Unsupported platform: ' + platform); } /** @@ -387,9 +389,7 @@ export class BrowserFetcher { else if (this._platform === 'win32' || this._platform === 'win64') executablePath = path.join(folderPath, 'firefox', 'firefox.exe'); else throw new Error('Unsupported platform: ' + this._platform); - } else { - throw new Error('Unsupported product: ' + this._product); - } + } else throw new Error('Unsupported product: ' + this._product); const url = downloadURL( this._product, this._platform, @@ -419,7 +419,7 @@ export class BrowserFetcher { * @internal */ _getFolderPath(revision: string): string { - return path.join(this._downloadsFolder, this._platform + '-' + revision); + return path.join(this._downloadsFolder, `${this._platform}-${revision}`); } } @@ -528,9 +528,9 @@ function installDMG(dmgPath: string, folderPath: string): Promise { mountPath = volumes[0]; readdirAsync(mountPath) .then((fileNames) => { - const appName = fileNames.filter( + const appName = fileNames.find( (item) => typeof item === 'string' && item.endsWith('.app') - )[0]; + ); if (!appName) return reject(new Error(`Cannot find app in ${mountPath}`)); const copyPath = path.join(mountPath, appName); From ae24bcaf6d8e4414704b4358f2e8b477ecc4514a Mon Sep 17 00:00:00 2001 From: Net Date: Mon, 13 Sep 2021 05:47:18 -0400 Subject: [PATCH 09/31] chore(docs): add instructions for headless GPU acceleration (#6924) --- docs/troubleshooting.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 95b6834aae7a0..882d3ffb039e2 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -5,6 +5,7 @@ - [Chrome headless doesn't launch on Windows](#chrome-headless-doesnt-launch-on-windows) - [Chrome headless doesn't launch on UNIX](#chrome-headless-doesnt-launch-on-unix) +- [Chrome headless disables GPU compositing](#chrome-headless-disables-gpu-compositing) - [Chrome is downloaded but fails to launch on Node.js 14](#chrome-is-downloaded-but-fails-to-launch-on-nodejs-14) - [Setting Up Chrome Linux Sandbox](#setting-up-chrome-linux-sandbox) * [[recommended] Enable user namespace cloning](#recommended-enable-user-namespace-cloning) @@ -135,6 +136,17 @@ yum update nss -y - [#379](https://github.com/puppeteer/puppeteer/issues/379) - Alpine troubleshooting
+## Chrome headless disables GPU compositing + +Chrome/Chromium requires `--use-gl=egl` to [enable GPU acceleration in headless mode](https://github.com/chromium/chromium/commit/19671359ae25aa1e30bde90f8ff92453eeaac2ba). + +```js +const browser = await puppeteer.launch({ + headless: true, + args: ['--use-gl=egl'], +}); +``` + ## Chrome is downloaded but fails to launch on Node.js 14 If you get an error that looks like this when trying to launch Chromium: From a21b7376e7feaf23066d67948d52480516f42496 Mon Sep 17 00:00:00 2001 From: Tom Jenkinson Date: Tue, 14 Sep 2021 13:46:53 +0100 Subject: [PATCH 10/31] fix(test): tweak waitForNetworkIdle delay in test between downloads (#7564) --- test/page.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/page.spec.ts b/test/page.spec.ts index 5c9ef3a09af1d..ede090a97019b 100644 --- a/test/page.spec.ts +++ b/test/page.spec.ts @@ -844,7 +844,7 @@ describe('Page', function () { ]); await new Promise((resolve) => setTimeout(resolve, 200)); await fetch('/digits/3.png'); - await new Promise((resolve) => setTimeout(resolve, 400)); + await new Promise((resolve) => setTimeout(resolve, 200)); await fetch('/digits/4.png'); })() ) From 32cb9e93d6db8fd2487ed6e3c98f51bbf7296140 Mon Sep 17 00:00:00 2001 From: Andy Chosak Date: Tue, 14 Sep 2021 09:07:12 -0400 Subject: [PATCH 11/31] docs: bump recommended version for Alpine Docker (#7563) The current documentation for running with an Alpine-based Docker image recommends using Chromium 89 / Puppeteer 6.0.0. Chromium 92 is now supported by Puppeteer 10.0.0; this commit bumps the recommended versions. --- docs/troubleshooting.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 882d3ffb039e2..dd3ceef3c2987 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -339,14 +339,14 @@ how to run this Dockerfile from a webserver running on App Engine Flex (Node). ### Running on Alpine -The [newest Chromium package](https://pkgs.alpinelinux.org/package/edge/community/x86_64/chromium) supported on Alpine is 89, which corresponds to [Puppeteer v6.0.0](https://github.com/puppeteer/puppeteer/releases/tag/v6.0.0). +The [newest Chromium package](https://pkgs.alpinelinux.org/package/edge/community/x86_64/chromium) supported on Alpine is 92, which corresponds to [Puppeteer v10.0.0](https://github.com/puppeteer/puppeteer/releases/tag/v10.0.0). Example Dockerfile: ```Dockerfile FROM alpine -# Installs latest Chromium (89) package. +# Installs latest Chromium (92) package. RUN apk add --no-cache \ chromium \ nss \ @@ -363,8 +363,8 @@ RUN apk add --no-cache \ ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser -# Puppeteer v6.0.0 works with Chromium 89. -RUN yarn add puppeteer@6.0.0 +# Puppeteer v10.0.0 works with Chromium 92. +RUN yarn add puppeteer@10.0.0 # Add user so we don't need --no-sandbox. RUN addgroup -S pptruser && adduser -S -g pptruser pptruser \ From d132b8b041696e6d5b9a99d0be1acf1cf943efef Mon Sep 17 00:00:00 2001 From: TASNEEM KOUSHAR Date: Tue, 14 Sep 2021 19:33:28 +0530 Subject: [PATCH 12/31] fix: added names in V9.1.1 (#7547) --- .../version-9.1.1-sidebars.json | 264 ++++++++++++------ 1 file changed, 176 insertions(+), 88 deletions(-) diff --git a/website/versioned_sidebars/version-9.1.1-sidebars.json b/website/versioned_sidebars/version-9.1.1-sidebars.json index a12d66df11ce4..4ce9211fcf0c3 100644 --- a/website/versioned_sidebars/version-9.1.1-sidebars.json +++ b/website/versioned_sidebars/version-9.1.1-sidebars.json @@ -209,7 +209,8 @@ "items": [ { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext" + "id": "version-9.1.1/puppeteer.browsercontext", + "label": "browsercontext" }, { "collapsed": true, @@ -218,39 +219,48 @@ "items": [ { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.browser" + "id": "version-9.1.1/puppeteer.browsercontext.browser", + "label": "browser" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.overridepermissions" + "id": "version-9.1.1/puppeteer.browsercontext.overridepermissions", + "label": "overridepermissions" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.close" + "id": "version-9.1.1/puppeteer.browsercontext.close", + "label": "close" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.isincognito" + "id": "version-9.1.1/puppeteer.browsercontext.isincognito", + "label": "isincognito" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.newpage" + "id": "version-9.1.1/puppeteer.browsercontext.newpage", + "label": "newpage" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.overridepermissions" + "id": "version-9.1.1/puppeteer.browsercontext.overridepermissions", + "label": "overridepermissions" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.pages" + "id": "version-9.1.1/puppeteer.browsercontext.pages", + "label": "pages" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.targets" + "id": "version-9.1.1/puppeteer.browsercontext.targets", + "label": "targets" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.browsercontext.waitfortarget" + "id": "version-9.1.1/puppeteer.browsercontext.waitfortarget", + "label": "waitfortarget" } ] } @@ -263,7 +273,8 @@ "items": [ { "type": "doc", - "id": "version-9.1.1/puppeteer.page" + "id": "version-9.1.1/puppeteer.page", + "label": "page" }, { "collapsed": true, @@ -272,27 +283,33 @@ "items": [ { "type": "doc", - "id": "version-9.1.1/puppeteer.page.accessibility" + "id": "version-9.1.1/puppeteer.page.accessibility", + "label": "accessibility" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.coverage" + "id": "version-9.1.1/puppeteer.page.coverage", + "label": "Coverage" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.keyboard" + "id": "version-9.1.1/puppeteer.page.keyboard", + "label": "Keyboard" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.mouse" + "id": "version-9.1.1/puppeteer.page.mouse", + "label": "mouse" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.touchscreen" + "id": "version-9.1.1/puppeteer.page.touchscreen", + "label": "touchScreen" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.tracing" + "id": "version-9.1.1/puppeteer.page.tracing", + "label": "tracing" } ] }, @@ -303,287 +320,358 @@ "items": [ { "type": "doc", - "id": "version-9.1.1/puppeteer.page._" + "id": "version-9.1.1/puppeteer.page._", + "label": "$" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.__" + "id": "version-9.1.1/puppeteer.page.__", + "label": "$$" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.__eval" + "id": "version-9.1.1/puppeteer.page.__eval", + "label": "$$eval" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page._eval" + "id": "version-9.1.1/puppeteer.page._eval", + "label": "$eval" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page._x" + "id": "version-9.1.1/puppeteer.page._x", + "label": "$x" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.addscripttag" + "id": "version-9.1.1/puppeteer.page.addscripttag", + "label": "addscripttag" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.addstyletag" + "id": "version-9.1.1/puppeteer.page.addstyletag", + "label": "addstyletag" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.authenticate" + "id": "version-9.1.1/puppeteer.page.authenticate", + "label": "authenticate" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.bringtofront" + "id": "version-9.1.1/puppeteer.page.bringtofront", + "label": "bringtofront" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.browser" + "id": "version-9.1.1/puppeteer.page.browser", + "label": "browser" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.browsercontext" + "id": "version-9.1.1/puppeteer.page.browsercontext", + "label": "browsercontext" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.click" + "id": "version-9.1.1/puppeteer.page.click", + "label": "click" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.close" + "id": "version-9.1.1/puppeteer.page.close", + "label": "close" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.content" + "id": "version-9.1.1/puppeteer.page.content", + "label": "content" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.cookies" + "id": "version-9.1.1/puppeteer.page.cookies", + "label": "cookies" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.deletecookie" + "id": "version-9.1.1/puppeteer.page.deletecookie", + "label": "deletecookie" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.emulate" + "id": "version-9.1.1/puppeteer.page.emulate", + "label": "emulate" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.emulateidlestate" + "id": "version-9.1.1/puppeteer.page.emulateidlestate", + "label": "emulateidlestate" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.emulatemediafeatures" + "id": "version-9.1.1/puppeteer.page.emulatemediafeatures", + "label": "emulatemediafeatures" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.emulatenetworkconditions" + "id": "version-9.1.1/puppeteer.page.emulatenetworkconditions", + "label": "emulatenetworkconditions" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.emulatetimezone" + "id": "version-9.1.1/puppeteer.page.emulatetimezone", + "label": "emulatetimezone" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.emulatevisiondeficiency" + "id": "version-9.1.1/puppeteer.page.emulatevisiondeficiency", + "label": "emulatevisiondefinciency" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.evaluate" + "id": "version-9.1.1/puppeteer.page.evaluate", + "label": "evaluate" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.evaluatehandle" + "id": "version-9.1.1/puppeteer.page.evaluatehandle", + "label": "evaluatehandle" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.evaluateonnewdocument" + "id": "version-9.1.1/puppeteer.page.evaluateonnewdocument", + "label": "evaluateonnewdocument" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.exposefunction" + "id": "version-9.1.1/puppeteer.page.exposefunction", + "label": "exposefunction" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.focus" + "id": "version-9.1.1/puppeteer.page.focus", + "label": "focus" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.frames" + "id": "version-9.1.1/puppeteer.page.frames", + "label": "frames" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.goback" + "id": "version-9.1.1/puppeteer.page.goback", + "label": "goback" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.goforward" + "id": "version-9.1.1/puppeteer.page.goforward", + "label": "goforward" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.goto" + "id": "version-9.1.1/puppeteer.page.goto", + "label": "goto" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.hover" + "id": "version-9.1.1/puppeteer.page.hover", + "label": "hover" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.isclosed" + "id": "version-9.1.1/puppeteer.page.isclosed", + "label": "isclosed" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.isjavascriptenabled" + "id": "version-9.1.1/puppeteer.page.isjavascriptenabled", + "label": "isjavascriptenabled" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.mainframe" + "id": "version-9.1.1/puppeteer.page.mainframe", + "label": "mainframe" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.metrics" + "id": "version-9.1.1/puppeteer.page.metrics", + "label": "metrics" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.once" + "id": "version-9.1.1/puppeteer.page.once", + "label": "once" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.pdf" + "id": "version-9.1.1/puppeteer.page.pdf", + "label": "pdf" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.queryobjects" + "id": "version-9.1.1/puppeteer.page.queryobjects", + "label": "queryobjects" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.reload" + "id": "version-9.1.1/puppeteer.page.reload", + "label": "reload" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.screenshot" + "id": "version-9.1.1/puppeteer.page.screenshot", + "label": "screenshot" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.select" + "id": "version-9.1.1/puppeteer.page.select", + "label": "select" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setbypasscsp" + "id": "version-9.1.1/puppeteer.page.setbypasscsp", + "label": "setbypasscsp" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setcacheenabled" + "id": "version-9.1.1/puppeteer.page.setcacheenabled", + "label": "setcacheenabled" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setcontent" + "id": "version-9.1.1/puppeteer.page.setcontent", + "label": "setcontent" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setcookie" + "id": "version-9.1.1/puppeteer.page.setcookie", + "label": "setcookie" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setdefaultnavigationtimeout" + "id": "version-9.1.1/puppeteer.page.setdefaultnavigationtimeout", + "label": "setdefaultnavigationtimeout" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setdefaulttimeout" + "id": "version-9.1.1/puppeteer.page.setdefaulttimeout", + "label": "setdefaulttimeout" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setextrahttpheaders" + "id": "version-9.1.1/puppeteer.page.setextrahttpheaders", + "label": "setextrahttpheaders" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setgeolocation" + "id": "version-9.1.1/puppeteer.page.setgeolocation", + "label": "setgeolocation" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setjavascriptenabled" + "id": "version-9.1.1/puppeteer.page.setjavascriptenabled", + "label": "setjavascriptenabled" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setofflinemode" + "id": "version-9.1.1/puppeteer.page.setofflinemode", + "label": "setofflinemode" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setrequestinterception" + "id": "version-9.1.1/puppeteer.page.setrequestinterception", + "label": "setrequestinterception" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setuseragent" + "id": "version-9.1.1/puppeteer.page.setuseragent", + "label": "setuseragent" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.setviewport" + "id": "version-9.1.1/puppeteer.page.setviewport", + "label": "setviewport" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.tap" + "id": "version-9.1.1/puppeteer.page.tap", + "label": "tap" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.target" + "id": "version-9.1.1/puppeteer.page.target", + "label": "target" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.title" + "id": "version-9.1.1/puppeteer.page.title", + "label": "title" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.type" + "id": "version-9.1.1/puppeteer.page.type", + "label": "type" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.url" + "id": "version-9.1.1/puppeteer.page.url", + "label": "url" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.viewport" + "id": "version-9.1.1/puppeteer.page.viewport", + "label": "viewport" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitfor" + "id": "version-9.1.1/puppeteer.page.waitfor", + "label": "waitfor" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitforfilechooser" + "id": "version-9.1.1/puppeteer.page.waitforfilechooser", + "label": "waitforfilechooser" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitforfunction" + "id": "version-9.1.1/puppeteer.page.waitforfunction", + "label": "waitforfunction" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitfornavigation" + "id": "version-9.1.1/puppeteer.page.waitfornavigation", + "label": "waitfornavigation" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitforrequest" + "id": "version-9.1.1/puppeteer.page.waitforrequest", + "label": "waitforrequest" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitforresponse" + "id": "version-9.1.1/puppeteer.page.waitforresponse", + "label": "waitforresponse" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitforselector" + "id": "version-9.1.1/puppeteer.page.waitforselector", + "label": "waitforselector" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitfortimeout" + "id": "version-9.1.1/puppeteer.page.waitfortimeout", + "label": "waitfortimeout" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.waitforxpath" + "id": "version-9.1.1/puppeteer.page.waitforxpath", + "label": "waitforxpath" }, { "type": "doc", - "id": "version-9.1.1/puppeteer.page.workers" + "id": "version-9.1.1/puppeteer.page.workers", + "label": "workers" } ] } From 686030fe0d627c6ede577c6834adc7749ae06983 Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Tue, 14 Sep 2021 17:02:39 +0200 Subject: [PATCH 13/31] chore: remove references to upstream `master` branches (#7412) Chromium had its branch renamed to `main`, and for other projects we can just point to the `HEAD`. --- .eslintrc.js | 2 +- README.md | 2 +- docs/api.md | 6 +++--- docs/troubleshooting.md | 2 +- src/common/Connection.ts | 2 +- src/common/Page.ts | 4 ++-- src/node/LaunchOptions.ts | 2 +- utils/fetch_devices.js | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index a119974e1fed2..2c53f10bc4cf6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -142,7 +142,7 @@ module.exports = { '@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), + * https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/docs/rules/ban-types.md), * * Unfortunately there's no way to */ diff --git a/README.md b/README.md index aab80dd1dee3b..38613e2fe951e 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ 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/v10.2.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. +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/+/refs/heads/main/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users. **3. Creates a fresh user profile** diff --git a/docs/api.md b/docs/api.md index 6d73a1c2457be..353c5b8f47520 100644 --- a/docs/api.md +++ b/docs/api.md @@ -565,7 +565,7 @@ This methods attaches Puppeteer to an existing browser instance. - `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). + - `userDataDir` <[string]> Path to a [User Data Directory](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/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]>> @@ -646,7 +646,7 @@ try { - `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). + - `userDataDir` <[string]> Path to a [User Data Directory](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/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`. @@ -5036,7 +5036,7 @@ The `CDPSession` instances are used to talk raw Chrome Devtools Protocol: Useful links: - Documentation on DevTools Protocol can be found here: [DevTools Protocol Viewer](https://chromedevtools.github.io/devtools-protocol/). -- Getting Started with DevTools Protocol: https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md +- Getting Started with DevTools Protocol: https://github.com/aslushnikov/getting-started-with-cdp/blob/HEAD/README.md ```js const client = await page.target().createCDPSession(); diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index dd3ceef3c2987..64446217f9a40 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -440,7 +440,7 @@ There's also another [simple guide](https://timleland.com/headless-chrome-on-her AWS Lambda [limits](https://docs.aws.amazon.com/lambda/latest/dg/limits.html) deployment package sizes to ~50MB. This presents challenges for running headless Chrome (and therefore Puppeteer) on Lambda. The community has put together a few resources that work around the issues: - https://github.com/alixaxel/chrome-aws-lambda (kept updated with the latest stable release of puppeteer) -- https://github.com/adieuadieu/serverless-chrome/blob/master/docs/chrome.md (serverless plugin - outdated) +- https://github.com/adieuadieu/serverless-chrome/blob/HEAD/docs/chrome.md (serverless plugin - outdated) ### Running Puppeteer on AWS EC2 instance running Amazon-Linux diff --git a/src/common/Connection.ts b/src/common/Connection.ts index 865e9833fb158..9b3a861fe0a31 100644 --- a/src/common/Connection.ts +++ b/src/common/Connection.ts @@ -228,7 +228,7 @@ export const CDPSessionEmittedEvents = { * events can be subscribed to with `CDPSession.on` method. * * Useful links: {@link https://chromedevtools.github.io/devtools-protocol/ | DevTools Protocol Viewer} - * and {@link https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md | Getting Started with DevTools Protocol}. + * and {@link https://github.com/aslushnikov/getting-started-with-cdp/blob/HEAD/README.md | Getting Started with DevTools Protocol}. * * @example * ```js diff --git a/src/common/Page.ts b/src/common/Page.ts index b2aa354d9eb30..20d282e364388 100644 --- a/src/common/Page.ts +++ b/src/common/Page.ts @@ -501,7 +501,7 @@ export class Page extends EventEmitter { // We still want to attach to workers for emitting events. // We still want to attach to iframes so sessions may interact with them. // We detach from all other types out of an abundance of caution. - // See https://source.chromium.org/chromium/chromium/src/+/master:content/browser/devtools/devtools_agent_host_impl.cc?q=f:devtools%20-f:out%20%22::kTypePage%5B%5D%22&ss=chromium + // See https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/devtools_agent_host_impl.cc?ss=chromium&q=f:devtools%20-f:out%20%22::kTypePage%5B%5D%22 // for the complete list of available types. client .send('Target.detachFromTarget', { @@ -1098,7 +1098,7 @@ export class Page extends EventEmitter { * * TODO(@jackfranklin): We could fix this by using overloads like * DefinitelyTyped does: - * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/puppeteer/index.d.ts#L114 + * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/HEAD/types/puppeteer/index.d.ts#L114 */ ...args: unknown[] ) => ReturnType | Promise, diff --git a/src/node/LaunchOptions.ts b/src/node/LaunchOptions.ts index 52c81cf519321..6b3d9b25af148 100644 --- a/src/node/LaunchOptions.ts +++ b/src/node/LaunchOptions.ts @@ -30,7 +30,7 @@ export interface BrowserLaunchArgumentOptions { headless?: boolean; /** * Path to a user data directory. - * {@link https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md | see the Chromium docs} + * {@link https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/user_data_dir.md | see the Chromium docs} * for more info. */ userDataDir?: string; diff --git a/utils/fetch_devices.js b/utils/fetch_devices.js index f49a09124cd95..4d255b5d39a48 100755 --- a/utils/fetch_devices.js +++ b/utils/fetch_devices.js @@ -20,7 +20,7 @@ const fs = require('fs'); const path = require('path'); const puppeteer = require('..'); const DEVICES_URL = - 'https://raw.githubusercontent.com/ChromeDevTools/devtools-frontend/master/front_end/emulated_devices/module.json'; + 'https://raw.githubusercontent.com/ChromeDevTools/devtools-frontend/HEAD/front_end/emulated_devices/module.json'; const template = `/** * Copyright 2017 Google Inc. All rights reserved. From a0b1f6b401abae2fbc5a8987061644adfaa7b482 Mon Sep 17 00:00:00 2001 From: Jan Scheffler Date: Tue, 14 Sep 2021 17:21:06 +0200 Subject: [PATCH 14/31] feat: add unit test support for bisect (#7553) --- CONTRIBUTING.md | 6 +++- utils/bisect.js | 93 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a40178380d293..344b75fb24b3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -292,12 +292,16 @@ The following steps are needed to update the Chromium version. ### 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: +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 pattern for one or more unit tests, it will automatically bisect the current range: ```sh node utils/bisect.js --good 686378 --bad 706915 script.js + +node utils/bisect.js --unit-test Response.fromCache ``` +By default, it will use the Chromium revision in `src/revisions.ts` from the `main` branch and from the working tree to determine the range to bisect. + ## Releasing to npm Releasing to npm consists of the following phases: diff --git a/utils/bisect.js b/utils/bisect.js index d81fdec8f5908..60b7ba07c61d5 100755 --- a/utils/bisect.js +++ b/utils/bisect.js @@ -21,7 +21,7 @@ const pptr = require('..'); const browserFetcher = pptr.createBrowserFetcher(); const path = require('path'); const fs = require('fs'); -const { fork } = require('child_process'); +const { fork, spawn, execSync } = require('child_process'); const COLOR_RESET = '\x1b[0m'; const COLOR_RED = '\x1b[31m'; @@ -35,12 +35,16 @@ Usage: node bisect.js --good --bad