From e3e68a99d2f0b0390984718edda131431396dba4 Mon Sep 17 00:00:00 2001 From: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com> Date: Mon, 12 Jun 2023 10:44:18 +0200 Subject: [PATCH] chore: use `launch` helper (#10344) --- test/.eslintrc.js | 2 +- test/TestExpectations.json | 12 +- test/src/TargetManager.spec.ts | 37 +- test/src/chromiumonly.spec.ts | 155 +++-- test/src/cookies.spec.ts | 11 +- test/src/headful.spec.ts | 80 +-- test/src/ignorehttpserrors.spec.ts | 1 + test/src/launcher.spec.ts | 981 ++++++++++++++++------------- test/src/mocha-utils.ts | 54 +- test/src/oopif.spec.ts | 1 + test/src/proxy.spec.ts | 136 ++-- test/src/screenshot.spec.ts | 7 +- test/src/tracing.spec.ts | 29 +- 13 files changed, 824 insertions(+), 682 deletions(-) diff --git a/test/.eslintrc.js b/test/.eslintrc.js index e74e13b8..969bf1c1 100644 --- a/test/.eslintrc.js +++ b/test/.eslintrc.js @@ -15,7 +15,7 @@ module.exports = { files: ['*.spec.ts'], rules: { 'no-restricted-syntax': [ - 'warn', + 'error', { message: 'Use helper command `launch` to make sure the browsers get cleaned', diff --git a/test/TestExpectations.json b/test/TestExpectations.json index 9d916e35..e339f94b 100644 --- a/test/TestExpectations.json +++ b/test/TestExpectations.json @@ -401,6 +401,12 @@ "parameters": ["webDriverBiDi"], "expectations": ["PASS"] }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome"], + "expectations": ["SKIP"] + }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", "platforms": ["darwin", "linux", "win32"], @@ -1145,12 +1151,6 @@ "parameters": ["cdp", "firefox"], "expectations": ["SKIP"] }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL"] - }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", "platforms": ["darwin", "linux", "win32"], diff --git a/test/src/TargetManager.spec.ts b/test/src/TargetManager.spec.ts index 282086ed..26c25467 100644 --- a/test/src/TargetManager.spec.ts +++ b/test/src/TargetManager.spec.ts @@ -15,46 +15,39 @@ */ import expect from 'expect'; -import { - CDPBrowser, - CDPBrowserContext, -} from 'puppeteer-core/internal/common/Browser.js'; +import {CDPBrowser} from 'puppeteer-core/internal/common/Browser.js'; -import {getTestState} from './mocha-utils'; // eslint-disable-line import/extensions +import {getTestState, launch} from './mocha-utils.js'; import {attachFrame} from './utils.js'; describe('TargetManager', () => { /* We use a special browser for this test as we need the --site-per-process flag */ - let browser: CDPBrowser; - let context: CDPBrowserContext; + let testState: Awaited> & { + browser: CDPBrowser; + }; - before(async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); - browser = (await puppeteer.launch( + beforeEach(async () => { + const {defaultBrowserOptions} = getTestState(); + testState = (await launch( Object.assign({}, defaultBrowserOptions, { args: (defaultBrowserOptions.args || []).concat([ '--site-per-process', '--remote-debugging-port=21222', '--host-rules=MAP * 127.0.0.1', ]), - }) - )) as CDPBrowser; - }); - - beforeEach(async () => { - context = await browser.createIncognitoBrowserContext(); + }), + {createPage: false} + )) as Awaited> & { + browser: CDPBrowser; + }; }); afterEach(async () => { - await context.close(); - }); - - after(async () => { - await browser.close(); + await testState.close(); }); it('should handle targets', async () => { - const {server} = getTestState(); + const {server, context, browser} = testState; const targetManager = browser._targetManager(); expect(targetManager.getAvailableTargets().size).toBe(2); diff --git a/test/src/chromiumonly.spec.ts b/test/src/chromiumonly.spec.ts index 8ddcfe33..ae69926f 100644 --- a/test/src/chromiumonly.spec.ts +++ b/test/src/chromiumonly.spec.ts @@ -19,6 +19,7 @@ import expect from 'expect'; import { getTestState, + launch, setupTestBrowserHooks, setupTestPageAndContextHooks, } from './mocha-utils.js'; @@ -29,111 +30,129 @@ describe('Chromium-Specific Launcher tests', function () { it('should be able to connect using browserUrl, with and without trailing slash', async () => { const {defaultBrowserOptions, puppeteer} = getTestState(); - const originalBrowser = await puppeteer.launch( + const {close} = await launch( Object.assign({}, defaultBrowserOptions, { args: ['--remote-debugging-port=21222'], }) ); - const browserURL = 'http://127.0.0.1:21222'; + try { + const browserURL = 'http://127.0.0.1:21222'; - const browser1 = await puppeteer.connect({browserURL}); - const page1 = await browser1.newPage(); - expect( - await page1.evaluate(() => { - return 7 * 8; - }) - ).toBe(56); - browser1.disconnect(); + const browser1 = await puppeteer.connect({browserURL}); + const page1 = await browser1.newPage(); + expect( + await page1.evaluate(() => { + return 7 * 8; + }) + ).toBe(56); + browser1.disconnect(); - const browser2 = await puppeteer.connect({ - browserURL: browserURL + '/', - }); - const page2 = await browser2.newPage(); - expect( - await page2.evaluate(() => { - return 8 * 7; - }) - ).toBe(56); - browser2.disconnect(); - await originalBrowser.close(); + const browser2 = await puppeteer.connect({ + browserURL: browserURL + '/', + }); + const page2 = await browser2.newPage(); + expect( + await page2.evaluate(() => { + return 8 * 7; + }) + ).toBe(56); + browser2.disconnect(); + } finally { + await close(); + } }); it('should throw when using both browserWSEndpoint and browserURL', async () => { const {defaultBrowserOptions, puppeteer} = getTestState(); - const originalBrowser = await puppeteer.launch( + const {browser, close} = await launch( Object.assign({}, defaultBrowserOptions, { args: ['--remote-debugging-port=21222'], }) ); - const browserURL = 'http://127.0.0.1:21222'; + try { + const browserURL = 'http://127.0.0.1:21222'; - let error!: Error; - await puppeteer - .connect({ - browserURL, - browserWSEndpoint: originalBrowser.wsEndpoint(), - }) - .catch(error_ => { - return (error = error_); - }); - expect(error.message).toContain( - 'Exactly one of browserWSEndpoint, browserURL or transport' - ); - - await originalBrowser.close(); + let error!: Error; + await puppeteer + .connect({ + browserURL, + browserWSEndpoint: browser.wsEndpoint(), + }) + .catch(error_ => { + return (error = error_); + }); + expect(error.message).toContain( + 'Exactly one of browserWSEndpoint, browserURL or transport' + ); + } finally { + await close(); + } }); it('should throw when trying to connect to non-existing browser', async () => { const {defaultBrowserOptions, puppeteer} = getTestState(); - const originalBrowser = await puppeteer.launch( + const {close} = await launch( Object.assign({}, defaultBrowserOptions, { args: ['--remote-debugging-port=21222'], }) ); - const browserURL = 'http://127.0.0.1:32333'; + try { + const browserURL = 'http://127.0.0.1:32333'; - let error!: Error; - await puppeteer.connect({browserURL}).catch(error_ => { - return (error = error_); - }); - expect(error.message).toContain( - 'Failed to fetch browser webSocket URL from' - ); - await originalBrowser.close(); + let error!: Error; + await puppeteer.connect({browserURL}).catch(error_ => { + return (error = error_); + }); + expect(error.message).toContain( + 'Failed to fetch browser webSocket URL from' + ); + } finally { + await close(); + } }); }); describe('Puppeteer.launch |pipe| option', function () { it('should support the pipe option', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({pipe: true}, defaultBrowserOptions); - const browser = await puppeteer.launch(options); - expect(await browser.pages()).toHaveLength(1); - expect(browser.wsEndpoint()).toBe(''); - const page = await browser.newPage(); - expect(await page.evaluate('11 * 11')).toBe(121); - await page.close(); - await browser.close(); + const {browser, close} = await launch(options, {createPage: false}); + try { + expect(await browser.pages()).toHaveLength(1); + expect(browser.wsEndpoint()).toBe(''); + const page = await browser.newPage(); + expect(await page.evaluate('11 * 11')).toBe(121); + await page.close(); + } finally { + await close(); + } }); it('should support the pipe argument', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions); options.args = ['--remote-debugging-pipe'].concat(options.args || []); - const browser = await puppeteer.launch(options); - expect(browser.wsEndpoint()).toBe(''); - const page = await browser.newPage(); - expect(await page.evaluate('11 * 11')).toBe(121); - await page.close(); - await browser.close(); + const {browser, close} = await launch(options); + try { + expect(browser.wsEndpoint()).toBe(''); + const page = await browser.newPage(); + expect(await page.evaluate('11 * 11')).toBe(121); + await page.close(); + } finally { + await close(); + } }); it('should fire "disconnected" when closing with pipe', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({pipe: true}, defaultBrowserOptions); - const browser = await puppeteer.launch(options); - const disconnectedEventPromise = waitEvent(browser, 'disconnected'); - // Emulate user exiting browser. - browser.process()!.kill(); - await disconnectedEventPromise; + const {browser, close} = await launch(options); + try { + const disconnectedEventPromise = waitEvent(browser, 'disconnected'); + // Emulate user exiting browser. + browser.process()!.kill(); + await disconnectedEventPromise; + } finally { + await close(); + } }); }); }); diff --git a/test/src/cookies.spec.ts b/test/src/cookies.spec.ts index 2a048bd0..2e57f245 100644 --- a/test/src/cookies.spec.ts +++ b/test/src/cookies.spec.ts @@ -20,6 +20,7 @@ import { getTestState, setupTestBrowserHooks, setupTestPageAndContextHooks, + launch, } from './mocha-utils.js'; describe('Cookie specs', () => { @@ -480,16 +481,15 @@ describe('Cookie specs', () => { ]); }); it('should set secure same-site cookies from a frame', async () => { - const {httpsServer, puppeteer, defaultBrowserOptions} = getTestState(); + const {httpsServer, defaultBrowserOptions} = getTestState(); - const browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, ignoreHTTPSErrors: true, }); - const page = await browser.newPage(); - try { + const page = await browser.newPage(); await page.goto(httpsServer.PREFIX + '/grid.html'); await page.evaluate(src => { let fulfill!: () => void; @@ -533,8 +533,7 @@ describe('Cookie specs', () => { ] ); } finally { - await page.close(); - await browser.close(); + await close(); } }); }); diff --git a/test/src/headful.spec.ts b/test/src/headful.spec.ts index f75654f1..6be13b82 100644 --- a/test/src/headful.spec.ts +++ b/test/src/headful.spec.ts @@ -19,13 +19,10 @@ import os from 'os'; import path from 'path'; import expect from 'expect'; -import { - PuppeteerLaunchOptions, - PuppeteerNode, -} from 'puppeteer-core/internal/node/PuppeteerNode.js'; +import {PuppeteerLaunchOptions} from 'puppeteer-core/internal/node/PuppeteerNode.js'; import {rmSync} from 'puppeteer-core/internal/node/util/fs.js'; -import {getTestState} from './mocha-utils.js'; +import {getTestState, launch} from './mocha-utils.js'; const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); @@ -59,7 +56,7 @@ describe('headful tests', function () { headless: boolean; devtools: boolean; }; - const browsers: any[] = []; + const browsers: Array<() => Promise> = []; beforeEach(() => { const {server, defaultBrowserOptions} = getTestState(); @@ -96,29 +93,24 @@ describe('headful tests', function () { }); }); - async function launchBrowser(puppeteer: PuppeteerNode, options: any) { - const browser = await puppeteer.launch(options); - browsers.push(browser); + async function launchBrowser(options: any) { + const {browser, close} = await launch(options, {createContext: false}); + browsers.push(close); return browser; } - afterEach(() => { - for (const i in browsers) { - const browser = browsers[i]; - if (browser.isConnected()) { - browser.close(); - } - delete browsers[i]; - } + afterEach(async () => { + await Promise.all( + browsers.map((close, index) => { + delete browsers[index]; + return close(); + }) + ); }); describe('HEADFUL', function () { it('background_page target type should be available', async () => { - const {puppeteer} = getTestState(); - const browserWithExtension = await launchBrowser( - puppeteer, - extensionOptions - ); + const browserWithExtension = await launchBrowser(extensionOptions); const page = await browserWithExtension.newPage(); const backgroundPageTarget = await browserWithExtension.waitForTarget( target => { @@ -130,8 +122,8 @@ describe('headful tests', function () { expect(backgroundPageTarget).toBeTruthy(); }); it('service_worker target type should be available', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); - const browserWithExtension = await launchBrowser(puppeteer, { + const {defaultBrowserOptions} = getTestState(); + const browserWithExtension = await launchBrowser({ ...defaultBrowserOptions, headless: false, args: [ @@ -150,11 +142,7 @@ describe('headful tests', function () { expect(serviceWorkerTarget).toBeTruthy(); }); it('target.page() should return a background_page', async function () { - const {puppeteer} = getTestState(); - const browserWithExtension = await launchBrowser( - puppeteer, - extensionOptions - ); + const browserWithExtension = await launchBrowser(extensionOptions); const backgroundPageTarget = await browserWithExtension.waitForTarget( target => { return target.type() === 'background_page'; @@ -175,7 +163,7 @@ describe('headful tests', function () { }); it('target.page() should return a DevTools page if custom isPageTarget is provided', async function () { const {puppeteer} = getTestState(); - const originalBrowser = await launchBrowser(puppeteer, devtoolsOptions); + const originalBrowser = await launchBrowser(devtoolsOptions); const browserWSEndpoint = originalBrowser.wsEndpoint(); @@ -197,25 +185,21 @@ describe('headful tests', function () { }) ).toBe(6); expect(await browser.pages()).toContainEqual(page); - await browser.close(); }); it('should have default url when launching browser', async function () { - const {puppeteer} = getTestState(); - const browser = await launchBrowser(puppeteer, extensionOptions); + const browser = await launchBrowser(extensionOptions); const pages = (await browser.pages()).map((page: {url: () => any}) => { return page.url(); }); expect(pages).toEqual(['about:blank']); - await browser.close(); }); it('headless should be able to read cookies written by headful', async () => { /* Needs investigation into why but this fails consistently on Windows CI. */ - const {server, puppeteer} = getTestState(); + const {server} = getTestState(); const userDataDir = await mkdtemp(TMP_FOLDER); // Write a cookie in headful chrome const headfulBrowser = await launchBrowser( - puppeteer, Object.assign({userDataDir}, headfulOptions) ); const headfulPage = await headfulBrowser.newPage(); @@ -227,7 +211,6 @@ describe('headful tests', function () { await headfulBrowser.close(); // Read the cookie from headless chrome const headlessBrowser = await launchBrowser( - puppeteer, Object.assign({userDataDir}, headlessOptions) ); const headlessPage = await headlessBrowser.newPage(); @@ -244,10 +227,10 @@ describe('headful tests', function () { }); // TODO: Support OOOPIF. @see https://github.com/puppeteer/puppeteer/issues/2548 it.skip('OOPIF: should report google.com frame', async () => { - const {server, puppeteer} = getTestState(); + const {server} = getTestState(); // https://google.com is isolated by default in Chromium embedder. - const browser = await launchBrowser(puppeteer, headfulOptions); + const browser = await launchBrowser(headfulOptions); const page = await browser.newPage(); await page.goto(server.EMPTY_PAGE); await page.setRequestInterception(true); @@ -270,12 +253,11 @@ describe('headful tests', function () { }) .sort(); expect(urls).toEqual([server.EMPTY_PAGE, 'https://google.com/']); - await browser.close(); }); it('OOPIF: should expose events within OOPIFs', async () => { - const {server, puppeteer} = getTestState(); + const {server} = getTestState(); - const browser = await launchBrowser(puppeteer, forcedOopifOptions); + const browser = await launchBrowser(forcedOopifOptions); const page = await browser.newPage(); // Setup our session listeners to observe OOPIF activity. @@ -333,9 +315,9 @@ describe('headful tests', function () { expect(requests).toContain(`http://oopifdomain:${server.PORT}/fetch`); }); it('should close browser with beforeunload page', async () => { - const {server, puppeteer} = getTestState(); + const {server} = getTestState(); - const browser = await launchBrowser(puppeteer, headfulOptions); + const browser = await launchBrowser(headfulOptions); const page = await browser.newPage(); await page.goto(server.PREFIX + '/beforeunload.html'); // We have to interact with a page so that 'beforeunload' handlers @@ -344,10 +326,7 @@ describe('headful tests', function () { await browser.close(); }); it('should open devtools when "devtools: true" option is given', async () => { - const {puppeteer} = getTestState(); - const browser = await launchBrowser( - puppeteer, Object.assign({devtools: true}, headfulOptions) ); const context = await browser.createIncognitoBrowserContext(); @@ -363,8 +342,7 @@ describe('headful tests', function () { describe('Page.bringToFront', function () { it('should work', async () => { - const {puppeteer} = getTestState(); - const browser = await launchBrowser(puppeteer, headfulOptions); + const browser = await launchBrowser(headfulOptions); const page1 = await browser.newPage(); const page2 = await browser.newPage(); @@ -400,8 +378,8 @@ describe('headful tests', function () { describe('Page.screenshot', function () { it('should run in parallel in multiple pages', async () => { - const {server, puppeteer} = getTestState(); - const browser = await puppeteer.launch(headfulOptions); + const {server} = getTestState(); + const browser = await launchBrowser(headfulOptions); const context = await browser.createIncognitoBrowserContext(); const N = 2; diff --git a/test/src/ignorehttpserrors.spec.ts b/test/src/ignorehttpserrors.spec.ts index 8217092e..0ca8f18a 100644 --- a/test/src/ignorehttpserrors.spec.ts +++ b/test/src/ignorehttpserrors.spec.ts @@ -39,6 +39,7 @@ describe('ignoreHTTPSErrors', function () { {ignoreHTTPSErrors: true}, defaultBrowserOptions ); + // eslint-disable-next-line no-restricted-syntax browser = await puppeteer.launch(options); }); diff --git a/test/src/launcher.spec.ts b/test/src/launcher.spec.ts index 61249c0e..ae548b9d 100644 --- a/test/src/launcher.spec.ts +++ b/test/src/launcher.spec.ts @@ -26,13 +26,20 @@ import {Page} from 'puppeteer-core/internal/api/Page.js'; import {rmSync} from 'puppeteer-core/internal/node/util/fs.js'; import sinon from 'sinon'; -import {getTestState, itOnlyRegularInstall} from './mocha-utils.js'; +import { + getTestState, + itOnlyRegularInstall, + launch, + setupTestBrowserHooks, +} from './mocha-utils.js'; import {dumpFrames, waitEvent} from './utils.js'; const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); const FIREFOX_TIMEOUT = 30 * 1000; describe('Launcher specs', function () { + setupTestBrowserHooks(); + if (getTestState().isFirefox) { this.timeout(FIREFOX_TIMEOUT); } @@ -42,83 +49,89 @@ describe('Launcher specs', function () { it('should reject navigation when browser closes', async () => { const {server, puppeteer, defaultBrowserOptions} = getTestState(); server.setRoute('/one-style.css', () => {}); - const browser = await puppeteer.launch(defaultBrowserOptions); - const remote = await puppeteer.connect({ - browserWSEndpoint: browser.wsEndpoint(), - }); - const page = await remote.newPage(); - const navigationPromise = page - .goto(server.PREFIX + '/one-style.html', {timeout: 60000}) - .catch(error_ => { - return error_; + const {browser, close} = await launch(defaultBrowserOptions); + try { + const remote = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), }); - await server.waitForRequest('/one-style.css'); - remote.disconnect(); - const error = await navigationPromise; - expect( - [ - 'Navigation failed because browser has disconnected!', - 'Protocol error (Page.navigate): Target closed.', - ].includes(error.message) - ).toBeTruthy(); - await browser.close(); + const page = await remote.newPage(); + const navigationPromise = page + .goto(server.PREFIX + '/one-style.html', {timeout: 60000}) + .catch(error_ => { + return error_; + }); + await server.waitForRequest('/one-style.css'); + remote.disconnect(); + const error = await navigationPromise; + expect( + [ + 'Navigation failed because browser has disconnected!', + 'Protocol error (Page.navigate): Target closed.', + ].includes(error.message) + ).toBeTruthy(); + } finally { + await close(); + } }); it('should reject waitForSelector when browser closes', async () => { const {server, puppeteer, defaultBrowserOptions} = getTestState(); - server.setRoute('/empty.html', () => {}); - const browser = await puppeteer.launch(defaultBrowserOptions); - const remote = await puppeteer.connect({ - browserWSEndpoint: browser.wsEndpoint(), - }); - const page = await remote.newPage(); - const watchdog = page - .waitForSelector('div', {timeout: 60000}) - .catch(error_ => { - return error_; + const {browser, close} = await launch(defaultBrowserOptions); + try { + const remote = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), }); - remote.disconnect(); - const error = await watchdog; - expect(error.message).toContain('Protocol error'); - await browser.close(); + const page = await remote.newPage(); + const watchdog = page + .waitForSelector('div', {timeout: 60000}) + .catch(error_ => { + return error_; + }); + remote.disconnect(); + const error = await watchdog; + expect(error.message).toContain('Protocol error'); + } finally { + await close(); + } }); }); describe('Browser.close', function () { it('should terminate network waiters', async () => { const {server, puppeteer, defaultBrowserOptions} = getTestState(); - - const browser = await puppeteer.launch(defaultBrowserOptions); - const remote = await puppeteer.connect({ - browserWSEndpoint: browser.wsEndpoint(), - }); - const newPage = await remote.newPage(); - const results = await Promise.all([ - newPage.waitForRequest(server.EMPTY_PAGE).catch(error => { - return error; - }), - newPage.waitForResponse(server.EMPTY_PAGE).catch(error => { - return error; - }), - browser.close(), - ]); - for (let i = 0; i < 2; i++) { - const message = results[i].message; - expect(message).toContain('Target closed'); - expect(message).not.toContain('Timeout'); + const {browser, close} = await launch(defaultBrowserOptions); + try { + const remote = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), + }); + const newPage = await remote.newPage(); + const results = await Promise.all([ + newPage.waitForRequest(server.EMPTY_PAGE).catch(error => { + return error; + }), + newPage.waitForResponse(server.EMPTY_PAGE).catch(error => { + return error; + }), + browser.close(), + ]); + for (let i = 0; i < 2; i++) { + const message = results[i].message; + expect(message).toContain('Target closed'); + expect(message).not.toContain('Timeout'); + } + } finally { + await close(); } - await browser.close(); }); }); describe('Puppeteer.launch', function () { it('can launch and close the browser', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); - const browser = await puppeteer.launch(defaultBrowserOptions); - await browser.close(); + const {defaultBrowserOptions} = getTestState(); + const {close} = await launch(defaultBrowserOptions); + await close(); }); it('should reject all promises when browser is closed', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); - const browser = await puppeteer.launch(defaultBrowserOptions); - const page = await browser.newPage(); + const {defaultBrowserOptions} = getTestState(); + const {page, close} = await launch(defaultBrowserOptions); let error!: Error; const neverResolves = page .evaluate(() => { @@ -127,32 +140,36 @@ describe('Launcher specs', function () { .catch(error_ => { return (error = error_); }); - await browser.close(); + await close(); await neverResolves; expect(error.message).toContain('Protocol error'); }); it('should reject if executable path is invalid', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); let waitError!: Error; const options = Object.assign({}, defaultBrowserOptions, { executablePath: 'random-invalid-path', }); - await puppeteer.launch(options).catch(error => { + await launch(options).catch(error => { return (waitError = error); }); expect(waitError.message).toContain('Failed to launch'); }); it('userDataDir option', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const userDataDir = await mkdtemp(TMP_FOLDER); const options = Object.assign({userDataDir}, defaultBrowserOptions); - const browser = await puppeteer.launch(options); + const {context, close} = await launch(options); // Open a page to make sure its functional. - await browser.newPage(); - expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); - await browser.close(); + try { + await context.newPage(); + expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); + } finally { + await close(); + } + expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { @@ -172,18 +189,21 @@ describe('Launcher specs', function () { // Path should be empty before starting the browser. expect(fs.readdirSync(testTmpDir)).toHaveLength(0); - const browser = await puppeteer.launch(defaultBrowserOptions); + const {context, close} = await launch(defaultBrowserOptions); + try { + // One profile folder should have been created at this moment. + const profiles = fs.readdirSync(testTmpDir); + expect(profiles).toHaveLength(1); + expect(profiles[0]?.startsWith('puppeteer_dev_chrome_profile-')).toBe( + true + ); - // One profile folder should have been created at this moment. - const profiles = fs.readdirSync(testTmpDir); - expect(profiles).toHaveLength(1); - expect(profiles[0]?.startsWith('puppeteer_dev_chrome_profile-')).toBe( - true - ); + // Open a page to make sure its functional. + await context.newPage(); + } finally { + await close(); + } - // Open a page to make sure its functional. - await browser.newPage(); - await browser.close(); // Profile should be deleted after closing the browser expect(fs.readdirSync(testTmpDir)).toHaveLength(0); @@ -191,7 +211,7 @@ describe('Launcher specs', function () { puppeteer.configuration.temporaryDirectory = oldTmpDir; }); it('userDataDir option restores preferences', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const userDataDir = await mkdtemp(TMP_FOLDER); @@ -200,14 +220,18 @@ describe('Launcher specs', function () { await writeFile(prefsJSPath, prefsJSContent); const options = Object.assign({userDataDir}, defaultBrowserOptions); - const browser = await puppeteer.launch(options); - // Open a page to make sure its functional. - await browser.newPage(); - expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); - await browser.close(); - expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); + const {context, close} = await launch(options); + try { + // Open a page to make sure its functional. + await context.newPage(); + expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); + await close(); + expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); - expect(await readFile(prefsJSPath, 'utf8')).toBe(prefsJSContent); + expect(await readFile(prefsJSPath, 'utf8')).toBe(prefsJSContent); + } finally { + await close(); + } // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { @@ -215,7 +239,7 @@ describe('Launcher specs', function () { } catch {} }); it('userDataDir argument', async () => { - const {isChrome, puppeteer, defaultBrowserOptions} = getTestState(); + const {isChrome, defaultBrowserOptions} = getTestState(); const userDataDir = await mkdtemp(TMP_FOLDER); const options = Object.assign({}, defaultBrowserOptions); @@ -231,9 +255,9 @@ describe('Launcher specs', function () { userDataDir, ]; } - const browser = await puppeteer.launch(options); + const {close} = await launch(options); expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); - await browser.close(); + await close(); expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { @@ -241,7 +265,7 @@ describe('Launcher specs', function () { } catch {} }); it('userDataDir argument with non-existent dir', async () => { - const {isChrome, puppeteer, defaultBrowserOptions} = getTestState(); + const {isChrome, defaultBrowserOptions} = getTestState(); const userDataDir = await mkdtemp(TMP_FOLDER); rmSync(userDataDir); @@ -258,9 +282,9 @@ describe('Launcher specs', function () { userDataDir, ]; } - const browser = await puppeteer.launch(options); + const {close} = await launch(options); expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); - await browser.close(); + await close(); expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { @@ -268,55 +292,69 @@ describe('Launcher specs', function () { } catch {} }); it('userDataDir option should restore state', async () => { - const {server, puppeteer, defaultBrowserOptions} = getTestState(); - + const {server, defaultBrowserOptions} = getTestState(); const userDataDir = await mkdtemp(TMP_FOLDER); const options = Object.assign({userDataDir}, defaultBrowserOptions); - const browser = await puppeteer.launch(options); - const page = await browser.newPage(); - await page.goto(server.EMPTY_PAGE); - await page.evaluate(() => { - return (localStorage['hey'] = 'hello'); - }); - await browser.close(); + const {browser, close} = await launch(options); + try { + const page = await browser.newPage(); + await page.goto(server.EMPTY_PAGE); + await page.evaluate(() => { + return (localStorage['hey'] = 'hello'); + }); + } finally { + await close(); + } + + const {browser: browser2, close: close2} = await launch(options); + + try { + const page2 = await browser2.newPage(); + await page2.goto(server.EMPTY_PAGE); + expect( + await page2.evaluate(() => { + return localStorage['hey']; + }) + ).toBe('hello'); + } finally { + await close2(); + } - const browser2 = await puppeteer.launch(options); - const page2 = await browser2.newPage(); - await page2.goto(server.EMPTY_PAGE); - expect( - await page2.evaluate(() => { - return localStorage['hey']; - }) - ).toBe('hello'); - await browser2.close(); // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { rmSync(userDataDir); } catch {} }); it('userDataDir option should restore cookies', async () => { - const {server, puppeteer, defaultBrowserOptions} = getTestState(); + const {server, defaultBrowserOptions} = getTestState(); const userDataDir = await mkdtemp(TMP_FOLDER); const options = Object.assign({userDataDir}, defaultBrowserOptions); - const browser = await puppeteer.launch(options); - const page = await browser.newPage(); - await page.goto(server.EMPTY_PAGE); - await page.evaluate(() => { - return (document.cookie = - 'doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'); - }); - await browser.close(); + const {browser, close} = await launch(options); + try { + const page = await browser.newPage(); + await page.goto(server.EMPTY_PAGE); + await page.evaluate(() => { + return (document.cookie = + 'doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'); + }); + } finally { + await close(); + } + + const {browser: browser2, close: close2} = await launch(options); + try { + const page2 = await browser2.newPage(); + await page2.goto(server.EMPTY_PAGE); + expect( + await page2.evaluate(() => { + return document.cookie; + }) + ).toBe('doSomethingOnlyOnce=true'); + } finally { + await close2(); + } - const browser2 = await puppeteer.launch(options); - const page2 = await browser2.newPage(); - await page2.goto(server.EMPTY_PAGE); - expect( - await page2.evaluate(() => { - return document.cookie; - }) - ).toBe('doSomethingOnlyOnce=true'); - await browser2.close(); // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { rmSync(userDataDir); @@ -371,151 +409,178 @@ describe('Launcher specs', function () { } }); it('should work with no default arguments', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions); options.ignoreDefaultArgs = true; - const browser = await puppeteer.launch(options); + const {context, close} = await launch(options); try { - const page = await browser.newPage(); + const page = await context.newPage(); expect(await page.evaluate('11 * 11')).toBe(121); await page.close(); } finally { - await browser.close(); + await close(); } }); it('should filter out ignored default arguments in Chrome', async () => { const {defaultBrowserOptions, puppeteer} = getTestState(); // Make sure we launch with `--enable-automation` by default. const defaultArgs = puppeteer.defaultArgs(); - const browser = await puppeteer.launch( + const {browser, close} = await launch( Object.assign({}, defaultBrowserOptions, { // Ignore first and third default argument. ignoreDefaultArgs: [defaultArgs[0]!, defaultArgs[2]], }) ); - const spawnargs = browser.process()!.spawnargs; - if (!spawnargs) { - throw new Error('spawnargs not present'); + try { + const spawnargs = browser.process()!.spawnargs; + if (!spawnargs) { + throw new Error('spawnargs not present'); + } + expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1); + expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1); + expect(spawnargs.indexOf(defaultArgs[2]!)).toBe(-1); + } finally { + await close(); } - expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1); - expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1); - expect(spawnargs.indexOf(defaultArgs[2]!)).toBe(-1); - await browser.close(); }); it('should filter out ignored default argument in Firefox', async () => { const {defaultBrowserOptions, puppeteer} = getTestState(); const defaultArgs = puppeteer.defaultArgs(); - const browser = await puppeteer.launch( + const {browser, close} = await launch( Object.assign({}, defaultBrowserOptions, { // Only the first argument is fixed, others are optional. ignoreDefaultArgs: [defaultArgs[0]!], }) ); - const spawnargs = browser.process()!.spawnargs; - if (!spawnargs) { - throw new Error('spawnargs not present'); + try { + const spawnargs = browser.process()!.spawnargs; + if (!spawnargs) { + throw new Error('spawnargs not present'); + } + expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1); + expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1); + } finally { + await close(); } - expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1); - expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1); - await browser.close(); }); it('should have default URL when launching browser', async function () { - const {defaultBrowserOptions, puppeteer} = getTestState(); - const browser = await puppeteer.launch(defaultBrowserOptions); - const pages = (await browser.pages()).map(page => { - return page.url(); + const {defaultBrowserOptions} = getTestState(); + const {browser, close} = await launch(defaultBrowserOptions, { + createContext: false, }); - expect(pages).toEqual(['about:blank']); - await browser.close(); + try { + const pages = (await browser.pages()).map(page => { + return page.url(); + }); + expect(pages).toEqual(['about:blank']); + } finally { + await close(); + } }); it('should have custom URL when launching browser', async () => { - const {server, puppeteer, defaultBrowserOptions} = getTestState(); + const {server, defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions); options.args = [server.EMPTY_PAGE].concat(options.args || []); - const browser = await puppeteer.launch(options); - const pages = await browser.pages(); - expect(pages).toHaveLength(1); - const page = pages[0]!; - if (page.url() !== server.EMPTY_PAGE) { - await page.waitForNavigation(); + const {browser, close} = await launch(options, {createContext: false}); + try { + const pages = await browser.pages(); + expect(pages).toHaveLength(1); + const page = pages[0]!; + if (page.url() !== server.EMPTY_PAGE) { + await page.waitForNavigation(); + } + expect(page.url()).toBe(server.EMPTY_PAGE); + } finally { + await close(); } - expect(page.url()).toBe(server.EMPTY_PAGE); - await browser.close(); }); it('should pass the timeout parameter to browser.waitForTarget', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions, { timeout: 1, }); let error!: Error; - await puppeteer.launch(options).catch(error_ => { + await launch(options).catch(error_ => { return (error = error_); }); expect(error).toBeInstanceOf(TimeoutError); }); it('should work with timeout = 0', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions, { timeout: 0, }); - const browser = await puppeteer.launch(options); - await browser.close(); + const {close} = await launch(options); + await close(); }); it('should set the default viewport', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions, { defaultViewport: { width: 456, height: 789, }, }); - const browser = await puppeteer.launch(options); - const page = await browser.newPage(); - expect(await page.evaluate('window.innerWidth')).toBe(456); - expect(await page.evaluate('window.innerHeight')).toBe(789); - await browser.close(); + const {context, close} = await launch(options); + + try { + const page = await context.newPage(); + expect(await page.evaluate('window.innerWidth')).toBe(456); + expect(await page.evaluate('window.innerHeight')).toBe(789); + } finally { + await close(); + } }); it('should disable the default viewport', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions, { defaultViewport: null, }); - const browser = await puppeteer.launch(options); - const page = await browser.newPage(); - expect(page.viewport()).toBe(null); - await browser.close(); + const {context, close} = await launch(options); + try { + const page = await context.newPage(); + expect(page.viewport()).toBe(null); + } finally { + await close(); + } }); it('should take fullPage screenshots when defaultViewport is null', async () => { - const {server, puppeteer, defaultBrowserOptions} = getTestState(); + const {server, defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions, { defaultViewport: null, }); - const browser = await puppeteer.launch(options); - const page = await browser.newPage(); - await page.goto(server.PREFIX + '/grid.html'); - const screenshot = await page.screenshot({ - fullPage: true, - }); - expect(screenshot).toBeInstanceOf(Buffer); - await browser.close(); + const {context, close} = await launch(options); + try { + const page = await context.newPage(); + await page.goto(server.PREFIX + '/grid.html'); + const screenshot = await page.screenshot({ + fullPage: true, + }); + expect(screenshot).toBeInstanceOf(Buffer); + } finally { + await close(); + } }); it('should set the debugging port', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions, { defaultViewport: null, debuggingPort: 9999, }); - const browser = await puppeteer.launch(options); - const url = new URL(browser.wsEndpoint()); - await browser.close(); - expect(url.port).toBe('9999'); + const {browser, close} = await launch(options); + try { + const url = new URL(browser.wsEndpoint()); + expect(url.port).toBe('9999'); + } finally { + await close(); + } }); it('should not allow setting debuggingPort and pipe', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = Object.assign({}, defaultBrowserOptions, { defaultViewport: null, @@ -524,13 +589,13 @@ describe('Launcher specs', function () { }); let error!: Error; - await puppeteer.launch(options).catch(error_ => { + await launch(options).catch(error_ => { return (error = error_); }); expect(error.message).toContain('either pipe or debugging port'); }); it('should launch Chrome properly with --no-startup-window and waitForInitialPage=false', async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); + const {defaultBrowserOptions} = getTestState(); const options = { waitForInitialPage: false, // This is needed to prevent Puppeteer from adding an initial blank page. @@ -539,124 +604,151 @@ describe('Launcher specs', function () { ...defaultBrowserOptions, args: ['--no-startup-window'], }; - const browser = await puppeteer.launch(options); - const pages = await browser.pages(); - expect(pages).toHaveLength(0); - await browser.close(); + const {browser, close} = await launch(options, {createContext: false}); + try { + const pages = await browser.pages(); + expect(pages).toHaveLength(0); + } finally { + await close(); + } }); }); describe('Puppeteer.launch', function () { itOnlyRegularInstall('should be able to launch Chrome', async () => { - const {puppeteer} = getTestState(); - const browser = await puppeteer.launch({product: 'chrome'}); - const userAgent = await browser.userAgent(); - await browser.close(); - expect(userAgent).toContain('Chrome'); + const {browser, close} = await launch({product: 'chrome'}); + try { + const userAgent = await browser.userAgent(); + expect(userAgent).toContain('Chrome'); + } finally { + await close(); + } }); it('should be able to launch Firefox', async function () { this.timeout(FIREFOX_TIMEOUT); - const {puppeteer} = getTestState(); - const browser = await puppeteer.launch({product: 'firefox'}); - const userAgent = await browser.userAgent(); - await browser.close(); - expect(userAgent).toContain('Firefox'); + const {browser, close} = await launch({product: 'firefox'}); + try { + const userAgent = await browser.userAgent(); + expect(userAgent).toContain('Firefox'); + } finally { + await close(); + } }); }); describe('Puppeteer.connect', function () { it('should be able to connect multiple times to the same browser', async () => { const {puppeteer, defaultBrowserOptions} = getTestState(); + const {browser, close} = await launch(defaultBrowserOptions); + try { + const otherBrowser = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), + }); + const page = await otherBrowser.newPage(); + expect( + await page.evaluate(() => { + return 7 * 8; + }) + ).toBe(56); + otherBrowser.disconnect(); - const originalBrowser = await puppeteer.launch(defaultBrowserOptions); - const otherBrowser = await puppeteer.connect({ - browserWSEndpoint: originalBrowser.wsEndpoint(), - }); - const page = await otherBrowser.newPage(); - expect( - await page.evaluate(() => { - return 7 * 8; - }) - ).toBe(56); - otherBrowser.disconnect(); - - const secondPage = await originalBrowser.newPage(); - expect( - await secondPage.evaluate(() => { - return 7 * 6; - }) - ).toBe(42); - await originalBrowser.close(); + const secondPage = await browser.newPage(); + expect( + await secondPage.evaluate(() => { + return 7 * 6; + }) + ).toBe(42); + } finally { + await close(); + } }); it('should be able to close remote browser', async () => { const {defaultBrowserOptions, puppeteer} = getTestState(); - - const originalBrowser = await puppeteer.launch(defaultBrowserOptions); - const remoteBrowser = await puppeteer.connect({ - browserWSEndpoint: originalBrowser.wsEndpoint(), - }); - await Promise.all([ - waitEvent(originalBrowser, 'disconnected'), - remoteBrowser.close(), - ]); + const {browser, close} = await launch(defaultBrowserOptions); + try { + const remoteBrowser = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), + }); + await Promise.all([ + waitEvent(browser, 'disconnected'), + remoteBrowser.close(), + ]); + } finally { + await close(); + } }); it('should be able to connect to a browser with no page targets', async () => { const {defaultBrowserOptions, puppeteer} = getTestState(); + const {browser, close} = await launch(defaultBrowserOptions); - const originalBrowser = await puppeteer.launch(defaultBrowserOptions); - const pages = await originalBrowser.pages(); - await Promise.all( - pages.map(page => { - return page.close(); - }) - ); - const remoteBrowser = await puppeteer.connect({ - browserWSEndpoint: originalBrowser.wsEndpoint(), - }); - await Promise.all([ - waitEvent(originalBrowser, 'disconnected'), - remoteBrowser.close(), - ]); + try { + const pages = await browser.pages(); + await Promise.all( + pages.map(page => { + return page.close(); + }) + ); + const remoteBrowser = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), + }); + await Promise.all([ + waitEvent(browser, 'disconnected'), + remoteBrowser.close(), + ]); + } finally { + await close(); + } }); it('should support ignoreHTTPSErrors option', async () => { - const {httpsServer, puppeteer, defaultBrowserOptions} = getTestState(); + const {puppeteer, defaultBrowserOptions} = getTestState(); + const {httpsServer, browser, close} = await launch( + defaultBrowserOptions, + { + createContext: false, + } + ); - const originalBrowser = await puppeteer.launch(defaultBrowserOptions); - const browserWSEndpoint = originalBrowser.wsEndpoint(); - - const browser = await puppeteer.connect({ - browserWSEndpoint, - ignoreHTTPSErrors: true, - }); - const page = await browser.newPage(); - let error!: Error; - const [serverRequest, response] = await Promise.all([ - httpsServer.waitForRequest('/empty.html'), - page.goto(httpsServer.EMPTY_PAGE).catch(error_ => { - return (error = error_); - }), - ]); - expect(error).toBeUndefined(); - expect(response.ok()).toBe(true); - expect(response.securityDetails()).toBeTruthy(); - const protocol = (serverRequest.socket as TLSSocket) - .getProtocol()! - .replace('v', ' '); - expect(response.securityDetails().protocol()).toBe(protocol); - await page.close(); - await browser.close(); + try { + const browserWSEndpoint = browser.wsEndpoint(); + const remoteBrowser = await puppeteer.connect({ + browserWSEndpoint, + ignoreHTTPSErrors: true, + }); + const page = await remoteBrowser.newPage(); + let error!: Error; + const [serverRequest, response] = await Promise.all([ + httpsServer.waitForRequest('/empty.html'), + page.goto(httpsServer.EMPTY_PAGE).catch(error_ => { + return (error = error_); + }), + ]); + expect(error).toBeUndefined(); + expect(response.ok()).toBe(true); + expect(response.securityDetails()).toBeTruthy(); + const protocol = (serverRequest.socket as TLSSocket) + .getProtocol()! + .replace('v', ' '); + expect(response.securityDetails().protocol()).toBe(protocol); + await page.close(); + await remoteBrowser.close(); + } finally { + await close(); + } }); it('should support targetFilter option in puppeteer.launch', async () => { - const {puppeteer, defaultBrowserOptions} = getTestState(); - const browser = await puppeteer.launch({ - ...defaultBrowserOptions, - targetFilter: target => { - return target.type !== 'page'; + const {defaultBrowserOptions} = getTestState(); + const {browser, close} = await launch( + { + ...defaultBrowserOptions, + targetFilter: target => { + return target.type !== 'page'; + }, + waitForInitialPage: false, }, - waitForInitialPage: false, - }); + {createContext: false} + ); try { const targets = browser.targets(); expect(targets).toHaveLength(1); @@ -666,122 +758,142 @@ describe('Launcher specs', function () { }) ).toBeUndefined(); } finally { - await browser.close(); + await close(); } }); // @see https://github.com/puppeteer/puppeteer/issues/4197 it('should support targetFilter option', async () => { - const {server, puppeteer, defaultBrowserOptions} = getTestState(); - - const originalBrowser = await puppeteer.launch(defaultBrowserOptions); - const browserWSEndpoint = originalBrowser.wsEndpoint(); - - const page1 = await originalBrowser.newPage(); - await page1.goto(server.EMPTY_PAGE); - - const page2 = await originalBrowser.newPage(); - await page2.goto(server.EMPTY_PAGE + '?should-be-ignored'); - - const browser = await puppeteer.connect({ - browserWSEndpoint, - targetFilter: (targetInfo: Protocol.Target.TargetInfo) => { - return !targetInfo.url?.includes('should-be-ignored'); - }, + const {puppeteer, defaultBrowserOptions} = getTestState(); + const {server, browser, close} = await launch(defaultBrowserOptions, { + createContext: false, }); + try { + const browserWSEndpoint = browser.wsEndpoint(); + const page1 = await browser.newPage(); + await page1.goto(server.EMPTY_PAGE); - const pages = await browser.pages(); + const page2 = await browser.newPage(); + await page2.goto(server.EMPTY_PAGE + '?should-be-ignored'); - await page2.close(); - await page1.close(); - await browser.disconnect(); - await originalBrowser.close(); + const remoteBrowser = await puppeteer.connect({ + browserWSEndpoint, + targetFilter: (targetInfo: Protocol.Target.TargetInfo) => { + return !targetInfo.url?.includes('should-be-ignored'); + }, + }); - expect( - pages - .map((p: Page) => { - return p.url(); - }) - .sort() - ).toEqual(['about:blank', server.EMPTY_PAGE]); + const pages = await remoteBrowser.pages(); + + await page2.close(); + await page1.close(); + remoteBrowser.disconnect(); + await browser.close(); + + expect( + pages + .map((p: Page) => { + return p.url(); + }) + .sort() + ).toEqual(['about:blank', server.EMPTY_PAGE]); + } finally { + await close(); + } }); it('should be able to reconnect to a disconnected browser', async () => { - const {server, puppeteer, defaultBrowserOptions} = getTestState(); + const {puppeteer, defaultBrowserOptions} = getTestState(); + const {server, browser, close} = await launch(defaultBrowserOptions); + try { + const browserWSEndpoint = browser.wsEndpoint(); + const page = await browser.newPage(); + await page.goto(server.PREFIX + '/frames/nested-frames.html'); + browser.disconnect(); - const originalBrowser = await puppeteer.launch(defaultBrowserOptions); - const browserWSEndpoint = originalBrowser.wsEndpoint(); - const page = await originalBrowser.newPage(); - await page.goto(server.PREFIX + '/frames/nested-frames.html'); - originalBrowser.disconnect(); - - const browser = await puppeteer.connect({browserWSEndpoint}); - const pages = await browser.pages(); - const restoredPage = pages.find(page => { - return page.url() === server.PREFIX + '/frames/nested-frames.html'; - })!; - expect(dumpFrames(restoredPage.mainFrame())).toEqual([ - 'http://localhost:/frames/nested-frames.html', - ' http://localhost:/frames/two-frames.html (2frames)', - ' http://localhost:/frames/frame.html (uno)', - ' http://localhost:/frames/frame.html (dos)', - ' http://localhost:/frames/frame.html (aframe)', - ]); - expect( - await restoredPage.evaluate(() => { - return 7 * 8; - }) - ).toBe(56); - await browser.close(); + const remoteBrowser = await puppeteer.connect({browserWSEndpoint}); + const pages = await remoteBrowser.pages(); + const restoredPage = pages.find(page => { + return page.url() === server.PREFIX + '/frames/nested-frames.html'; + })!; + expect(dumpFrames(restoredPage.mainFrame())).toEqual([ + 'http://localhost:/frames/nested-frames.html', + ' http://localhost:/frames/two-frames.html (2frames)', + ' http://localhost:/frames/frame.html (uno)', + ' http://localhost:/frames/frame.html (dos)', + ' http://localhost:/frames/frame.html (aframe)', + ]); + expect( + await restoredPage.evaluate(() => { + return 7 * 8; + }) + ).toBe(56); + await remoteBrowser.close(); + } finally { + await close(); + } }); // @see https://github.com/puppeteer/puppeteer/issues/4197#issuecomment-481793410 it('should be able to connect to the same page simultaneously', async () => { const {puppeteer, defaultBrowserOptions} = getTestState(); + const {browser: browserOne, close} = await launch( + defaultBrowserOptions + ); - const browserOne = await puppeteer.launch(defaultBrowserOptions); - const browserTwo = await puppeteer.connect({ - browserWSEndpoint: browserOne.wsEndpoint(), - }); - const [page1, page2] = await Promise.all([ - new Promise(x => { - return browserOne.once('targetcreated', target => { - return x(target.page()); - }); - }), - browserTwo.newPage(), - ]); - expect( - await page1.evaluate(() => { - return 7 * 8; - }) - ).toBe(56); - expect( - await page2.evaluate(() => { - return 7 * 6; - }) - ).toBe(42); - await browserOne.close(); + try { + const browserTwo = await puppeteer.connect({ + browserWSEndpoint: browserOne.wsEndpoint(), + }); + const [page1, page2] = await Promise.all([ + new Promise(x => { + return browserOne.once('targetcreated', target => { + return x(target.page()); + }); + }), + browserTwo.newPage(), + ]); + expect( + await page1.evaluate(() => { + return 7 * 8; + }) + ).toBe(56); + expect( + await page2.evaluate(() => { + return 7 * 6; + }) + ).toBe(42); + } finally { + await close(); + } }); it('should be able to reconnect', async () => { - const {puppeteer, server, defaultBrowserOptions} = getTestState(); - const browserOne = await puppeteer.launch(defaultBrowserOptions); - const browserWSEndpoint = browserOne.wsEndpoint(); - const pageOne = await browserOne.newPage(); - await pageOne.goto(server.EMPTY_PAGE); - browserOne.disconnect(); + const {puppeteer, defaultBrowserOptions} = getTestState(); + const { + server, + browser: browserOne, + close, + } = await launch(defaultBrowserOptions); + try { + const browserWSEndpoint = browserOne.wsEndpoint(); + const pageOne = await browserOne.newPage(); + await pageOne.goto(server.EMPTY_PAGE); + browserOne.disconnect(); - const browserTwo = await puppeteer.connect({ - browserWSEndpoint, - }); - const pages = await browserTwo.pages(); - const pageTwo = pages.find(page => { - return page.url() === server.EMPTY_PAGE; - })!; - await pageTwo.reload(); - const bodyHandle = await pageTwo.waitForSelector('body', { - timeout: 10000, - }); - await bodyHandle!.dispose(); - await browserTwo.close(); + const browserTwo = await puppeteer.connect({ + browserWSEndpoint, + }); + const pages = await browserTwo.pages(); + const pageTwo = pages.find(page => { + return page.url() === server.EMPTY_PAGE; + })!; + await pageTwo.reload(); + const bodyHandle = await pageTwo.waitForSelector('body', { + timeout: 10000, + }); + await bodyHandle!.dispose(); + await browserTwo.close(); + } finally { + await close(); + } }); }); describe('Puppeteer.executablePath', function () { @@ -828,70 +940,77 @@ describe('Launcher specs', function () { describe('Browser target events', function () { it('should work', async () => { - const {server, puppeteer, defaultBrowserOptions} = getTestState(); + const {defaultBrowserOptions} = getTestState(); + const {browser, server, close} = await launch(defaultBrowserOptions); - const browser = await puppeteer.launch(defaultBrowserOptions); - const events: string[] = []; - browser.on('targetcreated', () => { - return events.push('CREATED'); - }); - browser.on('targetchanged', () => { - return events.push('CHANGED'); - }); - browser.on('targetdestroyed', () => { - return events.push('DESTROYED'); - }); - const page = await browser.newPage(); - await page.goto(server.EMPTY_PAGE); - await page.close(); - expect(events).toEqual(['CREATED', 'CHANGED', 'DESTROYED']); - await browser.close(); + try { + const events: string[] = []; + browser.on('targetcreated', () => { + return events.push('CREATED'); + }); + browser.on('targetchanged', () => { + return events.push('CHANGED'); + }); + browser.on('targetdestroyed', () => { + return events.push('DESTROYED'); + }); + const page = await browser.newPage(); + await page.goto(server.EMPTY_PAGE); + await page.close(); + expect(events).toEqual(['CREATED', 'CHANGED', 'DESTROYED']); + } finally { + await close(); + } }); }); describe('Browser.Events.disconnected', function () { it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async () => { const {puppeteer, defaultBrowserOptions} = getTestState(); - const originalBrowser = await puppeteer.launch(defaultBrowserOptions); - const browserWSEndpoint = originalBrowser.wsEndpoint(); - const remoteBrowser1 = await puppeteer.connect({ - browserWSEndpoint, - }); - const remoteBrowser2 = await puppeteer.connect({ - browserWSEndpoint, - }); + const {browser, close} = await launch(defaultBrowserOptions); + try { + const browserWSEndpoint = browser.wsEndpoint(); + const remoteBrowser1 = await puppeteer.connect({ + browserWSEndpoint, + }); + const remoteBrowser2 = await puppeteer.connect({ + browserWSEndpoint, + }); - let disconnectedOriginal = 0; - let disconnectedRemote1 = 0; - let disconnectedRemote2 = 0; - originalBrowser.on('disconnected', () => { - return ++disconnectedOriginal; - }); - remoteBrowser1.on('disconnected', () => { - return ++disconnectedRemote1; - }); - remoteBrowser2.on('disconnected', () => { - return ++disconnectedRemote2; - }); + let disconnectedOriginal = 0; + let disconnectedRemote1 = 0; + let disconnectedRemote2 = 0; + browser.on('disconnected', () => { + return ++disconnectedOriginal; + }); + remoteBrowser1.on('disconnected', () => { + return ++disconnectedRemote1; + }); + remoteBrowser2.on('disconnected', () => { + return ++disconnectedRemote2; + }); - await Promise.all([ - waitEvent(remoteBrowser2, 'disconnected'), - remoteBrowser2.disconnect(), - ]); + await Promise.all([ + waitEvent(remoteBrowser2, 'disconnected'), + remoteBrowser2.disconnect(), + ]); - expect(disconnectedOriginal).toBe(0); - expect(disconnectedRemote1).toBe(0); - expect(disconnectedRemote2).toBe(1); + expect(disconnectedOriginal).toBe(0); + expect(disconnectedRemote1).toBe(0); + expect(disconnectedRemote2).toBe(1); - await Promise.all([ - waitEvent(remoteBrowser1, 'disconnected'), - waitEvent(originalBrowser, 'disconnected'), - originalBrowser.close(), - ]); + await Promise.all([ + waitEvent(remoteBrowser1, 'disconnected'), + waitEvent(browser, 'disconnected'), + browser.close(), + ]); - expect(disconnectedOriginal).toBe(1); - expect(disconnectedRemote1).toBe(1); - expect(disconnectedRemote2).toBe(1); + expect(disconnectedOriginal).toBe(1); + expect(disconnectedRemote1).toBe(1); + expect(disconnectedRemote2).toBe(1); + } finally { + await close(); + } }); }); }); diff --git a/test/src/mocha-utils.ts b/test/src/mocha-utils.ts index fa96c182..0db93b00 100644 --- a/test/src/mocha-utils.ts +++ b/test/src/mocha-utils.ts @@ -364,47 +364,69 @@ export const createTimeout = ( }); }; -const browserCleanups: Array<() => Promise> = []; +let browserCleanups: Array<() => Promise> = []; export const launch = async ( - options: PuppeteerLaunchOptions + launchOptions: PuppeteerLaunchOptions, + options: { + createContext?: boolean; + createPage?: boolean; + } = {} ): Promise< PuppeteerTestState & { close: () => Promise; } > => { + const {createContext = true, createPage = true} = options; const close = async () => { let cleanup = browserCleanups.pop(); - while (cleanup) { - await cleanup(); - cleanup = browserCleanups.pop(); + try { + while (cleanup) { + await cleanup(); + cleanup = browserCleanups.pop(); + } + } catch (error) { + // If the browser was closed by other mean swallow the error + // and mark he browser as closed + if ((error as any)?.message.includes('Connection closed')) { + browserCleanups = []; + return; + } + + throw error; } }; try { const browser = await puppeteer.launch({ ...defaultBrowserOptions, - ...options, + ...launchOptions, }); browserCleanups.push(() => { return browser.close(); }); - const context = await browser.createIncognitoBrowserContext(); - browserCleanups.push(() => { - return context.close(); - }); + let context: BrowserContext; + let page: Page; + if (createContext) { + context = await browser.createIncognitoBrowserContext(); + browserCleanups.push(() => { + return context.close(); + }); - const page = await context.newPage(); - browserCleanups.push(() => { - return page.close(); - }); + if (createPage) { + page = await context.newPage(); + browserCleanups.push(() => { + return page.close(); + }); + } + } return { ...getTestState(), browser, - context, - page, + context: context!, + page: page!, close, }; } catch (error) { diff --git a/test/src/oopif.spec.ts b/test/src/oopif.spec.ts index 744b3108..9389f1a3 100644 --- a/test/src/oopif.spec.ts +++ b/test/src/oopif.spec.ts @@ -30,6 +30,7 @@ describeWithDebugLogs('OOPIF', function () { before(async () => { const {puppeteer, defaultBrowserOptions} = getTestState(); + // eslint-disable-next-line no-restricted-syntax browser = await puppeteer.launch( Object.assign({}, defaultBrowserOptions, { args: (defaultBrowserOptions.args || []).concat([ diff --git a/test/src/proxy.spec.ts b/test/src/proxy.spec.ts index de0e9f54..6688534f 100644 --- a/test/src/proxy.spec.ts +++ b/test/src/proxy.spec.ts @@ -21,9 +21,8 @@ import os from 'os'; import {TestServer} from '@pptr/testserver'; import expect from 'expect'; -import type {Browser} from 'puppeteer-core/internal/api/Browser.js'; -import {getTestState} from './mocha-utils.js'; +import {getTestState, launch} from './mocha-utils.js'; let HOSTNAME = os.hostname(); @@ -52,12 +51,13 @@ function getEmptyPageUrl(server: TestServer): string { } describe('request proxy', () => { - let browser: Browser; let proxiedRequestUrls: string[]; let proxyServer: Server; let proxyServerUrl: string; const defaultArgs = [ - '--disable-features=NetworkTimeServiceQuerying', // We disable this in tests so that proxy-related tests don't intercept queries from this service in headful. + // We disable this in tests so that proxy-related tests + // don't intercept queries from this service in headful. + '--disable-features=NetworkTimeServiceQuerying', ]; beforeEach(() => { @@ -97,8 +97,6 @@ describe('request proxy', () => { }); afterEach(async () => { - await browser.close(); - await new Promise((resolve, reject) => { proxyServer.close(error => { if (error) { @@ -111,27 +109,29 @@ describe('request proxy', () => { }); it('should proxy requests when configured', async () => { - const {puppeteer, defaultBrowserOptions, server} = getTestState(); + const {defaultBrowserOptions, server} = getTestState(); const emptyPageUrl = getEmptyPageUrl(server); - browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, args: [...defaultArgs, `--proxy-server=${proxyServerUrl}`], }); + try { + const page = await browser.newPage(); + const response = (await page.goto(emptyPageUrl))!; - const page = await browser.newPage(); - const response = (await page.goto(emptyPageUrl))!; - - expect(response.ok()).toBe(true); - - expect(proxiedRequestUrls).toEqual([emptyPageUrl]); + expect(response.ok()).toBe(true); + expect(proxiedRequestUrls).toEqual([emptyPageUrl]); + } finally { + await close(); + } }); it('should respect proxy bypass list', async () => { - const {puppeteer, defaultBrowserOptions, server} = getTestState(); + const {defaultBrowserOptions, server} = getTestState(); const emptyPageUrl = getEmptyPageUrl(server); - browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, args: [ ...defaultArgs, @@ -139,39 +139,43 @@ describe('request proxy', () => { `--proxy-bypass-list=${new URL(emptyPageUrl).host}`, ], }); + try { + const page = await browser.newPage(); + const response = (await page.goto(emptyPageUrl))!; - const page = await browser.newPage(); - const response = (await page.goto(emptyPageUrl))!; - - expect(response.ok()).toBe(true); - - expect(proxiedRequestUrls).toEqual([]); + expect(response.ok()).toBe(true); + expect(proxiedRequestUrls).toEqual([]); + } finally { + await close(); + } }); describe('in incognito browser context', () => { it('should proxy requests when configured at browser level', async () => { - const {puppeteer, defaultBrowserOptions, server} = getTestState(); + const {defaultBrowserOptions, server} = getTestState(); const emptyPageUrl = getEmptyPageUrl(server); - browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, args: [...defaultArgs, `--proxy-server=${proxyServerUrl}`], }); + try { + const context = await browser.createIncognitoBrowserContext(); + const page = await context.newPage(); + const response = (await page.goto(emptyPageUrl))!; - const context = await browser.createIncognitoBrowserContext(); - const page = await context.newPage(); - const response = (await page.goto(emptyPageUrl))!; - - expect(response.ok()).toBe(true); - - expect(proxiedRequestUrls).toEqual([emptyPageUrl]); + expect(response.ok()).toBe(true); + expect(proxiedRequestUrls).toEqual([emptyPageUrl]); + } finally { + await close(); + } }); it('should respect proxy bypass list when configured at browser level', async () => { - const {puppeteer, defaultBrowserOptions, server} = getTestState(); + const {defaultBrowserOptions, server} = getTestState(); const emptyPageUrl = getEmptyPageUrl(server); - browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, args: [ ...defaultArgs, @@ -179,58 +183,64 @@ describe('request proxy', () => { `--proxy-bypass-list=${new URL(emptyPageUrl).host}`, ], }); + try { + const context = await browser.createIncognitoBrowserContext(); + const page = await context.newPage(); + const response = (await page.goto(emptyPageUrl))!; - const context = await browser.createIncognitoBrowserContext(); - const page = await context.newPage(); - const response = (await page.goto(emptyPageUrl))!; - - expect(response.ok()).toBe(true); - - expect(proxiedRequestUrls).toEqual([]); + expect(response.ok()).toBe(true); + expect(proxiedRequestUrls).toEqual([]); + } finally { + await close(); + } }); /** * See issues #7873, #7719, and #7698. */ it('should proxy requests when configured at context level', async () => { - const {puppeteer, defaultBrowserOptions, server} = getTestState(); + const {defaultBrowserOptions, server} = getTestState(); const emptyPageUrl = getEmptyPageUrl(server); - browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, args: defaultArgs, }); + try { + const context = await browser.createIncognitoBrowserContext({ + proxyServer: proxyServerUrl, + }); + const page = await context.newPage(); + const response = (await page.goto(emptyPageUrl))!; - const context = await browser.createIncognitoBrowserContext({ - proxyServer: proxyServerUrl, - }); - const page = await context.newPage(); - const response = (await page.goto(emptyPageUrl))!; - - expect(response.ok()).toBe(true); - - expect(proxiedRequestUrls).toEqual([emptyPageUrl]); + expect(response.ok()).toBe(true); + expect(proxiedRequestUrls).toEqual([emptyPageUrl]); + } finally { + await close(); + } }); it('should respect proxy bypass list when configured at context level', async () => { - const {puppeteer, defaultBrowserOptions, server} = getTestState(); + const {defaultBrowserOptions, server} = getTestState(); const emptyPageUrl = getEmptyPageUrl(server); - browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, args: defaultArgs, }); + try { + const context = await browser.createIncognitoBrowserContext({ + proxyServer: proxyServerUrl, + proxyBypassList: [new URL(emptyPageUrl).host], + }); + const page = await context.newPage(); + const response = (await page.goto(emptyPageUrl))!; - const context = await browser.createIncognitoBrowserContext({ - proxyServer: proxyServerUrl, - proxyBypassList: [new URL(emptyPageUrl).host], - }); - const page = await context.newPage(); - const response = (await page.goto(emptyPageUrl))!; - - expect(response.ok()).toBe(true); - - expect(proxiedRequestUrls).toEqual([]); + expect(response.ok()).toBe(true); + expect(proxiedRequestUrls).toEqual([]); + } finally { + await close(); + } }); }); }); diff --git a/test/src/screenshot.spec.ts b/test/src/screenshot.spec.ts index f38d7ee8..c5e360a4 100644 --- a/test/src/screenshot.spec.ts +++ b/test/src/screenshot.spec.ts @@ -20,6 +20,7 @@ import { getTestState, setupTestBrowserHooks, setupTestPageAndContextHooks, + launch, } from './mocha-utils.js'; describe('Screenshots', function () { @@ -223,9 +224,9 @@ describe('Screenshots', function () { expect(screenshot).toBeGolden('screenshot-element-bounding-box.png'); }); it('should work with a null viewport', async () => { - const {defaultBrowserOptions, puppeteer, server} = getTestState(); + const {defaultBrowserOptions, server} = getTestState(); - const browser = await puppeteer.launch({ + const {browser, close} = await launch({ ...defaultBrowserOptions, defaultViewport: null, }); @@ -240,7 +241,7 @@ describe('Screenshots', function () { const screenshot = await elementHandle.screenshot(); expect(screenshot).toBeTruthy(); } finally { - await browser.close(); + await close(); } }); it('should take into account padding and border', async () => { diff --git a/test/src/tracing.spec.ts b/test/src/tracing.spec.ts index 13f16997..ad91b686 100644 --- a/test/src/tracing.spec.ts +++ b/test/src/tracing.spec.ts @@ -18,35 +18,30 @@ import fs from 'fs'; import path from 'path'; import expect from 'expect'; -import {Browser} from 'puppeteer-core/internal/api/Browser.js'; -import {Page} from 'puppeteer-core/internal/api/Page.js'; -import {getTestState} from './mocha-utils.js'; +import {getTestState, launch} from './mocha-utils.js'; describe('Tracing', function () { let outputFile!: string; - let browser!: Browser; - let page!: Page; + let testState: Awaited>; /* we manually manage the browser here as we want a new browser for each * individual test, which isn't the default behaviour of getTestState() */ - beforeEach(async () => { - const {defaultBrowserOptions, puppeteer} = getTestState(); - browser = await puppeteer.launch(defaultBrowserOptions); - page = await browser.newPage(); + const {defaultBrowserOptions} = getTestState(); + testState = await launch(defaultBrowserOptions); outputFile = path.join(__dirname, 'trace.json'); }); afterEach(async () => { - await browser.close(); + await testState.close(); if (fs.existsSync(outputFile)) { fs.unlinkSync(outputFile); } }); it('should output a trace', async () => { - const {server} = getTestState(); + const {server, page} = testState; await page.tracing.start({screenshots: true, path: outputFile}); await page.goto(server.PREFIX + '/grid.html'); @@ -55,6 +50,7 @@ describe('Tracing', function () { }); it('should run with custom categories if provided', async () => { + const {page} = testState; await page.tracing.start({ path: outputFile, categories: ['-*', 'disabled-by-default-devtools.timeline.frame'], @@ -77,6 +73,7 @@ describe('Tracing', function () { }); it('should run with default categories', async () => { + const {page} = testState; await page.tracing.start({ path: outputFile, }); @@ -92,6 +89,7 @@ describe('Tracing', function () { ); }); it('should throw if tracing on two pages', async () => { + const {page, browser} = testState; await page.tracing.start({path: outputFile}); const newPage = await browser.newPage(); let error!: Error; @@ -103,7 +101,7 @@ describe('Tracing', function () { await page.tracing.stop(); }); it('should return a buffer', async () => { - const {server} = getTestState(); + const {page, server} = testState; await page.tracing.start({screenshots: true, path: outputFile}); await page.goto(server.PREFIX + '/grid.html'); @@ -112,7 +110,7 @@ describe('Tracing', function () { expect(trace.toString()).toEqual(buf.toString()); }); it('should work without options', async () => { - const {server} = getTestState(); + const {page, server} = testState; await page.tracing.start(); await page.goto(server.PREFIX + '/grid.html'); @@ -121,7 +119,7 @@ describe('Tracing', function () { }); it('should return undefined in case of Buffer error', async () => { - const {server} = getTestState(); + const {page, server} = testState; await page.tracing.start({screenshots: true}); await page.goto(server.PREFIX + '/grid.html'); @@ -139,7 +137,7 @@ describe('Tracing', function () { }); it('should support a buffer without a path', async () => { - const {server} = getTestState(); + const {page, server} = testState; await page.tracing.start({screenshots: true}); await page.goto(server.PREFIX + '/grid.html'); @@ -148,6 +146,7 @@ describe('Tracing', function () { }); it('should properly fail if readProtocolStream errors out', async () => { + const {page} = testState; await page.tracing.start({path: __dirname}); let error!: Error;