diff --git a/docs/api.md b/docs/api.md index fc03d7f53e997..a908151509a3b 100644 --- a/docs/api.md +++ b/docs/api.md @@ -625,6 +625,7 @@ try { - `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`) - `targetFilter` Use this function to decide if Puppeteer should connect to the given target. If a `targetFilter` is provided, Puppeteer only connects to targets for which `targetFilter` returns `true`. By default, Puppeteer connects to all available targets. + - `waitForInitialPage` <[boolean]> Whether to wait for the initial page to be ready. Defaults to `true`. - returns: <[Promise]<[Browser]>> Promise which resolves to browser instance. You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments: diff --git a/src/node/LaunchOptions.ts b/src/node/LaunchOptions.ts index 306edd6eb94b0..c211c565034d2 100644 --- a/src/node/LaunchOptions.ts +++ b/src/node/LaunchOptions.ts @@ -110,6 +110,12 @@ export interface LaunchOptions { * {@link https://developer.mozilla.org/en-US/docs/Mozilla/Preferences/Preference_reference | Additional preferences } that can be passed when launching with Firefox. */ extraPrefsFirefox?: Record; + /** + * Whether to wait for the initial page to be ready. + * Useful when a user explicitly disables that (e.g. `--no-startup-window` for Chrome). + * @defaultValue true + */ + waitForInitialPage?: boolean; } /** diff --git a/src/node/Launcher.ts b/src/node/Launcher.ts index 2ea2709c59ba9..34190e3dd71c0 100644 --- a/src/node/Launcher.ts +++ b/src/node/Launcher.ts @@ -75,6 +75,7 @@ class ChromeLauncher implements ProductLauncher { defaultViewport = { width: 800, height: 600 }, slowMo = 0, timeout = 30000, + waitForInitialPage = true, } = options; const profilePath = path.join(os.tmpdir(), 'puppeteer_dev_chrome_profile-'); @@ -147,7 +148,8 @@ class ChromeLauncher implements ProductLauncher { runner.proc, runner.close.bind(runner) ); - await browser.waitForTarget((t) => t.type() === 'page'); + if (waitForInitialPage) + await browser.waitForTarget((t) => t.type() === 'page'); return browser; } catch (error) { runner.kill(); @@ -245,6 +247,7 @@ class FirefoxLauncher implements ProductLauncher { slowMo = 0, timeout = 30000, extraPrefsFirefox = {}, + waitForInitialPage = true, } = options; const firefoxArguments = []; @@ -313,7 +316,8 @@ class FirefoxLauncher implements ProductLauncher { runner.proc, runner.close.bind(runner) ); - await browser.waitForTarget((t) => t.type() === 'page'); + if (waitForInitialPage) + await browser.waitForTarget((t) => t.type() === 'page'); return browser; } catch (error) { runner.kill(); diff --git a/test/launcher.spec.ts b/test/launcher.spec.ts index c302db28c6b2f..c9d8c226a8406 100644 --- a/test/launcher.spec.ts +++ b/test/launcher.spec.ts @@ -21,6 +21,7 @@ import { promisify } from 'util'; import Protocol from 'devtools-protocol'; import { getTestState, + itChromeOnly, itFailsFirefox, itOnlyRegularInstall, } from './mocha-utils'; // eslint-disable-line import/extensions @@ -430,6 +431,24 @@ describe('Launcher specs', function () { expect(screenshot).toBeInstanceOf(Buffer); await browser.close(); }); + itChromeOnly( + 'should launch Chrome properly with --no-startup-window and waitForInitialPage=false', + async () => { + const { defaultBrowserOptions, puppeteer } = getTestState(); + const options = { + args: ['--no-startup-window'], + waitForInitialPage: false, + // This is needed to prevent Puppeteer from adding an initial blank page. + // See also https://github.com/puppeteer/puppeteer/blob/ad6b736039436fcc5c0a262e5b575aa041427be3/src/node/Launcher.ts#L200 + ignoreDefaultArgs: true, + ...defaultBrowserOptions, + }; + const browser = await puppeteer.launch(options); + const pages = await browser.pages(); + expect(pages.length).toBe(0); + await browser.close(); + } + ); }); describe('Puppeteer.launch', function () {