chore: readd browser setup hook (#10478)

This commit is contained in:
Nikolay Vitkov 2023-07-03 14:01:29 +02:00 committed by GitHub
parent 87aaed4807
commit d0d738d2fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 320 additions and 177 deletions

View File

@ -17,10 +17,12 @@
import expect from 'expect';
import {isErrorLike} from 'puppeteer-core/internal/util/ErrorLike.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {waitEvent} from './utils.js';
describe('Target.createCDPSession', function () {
setupTestBrowserHooks();
it('should work', async () => {
const {page} = await getTestState();

View File

@ -22,7 +22,7 @@ import {attachFrame} from './utils.js';
describe('TargetManager', () => {
/* We use a special browser for this test as we need the --site-per-process flag */
let testState: Awaited<ReturnType<typeof launch>> & {
let state: Awaited<ReturnType<typeof launch>> & {
browser: CDPBrowser;
};
@ -30,7 +30,7 @@ describe('TargetManager', () => {
const {defaultBrowserOptions} = await getTestState({
skipLaunch: true,
});
testState = (await launch(
state = (await launch(
Object.assign({}, defaultBrowserOptions, {
args: (defaultBrowserOptions.args || []).concat([
'--site-per-process',
@ -45,11 +45,11 @@ describe('TargetManager', () => {
});
afterEach(async () => {
await testState.close();
await state.close();
});
it('should handle targets', async () => {
const {server, context, browser} = testState;
const {server, context, browser} = state;
const targetManager = browser._targetManager();
expect(targetManager.getAvailableTargets().size).toBe(2);

View File

@ -19,9 +19,11 @@ import assert from 'assert';
import expect from 'expect';
import {SerializedAXNode} from 'puppeteer-core/internal/common/Accessibility.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Accessibility', function () {
setupTestBrowserHooks();
it('should work', async () => {
const {page, isFirefox} = await getTestState();

View File

@ -20,10 +20,12 @@ import expect from 'expect';
import {TimeoutError} from 'puppeteer';
import type {ElementHandle} from 'puppeteer-core/internal/api/ElementHandle.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame, detachFrame} from './utils.js';
describe('AriaQueryHandler', () => {
setupTestBrowserHooks();
describe('parseAriaSelector', () => {
it('should find button', async () => {
const {page} = await getTestState();

View File

@ -16,9 +16,11 @@
import expect from 'expect';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Browser specs', function () {
setupTestBrowserHooks();
describe('Browser.version', function () {
it('should return version', async () => {
const {browser} = await getTestState();

View File

@ -17,10 +17,12 @@
import expect from 'expect';
import {TimeoutError} from 'puppeteer';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {waitEvent} from './utils.js';
describe('BrowserContext', function () {
setupTestBrowserHooks();
it('should have default context', async () => {
const {browser} = await getTestState({
skipContextCreation: true,
@ -240,7 +242,6 @@ describe('BrowserContext', function () {
expect(browser.browserContexts()[0]!.id).toBeUndefined();
const context = await browser.createIncognitoBrowserContext();
console.log('2');
expect(browser.browserContexts()).toHaveLength(2);
expect(browser.browserContexts()[1]!.id).toBeDefined();
await context.close();

View File

@ -16,10 +16,10 @@
import {IncomingMessage} from 'http';
import expect from 'expect';
import {Deferred} from 'puppeteer-core/internal/util/Deferred.js';
import {getTestState, launch} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks, launch} from './mocha-utils.js';
import {waitEvent} from './utils.js';
// TODO: rename this test suite to launch/connect test suite as it actually
// works across browsers.
describe('Chromium-Specific Launcher tests', function () {
@ -124,13 +124,19 @@ describe('Chromium-Specific Launcher tests', function () {
await close();
}
});
it('should fire "disconnected" when closing with pipe', async () => {
it('should fire "disconnected" when closing with pipe', async function () {
const {browser, close} = await launch({pipe: true});
try {
const disconnectedEventPromise = waitEvent(browser, 'disconnected');
// Emulate user exiting browser.
browser.process()!.kill();
await disconnectedEventPromise;
await Deferred.race([
disconnectedEventPromise,
Deferred.create({
message: `Failed in after Hook`,
timeout: this.timeout() - 1000,
}),
]);
} finally {
await close();
}
@ -139,6 +145,8 @@ describe('Chromium-Specific Launcher tests', function () {
});
describe('Chromium-Specific Page Tests', function () {
setupTestBrowserHooks();
it('Page.setRequestInterception should work with intervention headers', async () => {
const {server, page} = await getTestState();

View File

@ -17,10 +17,12 @@
import expect from 'expect';
import {KnownDevices} from 'puppeteer';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame} from './utils.js';
describe('Page.click', function () {
setupTestBrowserHooks();
it('should click the button', async () => {
const {page, server} = await getTestState();

View File

@ -15,9 +15,16 @@
*/
import expect from 'expect';
import {expectCookieEquals, getTestState, launch} from './mocha-utils.js';
import {
expectCookieEquals,
getTestState,
launch,
setupTestBrowserHooks,
} from './mocha-utils.js';
describe('Cookie specs', () => {
setupTestBrowserHooks();
describe('Page.cookies', function () {
it('should return no cookies in pristine browser context', async () => {
const {page, server} = await getTestState();

View File

@ -16,9 +16,11 @@
import expect from 'expect';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Coverage specs', function () {
setupTestBrowserHooks();
describe('JSCoverage', function () {
it('should work', async () => {
const {page, server} = await getTestState();
@ -269,7 +271,6 @@ describe('Coverage specs', function () {
await page.goto(server.PREFIX + '/csscoverage/media.html');
const coverage = await page.coverage.stopCSSCoverage();
expect(coverage).toHaveLength(1);
console.log(coverage);
expect(coverage[0]!.url).toContain('/csscoverage/media.html');
expect(coverage[0]!.ranges).toEqual([{start: 8, end: 40}]);
});

View File

@ -15,9 +15,15 @@
*/
import expect from 'expect';
import {expectCookieEquals, getTestState} from './mocha-utils.js';
import {
expectCookieEquals,
getTestState,
setupTestBrowserHooks,
} from './mocha-utils.js';
describe('DefaultBrowserContext', function () {
setupTestBrowserHooks();
it('page.cookies() should work', async () => {
const {page, server} = await getTestState();

View File

@ -16,9 +16,11 @@
import expect from 'expect';
import sinon from 'sinon';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Page.Events.Dialog', function () {
setupTestBrowserHooks();
it('should fire', async () => {
const {page} = await getTestState();

View File

@ -16,9 +16,11 @@
import expect from 'expect';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Input.drag', function () {
setupTestBrowserHooks();
it('should throw an exception if not enabled before usage', async () => {
const {page, server} = await getTestState();

View File

@ -21,11 +21,14 @@ import sinon from 'sinon';
import {
getTestState,
setupTestBrowserHooks,
shortWaitForArrayToHaveAtLeastNElements,
} from './mocha-utils.js';
import {attachFrame} from './utils.js';
describe('ElementHandle specs', function () {
setupTestBrowserHooks();
describe('ElementHandle.boundingBox', function () {
it('should work', async () => {
const {page, server} = await getTestState();

View File

@ -17,12 +17,14 @@
import expect from 'expect';
import {KnownDevices, PredefinedNetworkConditions} from 'puppeteer';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
const iPhone = KnownDevices['iPhone 6'];
const iPhoneLandscape = KnownDevices['iPhone 6 landscape'];
describe('Emulation', () => {
setupTestBrowserHooks();
describe('Page.viewport', function () {
it('should get the proper viewport size', async () => {
const {page} = await getTestState();

View File

@ -16,10 +16,12 @@
import expect from 'expect';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame} from './utils.js';
describe('Evaluation specs', function () {
setupTestBrowserHooks();
describe('Page.evaluate', function () {
it('should work', async () => {
const {page} = await getTestState();

View File

@ -20,10 +20,12 @@ import path from 'path';
import expect from 'expect';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {waitEvent} from './utils.js';
describe('Fixtures', function () {
setupTestBrowserHooks();
it('dumpio option should work with pipe option', async () => {
const {defaultBrowserOptions, puppeteerPath, headless} =
await getTestState();
@ -49,7 +51,6 @@ describe('Fixtures', function () {
await new Promise(resolve => {
return res.on('close', resolve);
});
console.log(dumpioData);
expect(dumpioData).toContain('message from dumpio');
});
it('should dump browser process stderr', async () => {

View File

@ -18,7 +18,7 @@ import expect from 'expect';
import {Frame} from 'puppeteer-core/internal/api/Frame.js';
import {CDPSession} from 'puppeteer-core/internal/common/Connection.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {
attachFrame,
detachFrame,
@ -28,6 +28,8 @@ import {
} from './utils.js';
describe('Frame specs', function () {
setupTestBrowserHooks();
describe('Frame.executionContext', function () {
it('should work', async () => {
const {page, server} = await getTestState();

View File

@ -18,9 +18,11 @@ import expect from 'expect';
import {ElementHandle} from 'puppeteer-core/internal/api/ElementHandle.js';
import {Page} from 'puppeteer-core/internal/api/Page.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Emulate idle state', () => {
setupTestBrowserHooks();
async function getIdleState(page: Page) {
const stateElement = (await page.$('#state')) as ElementHandle<HTMLElement>;
return await page.evaluate(element => {

View File

@ -17,48 +17,42 @@
import {TLSSocket} from 'tls';
import expect from 'expect';
import {Browser} from 'puppeteer-core/internal/api/Browser.js';
import {BrowserContext} from 'puppeteer-core/internal/api/BrowserContext.js';
import {HTTPResponse} from 'puppeteer-core/internal/api/HTTPResponse.js';
import {Page} from 'puppeteer-core/internal/api/Page.js';
import {getTestState} from './mocha-utils.js';
import {launch} from './mocha-utils.js';
describe('ignoreHTTPSErrors', function () {
/* Note that this test creates its own browser rather than use
* the one provided by the test set-up as we need one
* with ignoreHTTPSErrors set to true
*/
let browser!: Browser;
let context: BrowserContext;
let page!: Page;
let state: Awaited<ReturnType<typeof launch>>;
before(async () => {
const {defaultBrowserOptions, puppeteer} = await getTestState();
const options = Object.assign(
state = await launch(
{ignoreHTTPSErrors: true},
defaultBrowserOptions
{
after: 'all',
}
);
// eslint-disable-next-line no-restricted-syntax
browser = await puppeteer.launch(options);
});
after(async () => {
await browser.close();
await state.close();
});
beforeEach(async () => {
context = await browser.createIncognitoBrowserContext();
page = await context.newPage();
state.context = await state.browser.createIncognitoBrowserContext();
state.page = await state.context.newPage();
});
afterEach(async () => {
await context.close();
await state.context.close();
});
describe('Response.securityDetails', function () {
it('should work', async () => {
const {httpsServer} = await getTestState();
const {httpsServer, page} = state;
const [serverRequest, response] = await Promise.all([
httpsServer.waitForRequest('/empty.html'),
@ -79,13 +73,13 @@ describe('ignoreHTTPSErrors', function () {
]);
});
it('should be |null| for non-secure requests', async () => {
const {server} = await getTestState();
const {server, page} = state;
const response = (await page.goto(server.EMPTY_PAGE))!;
expect(response.securityDetails()).toBe(null);
});
it('Network redirects should report SecurityDetails', async () => {
const {httpsServer} = await getTestState();
const {httpsServer, page} = state;
httpsServer.setRedirect('/plzredirect', '/empty.html');
const responses: HTTPResponse[] = [];
@ -107,7 +101,7 @@ describe('ignoreHTTPSErrors', function () {
});
it('should work', async () => {
const {httpsServer} = await getTestState();
const {httpsServer, page} = state;
let error!: Error;
const response = await page.goto(httpsServer.EMPTY_PAGE).catch(error_ => {
@ -117,7 +111,7 @@ describe('ignoreHTTPSErrors', function () {
expect(response.ok()).toBe(true);
});
it('should work with request interception', async () => {
const {httpsServer} = await getTestState();
const {httpsServer, page} = state;
await page.setRequestInterception(true);
page.on('request', request => {
@ -127,7 +121,7 @@ describe('ignoreHTTPSErrors', function () {
expect(response.status()).toBe(200);
});
it('should work with mixed content', async () => {
const {server, httpsServer} = await getTestState();
const {server, httpsServer, page} = state;
httpsServer.setRoute('/mixedcontent.html', (_req, res) => {
res.end(`<iframe src=${server.EMPTY_PAGE}></iframe>`);

View File

@ -18,9 +18,11 @@ import expect from 'expect';
import {PUPPETEER_WORLD} from 'puppeteer-core/internal/common/IsolatedWorlds.js';
import {LazyArg} from 'puppeteer-core/internal/common/LazyArg.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('PuppeteerUtil tests', function () {
setupTestBrowserHooks();
it('should work', async () => {
const {page} = await getTestState();

View File

@ -19,12 +19,14 @@ import path from 'path';
import expect from 'expect';
import {TimeoutError} from 'puppeteer';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {waitEvent} from './utils.js';
const FILE_TO_UPLOAD = path.join(__dirname, '/../assets/file-to-upload.txt');
describe('input tests', function () {
setupTestBrowserHooks();
describe('input', function () {
it('should upload the file', async () => {
const {page, server} = await getTestState();

View File

@ -16,9 +16,11 @@
import expect from 'expect';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('JSHandle', function () {
setupTestBrowserHooks();
describe('Page.evaluateHandle', function () {
it('should work', async () => {
const {page} = await getTestState();
@ -158,6 +160,7 @@ describe('JSHandle', function () {
return new Date('2017-09-26T00:00:00.000Z');
});
const date = await dateHandle.jsonValue();
expect(date).toBeInstanceOf(Date);
expect(date.toISOString()).toEqual('2017-09-26T00:00:00.000Z');
});
it('should throw for circular objects', async () => {

View File

@ -19,10 +19,12 @@ import os from 'os';
import expect from 'expect';
import {KeyInput} from 'puppeteer-core/internal/common/USKeyboardLayout.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame} from './utils.js';
describe('Keyboard', function () {
setupTestBrowserHooks();
it('should type into a textarea', async () => {
const {page} = await getTestState();

View File

@ -574,7 +574,9 @@ describe('Launcher specs', function () {
...defaultBrowserOptions,
args: ['--no-startup-window'],
};
const {browser, close} = await launch(options, {createContext: false});
const {browser, close} = await launch(options, {
createContext: false,
});
try {
const pages = await browser.pages();
expect(pages).toHaveLength(0);

View File

@ -22,9 +22,11 @@ import {
} from 'puppeteer-core/internal/api/Locator.js';
import sinon from 'sinon';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Locator', function () {
setupTestBrowserHooks();
it('should work with a frame', async () => {
const {page} = await getTestState();

View File

@ -34,6 +34,7 @@ import {
PuppeteerNode,
} from 'puppeteer-core/internal/node/PuppeteerNode.js';
import {rmSync} from 'puppeteer-core/internal/node/util/fs.js';
import {Deferred} from 'puppeteer-core/internal/util/Deferred.js';
import {isErrorLike} from 'puppeteer-core/internal/util/ErrorLike.js';
import sinon from 'sinon';
@ -135,6 +136,22 @@ const setupServer = async () => {
return {server, httpsServer};
};
export const setupTestBrowserHooks = (): void => {
before(async function () {
try {
if (!state.browser) {
state.browser = await puppeteer.launch({
...processVariables.defaultBrowserOptions,
timeout: this.timeout() - 1_000,
});
}
} catch {
// Intentionally empty as `getTestState` will throw
// if browser is not found
}
});
};
export const getTestState = async (
options: {
skipLaunch?: boolean;
@ -147,25 +164,15 @@ export const getTestState = async (
JSON.stringify(processVariables.defaultBrowserOptions)
);
if (!state.puppeteer) {
const {server, httpsServer} = await setupServer();
state.server?.reset();
state.httpsServer?.reset();
state.puppeteer = puppeteer;
state.server = server;
state.httpsServer = httpsServer;
state.isFirefox = processVariables.isFirefox;
state.isChrome = processVariables.isChrome;
state.isHeadless = processVariables.isHeadless;
state.headless = processVariables.headless;
state.puppeteerPath = path.resolve(
path.join(__dirname, '..', '..', 'packages', 'puppeteer')
);
if (skipLaunch) {
return state as PuppeteerTestState;
}
if (!state.browser && !skipLaunch) {
state.browser = await puppeteer.launch(
processVariables.defaultBrowserOptions
);
if (!state.browser) {
throw new Error('Browser was not set-up in time!');
}
if (state.context) {
@ -174,14 +181,10 @@ export const getTestState = async (
state.page = undefined;
}
if (!skipLaunch && !skipContextCreation) {
if (!skipContextCreation) {
state.context = await state.browser!.createIncognitoBrowserContext();
state.page = await state.context.newPage();
}
state.server?.reset();
state.httpsServer?.reset();
return state as PuppeteerTestState;
};
@ -197,7 +200,7 @@ const setupGoldenAssertions = (): void => {
setupGoldenAssertions();
interface PuppeteerTestState {
export interface PuppeteerTestState {
browser: Browser;
context: BrowserContext;
page: Page;
@ -253,16 +256,53 @@ const browserNotClosedError = new Error(
'A manually launched browser was not closed!'
);
export const mochaHooks = {
async beforeAll(): Promise<void> {
const {server, httpsServer} = await setupServer();
state.puppeteer = puppeteer;
state.server = server;
state.httpsServer = httpsServer;
state.isFirefox = processVariables.isFirefox;
state.isChrome = processVariables.isChrome;
state.isHeadless = processVariables.isHeadless;
state.headless = processVariables.headless;
state.puppeteerPath = path.resolve(
path.join(__dirname, '..', '..', 'packages', 'puppeteer')
);
},
async afterAll(): Promise<void> {
await state.browser?.close();
await state.server?.stop();
await state.httpsServer?.stop();
(this as any).timeout(0);
const lastTestFile = (this as any)?.test?.parent?.suites?.[0]?.file
?.split('/')
?.at(-1);
try {
await Promise.all([
state.server?.stop(),
state.httpsServer?.stop(),
state.browser?.close(),
]);
} catch (error) {
throw new Error(
`Closing defaults (HTTP TestServer, HTTPS TestServer, Browser ) failed in ${lastTestFile}}`
);
}
if (browserCleanupsAfterAll.length > 0) {
await closeLaunched(browserCleanupsAfterAll)();
throw new Error(`Browser was not closed in ${lastTestFile}`);
}
},
async afterEach(): Promise<void> {
if (browserCleanups.length > 0) {
await closeLaunched();
(this as any).test.error(browserNotClosedError);
await Deferred.race([
closeLaunched(browserCleanups)(),
Deferred.create({
message: `Failed in after Hook`,
timeout: (this as any).timeout() - 1000,
}),
]);
}
sinon.restore();
},
@ -381,30 +421,34 @@ export const createTimeout = <T>(
});
};
let browserCleanups: Array<() => Promise<void>> = [];
const browserCleanupsAfterAll: Array<() => Promise<void>> = [];
const browserCleanups: Array<() => Promise<void>> = [];
const closeLaunched = async () => {
let 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;
}
const closeLaunched = (storage: Array<() => Promise<void>>) => {
return async () => {
let cleanup = storage.pop();
try {
while (cleanup) {
await cleanup();
cleanup = storage.pop();
}
} catch (error) {
// If the browser was closed by other means, swallow the error
// and mark the browser as closed.
if ((error as Error)?.message.includes('Connection closed')) {
storage.splice(0, storage.length);
return;
}
throw error;
}
throw error;
}
};
};
export const launch = async (
launchOptions: PuppeteerLaunchOptions,
options: {
after?: 'each' | 'all';
createContext?: boolean;
createPage?: boolean;
} = {}
@ -413,17 +457,18 @@ export const launch = async (
close: () => Promise<void>;
}
> => {
const {createContext = true, createPage = true} = options;
const {after = 'each', createContext = true, createPage = true} = options;
const initState = await getTestState({
skipLaunch: true,
});
const cleanupStorage =
after === 'each' ? browserCleanups : browserCleanupsAfterAll;
try {
const browser = await puppeteer.launch({
...initState.defaultBrowserOptions,
...launchOptions,
});
browserCleanups.push(() => {
cleanupStorage.push(() => {
return browser.close();
});
@ -431,13 +476,13 @@ export const launch = async (
let page: Page;
if (createContext) {
context = await browser.createIncognitoBrowserContext();
browserCleanups.push(() => {
cleanupStorage.push(() => {
return context.close();
});
if (createPage) {
page = await context.newPage();
browserCleanups.push(() => {
cleanupStorage.push(() => {
return page.close();
});
}
@ -448,10 +493,10 @@ export const launch = async (
browser,
context: context!,
page: page!,
close: closeLaunched,
close: closeLaunched(cleanupStorage),
};
} catch (error) {
await closeLaunched();
await closeLaunched(cleanupStorage)();
throw error;
}

View File

@ -20,7 +20,7 @@ import {MouseButton} from 'puppeteer-core/internal/api/Input.js';
import {Page} from 'puppeteer-core/internal/api/Page.js';
import {KeyInput} from 'puppeteer-core/internal/common/USKeyboardLayout.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
interface ClickData {
type: string;
@ -50,6 +50,8 @@ function dimensions(): Dimensions {
}
describe('Mouse', function () {
setupTestBrowserHooks();
it('should click the document', async () => {
const {page} = await getTestState();

View File

@ -19,11 +19,14 @@ import {ServerResponse} from 'http';
import expect from 'expect';
import {Frame, TimeoutError} from 'puppeteer';
import {HTTPRequest} from 'puppeteer-core/internal/api/HTTPRequest.js';
import {Deferred} from 'puppeteer-core/internal/util/Deferred.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame, isFavicon, waitEvent} from './utils.js';
describe('navigation', function () {
setupTestBrowserHooks();
describe('Page.goto', function () {
it('should work', async () => {
const {page, server} = await getTestState();
@ -702,7 +705,7 @@ describe('navigation', function () {
server.setRoute('/frames/style.css', () => {});
let frame: Frame | undefined;
let timeout: NodeJS.Timeout | undefined;
const eventPromises = Promise.race([
const eventPromises = Deferred.race([
Promise.all([
waitEvent(page, 'frameattached').then(_frame => {
return (frame = _frame);
@ -711,10 +714,9 @@ describe('navigation', function () {
return f === frame;
}),
]),
new Promise((_, rej) => {
timeout = setTimeout(() => {
return rej(new Error('Timeout'));
}, this.timeout());
Deferred.create({
message: `should work when subframe issues window.stop()`,
timeout: this.timeout() - 1000,
}),
]);
const navigationPromise = page.goto(

View File

@ -22,10 +22,12 @@ import expect from 'expect';
import {HTTPRequest} from 'puppeteer-core/internal/api/HTTPRequest.js';
import {HTTPResponse} from 'puppeteer-core/internal/api/HTTPResponse.js';
import {getTestState, launch} from './mocha-utils.js';
import {getTestState, launch, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame, isFavicon, waitEvent} from './utils.js';
describe('network', function () {
setupTestBrowserHooks();
describe('Page.Events.Request', function () {
it('should fire for navigation requests', async () => {
const {page, server} = await getTestState();

View File

@ -15,48 +15,45 @@
*/
import expect from 'expect';
import {Browser} from 'puppeteer-core/internal/api/Browser.js';
import {BrowserContext} from 'puppeteer-core/internal/api/BrowserContext.js';
import {Page} from 'puppeteer-core/internal/api/Page.js';
import {describeWithDebugLogs, getTestState} from './mocha-utils.js';
import {describeWithDebugLogs, getTestState, launch} from './mocha-utils.js';
import {attachFrame, detachFrame, navigateFrame} from './utils.js';
describeWithDebugLogs('OOPIF', function () {
/* We use a special browser for this test as we need the --site-per-process flag */
let browser: Browser;
let context: BrowserContext;
let page: Page;
let state: Awaited<ReturnType<typeof launch>>;
before(async () => {
const {puppeteer, defaultBrowserOptions} = await getTestState();
// eslint-disable-next-line no-restricted-syntax
browser = await puppeteer.launch(
const {defaultBrowserOptions} = await getTestState({skipLaunch: true});
state = await launch(
Object.assign({}, defaultBrowserOptions, {
args: (defaultBrowserOptions.args || []).concat([
'--site-per-process',
'--remote-debugging-port=21222',
'--host-rules=MAP * 127.0.0.1',
]),
})
}),
{after: 'all'}
);
});
beforeEach(async () => {
context = await browser.createIncognitoBrowserContext();
page = await context.newPage();
state.context = await state.browser.createIncognitoBrowserContext();
state.page = await state.context.newPage();
});
afterEach(async () => {
await context.close();
await state.context.close();
});
after(async () => {
await browser.close();
await state.close();
});
it('should treat OOP iframes and normal iframes the same', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
@ -72,7 +69,7 @@ describeWithDebugLogs('OOPIF', function () {
expect(page.mainFrame().childFrames()).toHaveLength(2);
});
it('should track navigations within OOP iframes', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
@ -93,7 +90,7 @@ describeWithDebugLogs('OOPIF', function () {
expect(frame.url()).toContain('/assets/frame.html');
});
it('should support OOP iframes becoming normal iframes again', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
@ -114,7 +111,7 @@ describeWithDebugLogs('OOPIF', function () {
expect(page.frames()).toHaveLength(2);
});
it('should support frames within OOP frames', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const frame1Promise = page.waitForFrame(frame => {
@ -143,7 +140,7 @@ describeWithDebugLogs('OOPIF', function () {
).toMatch(/frames\/frame\.html$/);
});
it('should support OOP iframes getting detached', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
@ -164,7 +161,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('should support wait for navigation for transitions from local to OOPIF', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
@ -187,7 +184,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('should keep track of a frames OOP state', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
@ -205,7 +202,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('should support evaluating in oop iframes', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
@ -230,7 +227,7 @@ describeWithDebugLogs('OOPIF', function () {
expect(result).toBe('Test 123!');
});
it('should provide access to elements', async () => {
const {server, isHeadless, headless} = await getTestState();
const {server, isHeadless, headless, page} = state;
if (!isHeadless || headless === 'new') {
// TODO: this test is partially blocked on crbug.com/1334119. Enable test once
@ -276,7 +273,7 @@ describeWithDebugLogs('OOPIF', function () {
await frame.waitForSelector('#clicked');
});
it('should report oopif frames', async () => {
const {server} = await getTestState();
const {server, page, context} = state;
const frame = page.waitForFrame(frame => {
return frame.url().endsWith('/oopif.html');
@ -288,7 +285,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('should wait for inner OOPIFs', async () => {
const {server} = await getTestState();
const {server, page, context} = state;
await page.goto(`http://mainframe:${server.PORT}/main-frame.html`);
const frame2 = await page.waitForFrame(frame => {
return frame.url().endsWith('inner-frame2.html');
@ -307,7 +304,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('should load oopif iframes with subresources and request interception', async () => {
const {server} = await getTestState();
const {server, page, context} = state;
const frame = page.waitForFrame(frame => {
return frame.url().endsWith('/oopif.html');
@ -321,7 +318,7 @@ describeWithDebugLogs('OOPIF', function () {
expect(oopifs(context)).toHaveLength(1);
});
it('should support frames within OOP iframes', async () => {
const {server} = await getTestState();
const {server, page} = state;
const oopIframePromise = page.waitForFrame(frame => {
return frame.url().endsWith('/oopif.html');
@ -352,7 +349,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
const framePromise = page.waitForFrame(frame => {
return page.frames().indexOf(frame) === 1;
@ -398,7 +395,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('should detect existing OOPIFs when Puppeteer connects to an existing page', async () => {
const {server, puppeteer} = await getTestState();
const {server, puppeteer, page, context} = state;
const frame = page.waitForFrame(frame => {
return frame.url().endsWith('/oopif.html');
@ -418,7 +415,7 @@ describeWithDebugLogs('OOPIF', function () {
});
it('should support lazy OOP frames', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.PREFIX + '/lazy-oopif-frame.html');
await page.setViewport({width: 1000, height: 1000});
@ -432,7 +429,7 @@ describeWithDebugLogs('OOPIF', function () {
describe('waitForFrame', () => {
it('should resolve immediately if the frame already exists', async () => {
const {server} = await getTestState();
const {server, page} = state;
await page.goto(server.EMPTY_PAGE);
await attachFrame(

View File

@ -25,10 +25,12 @@ import {ConsoleMessage} from 'puppeteer-core/internal/common/ConsoleMessage.js';
import {CDPPage} from 'puppeteer-core/internal/common/Page.js';
import sinon from 'sinon';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame, detachFrame, isFavicon, waitEvent} from './utils.js';
describe('Page', function () {
setupTestBrowserHooks();
describe('Page.close', function () {
it('should reject all promises when page is closed', async () => {
const {context} = await getTestState();

View File

@ -19,9 +19,11 @@ import expect from 'expect';
import {Puppeteer} from 'puppeteer-core';
import {ElementHandle} from 'puppeteer-core/internal/api/ElementHandle.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Query handler tests', function () {
setupTestBrowserHooks();
describe('Pierce selectors', function () {
async function setUpPage(): ReturnType<typeof getTestState> {
const state = await getTestState();

View File

@ -17,9 +17,11 @@ import expect from 'expect';
import {Puppeteer} from 'puppeteer';
import type {CustomQueryHandler} from 'puppeteer-core/internal/common/CustomQueryHandler.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('querySelector', function () {
setupTestBrowserHooks();
describe('Page.$eval', function () {
it('should work', async () => {
const {page} = await getTestState();

View File

@ -25,10 +25,12 @@ import {
} from 'puppeteer-core/internal/api/HTTPRequest.js';
import {ConsoleMessage} from 'puppeteer-core/internal/common/ConsoleMessage.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {isFavicon, waitEvent} from './utils.js';
describe('request interception', function () {
setupTestBrowserHooks();
describe('Page.setRequestInterception', function () {
const expectedActions: ActionResult[] = ['abort', 'continue', 'respond'];
while (expectedActions.length > 0) {

View File

@ -21,10 +21,12 @@ import expect from 'expect';
import {HTTPRequest} from 'puppeteer-core/internal/api/HTTPRequest.js';
import {ConsoleMessage} from 'puppeteer-core/internal/common/ConsoleMessage.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {isFavicon, waitEvent} from './utils.js';
describe('request interception', function () {
setupTestBrowserHooks();
describe('Page.setRequestInterception', function () {
it('should intercept', async () => {
const {page, server} = await getTestState();

View File

@ -16,9 +16,11 @@
import expect from 'expect';
import {getTestState, launch} from './mocha-utils.js';
import {getTestState, launch, setupTestBrowserHooks} from './mocha-utils.js';
describe('Screenshots', function () {
setupTestBrowserHooks();
describe('Page.screenshot', function () {
it('should work', async () => {
const {page, server} = await getTestState();

View File

@ -18,12 +18,19 @@ import assert from 'assert';
import expect from 'expect';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {waitEvent} from './utils.js';
const FILENAME = __filename.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
const parseStackTrace = (stack: string): string => {
stack = stack.replace(new RegExp(FILENAME, 'g'), '<filename>');
stack = stack.replace(/<filename>:(\d+):(\d+)/g, '<filename>:<line>:<col>');
return stack;
};
describe('Stack trace', function () {
setupTestBrowserHooks();
it('should work', async () => {
const {page} = await getTestState();
@ -39,10 +46,12 @@ describe('Stack trace', function () {
expect(error.message).toEqual('Test');
assert(error.stack);
error.stack = error.stack.replace(new RegExp(FILENAME, 'g'), '<filename>');
expect(error.stack.split('\n at ').slice(0, 2)).toMatchObject({
expect(
parseStackTrace(error.stack).split('\n at ').slice(0, 2)
).toMatchObject({
...[
'Error: Test',
'evaluate (evaluate at Context.<anonymous> (<filename>:30:14), <anonymous>:1:18)',
'evaluate (evaluate at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:1:18)',
],
});
});
@ -61,11 +70,12 @@ describe('Stack trace', function () {
expect(error.name).toEqual('Error');
expect(error.message).toEqual('Test');
assert(error.stack);
error.stack = error.stack.replace(new RegExp(FILENAME, 'g'), '<filename>');
expect(error.stack.split('\n at ').slice(0, 2)).toMatchObject({
expect(
parseStackTrace(error.stack).split('\n at ').slice(0, 2)
).toMatchObject({
...[
'Error: Test',
'evaluateHandle (evaluateHandle at Context.<anonymous> (<filename>:50:14), <anonymous>:1:18)',
'evaluateHandle (evaluateHandle at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:1:18)',
],
});
});
@ -89,12 +99,13 @@ describe('Stack trace', function () {
expect(error.name).toEqual('Error');
expect(error.message).toEqual('Test');
assert(error.stack);
error.stack = error.stack.replace(new RegExp(FILENAME, 'g'), '<filename>');
expect(error.stack.split('\n at ').slice(0, 3)).toMatchObject({
expect(
parseStackTrace(error.stack).split('\n at ').slice(0, 3)
).toMatchObject({
...[
'Error: Test',
'evaluateHandle (evaluateHandle at Context.<anonymous> (<filename>:69:36), <anonymous>:2:22)',
'evaluate (evaluate at Context.<anonymous> (<filename>:75:14), <anonymous>:1:12)',
'evaluateHandle (evaluateHandle at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:2:22)',
'evaluate (evaluate at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:1:12)',
],
});
});
@ -125,15 +136,16 @@ describe('Stack trace', function () {
expect(error.name).toEqual('Error');
expect(error.message).toEqual('Test');
assert(error.stack);
error.stack = error.stack.replace(new RegExp(FILENAME, 'g'), '<filename>');
expect(error.stack.split('\n at ').slice(0, 6)).toMatchObject({
expect(
parseStackTrace(error.stack).split('\n at ').slice(0, 6)
).toMatchObject({
...[
'Error: Test',
'a (evaluate at Context.<anonymous> (<filename>:96:14), <anonymous>:2:22)',
'b (evaluate at Context.<anonymous> (<filename>:96:14), <anonymous>:5:16)',
'c (evaluate at Context.<anonymous> (<filename>:96:14), <anonymous>:8:16)',
'd (evaluate at Context.<anonymous> (<filename>:96:14), <anonymous>:11:16)',
'evaluate (evaluate at Context.<anonymous> (<filename>:96:14), <anonymous>:13:12)',
'a (evaluate at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:2:22)',
'b (evaluate at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:5:16)',
'c (evaluate at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:8:16)',
'd (evaluate at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:11:16)',
'evaluate (evaluate at Context.<anonymous> (<filename>:<line>:<col>), <anonymous>:13:12)',
],
});
});

View File

@ -21,10 +21,12 @@ import {TimeoutError} from 'puppeteer';
import {Page} from 'puppeteer-core/internal/api/Page.js';
import {Target} from 'puppeteer-core/internal/common/Target.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {waitEvent} from './utils.js';
describe('Target', function () {
setupTestBrowserHooks();
it('Browser.targets should return all of the targets', async () => {
const {browser} = await getTestState();

View File

@ -17,9 +17,11 @@
import expect from 'expect';
import {KnownDevices, BoundingBox} from 'puppeteer';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Touchscreen', function () {
setupTestBrowserHooks();
it('should tap the button', async () => {
const {page, server} = await getTestState();
const iPhone = KnownDevices['iPhone 6']!;

View File

@ -18,10 +18,16 @@ import expect from 'expect';
import {TimeoutError, ElementHandle} from 'puppeteer';
import {isErrorLike} from 'puppeteer-core/internal/util/ErrorLike.js';
import {createTimeout, getTestState} from './mocha-utils.js';
import {
createTimeout,
getTestState,
setupTestBrowserHooks,
} from './mocha-utils.js';
import {attachFrame, detachFrame} from './utils.js';
describe('waittask specs', function () {
setupTestBrowserHooks();
describe('Frame.waitForFunction', function () {
it('should accept a string', async () => {
const {page} = await getTestState();

View File

@ -18,10 +18,12 @@ import expect from 'expect';
import {ConsoleMessage} from 'puppeteer-core/internal/common/ConsoleMessage.js';
import {WebWorker} from 'puppeteer-core/internal/common/WebWorker.js';
import {getTestState} from './mocha-utils.js';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {waitEvent} from './utils.js';
describe('Workers', function () {
setupTestBrowserHooks();
it('Page.workers', async () => {
const {page, server} = await getTestState();

View File

@ -135,12 +135,6 @@ export function getExpectationUpdates(
const output: Map<string, RecommendedExpectation> = new Map();
for (const pass of results.passes) {
// If an error occurs during a hook
// the error not have a file associated with it
if (!pass.file) {
continue;
}
const expectationEntry = findEffectiveExpectationForTest(
expectations,
pass
@ -171,6 +165,15 @@ export function getExpectationUpdates(
// If an error occurs during a hook
// the error not have a file associated with it
if (!failure.file) {
addEntry({
expectation: {
testIdPattern: 'Hook failed!',
platforms: context.platforms,
parameters: context.parameters,
expectations: [],
},
action: 'add',
});
continue;
}