From 4c3bd11820665274071ee24663a58594a0b34b94 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Sun, 16 May 2021 19:58:26 -0700 Subject: [PATCH] test: roll to folio@0.4.0-alpha14 (#6602) --- package-lock.json | 18 +-- package.json | 2 +- tests/android/androidTest.ts | 68 ++++---- tests/browsercontext-proxy.spec.ts | 2 +- tests/chromium/oopif.spec.ts | 2 +- tests/config/android.config.ts | 33 +--- tests/config/baseTest.ts | 205 +++++++++++------------ tests/config/browserTest.ts | 243 +++++++++++++--------------- tests/config/default.config.ts | 64 ++------ tests/config/electron.config.ts | 27 +--- tests/electron/electronTest.ts | 91 +++++------ tests/inspector/inspectorTest.ts | 52 +++--- tests/page/page-event-crash.spec.ts | 29 ++-- tests/page/pageTest.ts | 4 +- tests/snapshotter.spec.ts | 31 ++-- tests/tap.spec.ts | 2 +- tests/tracing.spec.ts | 32 ++-- 17 files changed, 398 insertions(+), 507 deletions(-) diff --git a/package-lock.json b/package-lock.json index 65832f4246..39c4b33ce9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2659,9 +2659,9 @@ } }, "electron-to-chromium": { - "version": "1.3.727", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.727.tgz", - "integrity": "sha512-Mfz4FIB4FSvEwBpDfdipRIrwd6uo8gUDoRDF4QEYb4h4tSuI3ov594OrjU6on042UlFHouIJpClDODGkPcBSbg==", + "version": "1.3.728", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.728.tgz", + "integrity": "sha512-SHv4ziXruBpb1Nz4aTuqEHBYi/9GNCJMYIJgDEXrp/2V01nFXMNFUTli5Z85f5ivSkioLilQatqBYFB44wNJrA==", "dev": true }, "elliptic": { @@ -3483,9 +3483,9 @@ } }, "folio": { - "version": "0.4.0-alpha13", - "resolved": "https://registry.npmjs.org/folio/-/folio-0.4.0-alpha13.tgz", - "integrity": "sha512-ujrTuD4bSY3jNB2QVf5B2JSZFz2PNtNR0LIIbD+o4vCNutU9IAK0vn1WAiM5uLMt47CadAuFEb7260nanrTCcw==", + "version": "0.4.0-alpha14", + "resolved": "https://registry.npmjs.org/folio/-/folio-0.4.0-alpha14.tgz", + "integrity": "sha512-rQdHvFmczTtMFy2mlBRWMX6keC1Dd0bfJzF3NfU/H9JcYrU9zv6TuXiN662hC7Z+aky14JpIRNawwg+FVi1Bog==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", @@ -5152,9 +5152,9 @@ "dev": true }, "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", "dev": true }, "node-stream-zip": { diff --git a/package.json b/package.json index 815d5de143..f0a220220c 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "eslint-plugin-notice": "^0.9.10", "eslint-plugin-react-hooks": "^4.2.0", "file-loader": "^6.1.0", - "folio": "=0.4.0-alpha13", + "folio": "=0.4.0-alpha14", "formidable": "^1.2.2", "html-webpack-plugin": "^4.4.1", "ncp": "^2.0.0", diff --git a/tests/android/androidTest.ts b/tests/android/androidTest.ts index fdda9f4cf7..edd8c4ff30 100644 --- a/tests/android/androidTest.ts +++ b/tests/android/androidTest.ts @@ -14,48 +14,60 @@ * limitations under the License. */ -import type { AndroidDevice } from '../../index'; -import { CommonArgs, baseTest } from '../config/baseTest'; +import type { AndroidDevice, BrowserContext } from '../../index'; +import { CommonWorkerFixtures, baseTest } from '../config/baseTest'; import * as folio from 'folio'; +import { PageTestFixtures } from '../page/pageTest'; export { expect } from 'folio'; -type AndroidTestArgs = { +type AndroidWorkerFixtures = { androidDevice: AndroidDevice; }; -export class AndroidEnv { - protected _device?: AndroidDevice; - protected _browserVersion: string; - protected _browserMajorVersion: number; +export const androidFixtures: folio.Fixtures = { + androidDevice: [ async ({ playwright }, run) => { + const device = (await playwright._android.devices())[0]; + await device.shell('am force-stop org.chromium.webview_shell'); + await device.shell('am force-stop com.android.chrome'); + device.setDefaultTimeout(90000); + await run(device); + await device.close(); + }, { scope: 'worker' } ], - async beforeAll(args: CommonArgs, workerInfo: folio.WorkerInfo) { - this._device = (await args.playwright._android.devices())[0]; - await this._device.shell('am force-stop org.chromium.webview_shell'); - await this._device.shell('am force-stop com.android.chrome'); - this._browserVersion = (await this._device.shell('dumpsys package com.android.chrome')) + browserVersion: async ({ androidDevice }, run) => { + const browserVersion = (await androidDevice.shell('dumpsys package com.android.chrome')) .toString('utf8') .split('\n') .find(line => line.includes('versionName=')) .trim() .split('=')[1]; - this._browserMajorVersion = Number(this._browserVersion.split('.')[0]); - this._device.setDefaultTimeout(90000); - } + await run(browserVersion); + }, - async beforeEach({}, testInfo: folio.TestInfo): Promise { + browserMajorVersion: async ({ browserVersion }, run) => { + await run(Number(browserVersion.split('.')[0])); + }, + + isAndroid: true, + isElectron: false, + + __androidSetup: [ async ({ browserVersion }, run, testInfo) => { testInfo.data.platform = 'Android'; testInfo.data.headful = true; - testInfo.data.browserVersion = this._browserVersion; - return { - androidDevice: this._device!, - }; - } + testInfo.data.browserVersion = browserVersion; + await run(); + }, { auto: true } ], - async afterAll({}, workerInfo: folio.WorkerInfo) { - if (this._device) - await this._device.close(); - this._device = undefined; - } -} + androidContext: [ async ({ androidDevice }, run) => { + await run(await androidDevice.launchBrowser()); + }, { scope: 'worker' } ], -export const androidTest = baseTest.extend(new AndroidEnv()); + page: async ({ androidContext }, run) => { + const page = await androidContext.newPage(); + await run(page); + for (const page of androidContext.pages()) + await page.close(); + }, +}; + +export const androidTest = baseTest.extend(androidFixtures as any); diff --git a/tests/browsercontext-proxy.spec.ts b/tests/browsercontext-proxy.spec.ts index c0a8b06051..e51e58b642 100644 --- a/tests/browsercontext-proxy.spec.ts +++ b/tests/browsercontext-proxy.spec.ts @@ -16,7 +16,7 @@ import { browserTest as it, expect } from './config/browserTest'; -it.useOptions({ proxy: { server: 'per-context' } }); +it.use({ proxy: { server: 'per-context' } }); it('should throw for missing global proxy on Chromium Windows', async ({ browserName, platform, browserType, browserOptions, server }) => { it.skip(browserName !== 'chromium' || platform !== 'win32'); diff --git a/tests/chromium/oopif.spec.ts b/tests/chromium/oopif.spec.ts index 4e57914867..9b1b23a2b9 100644 --- a/tests/chromium/oopif.spec.ts +++ b/tests/chromium/oopif.spec.ts @@ -16,7 +16,7 @@ import { contextTest as it, expect } from '../config/browserTest'; -it.useOptions({ args: ['--site-per-process'] }); +it.use({ args: ['--site-per-process'] }); it('should report oopif frames', async function({page, browser, server}) { await page.goto(server.PREFIX + '/dynamic-oopif.html'); diff --git a/tests/config/android.config.ts b/tests/config/android.config.ts index 24cfd2f9c6..ff574ae39c 100644 --- a/tests/config/android.config.ts +++ b/tests/config/android.config.ts @@ -17,34 +17,13 @@ import * as folio from 'folio'; import * as path from 'path'; import { test as pageTest } from '../page/pageTest'; -import { AndroidEnv } from '../android/androidTest'; -import type { BrowserContext } from '../../index'; -import { PlaywrightEnvOptions } from './browserTest'; +import { androidFixtures } from '../android/androidTest'; +import { PlaywrightOptions } from './browserTest'; import { CommonOptions } from './baseTest'; -class AndroidPageEnv extends AndroidEnv { - private _context?: BrowserContext; - - async beforeAll(args: any, workerInfo: folio.WorkerInfo) { - await super.beforeAll(args, workerInfo); - this._context = await this._device!.launchBrowser(); - } - - async beforeEach(args: any, testInfo: folio.TestInfo) { - const result = await super.beforeEach(args, testInfo); - const page = await this._context!.newPage(); - return { ...result, browserVersion: this._browserVersion, browserMajorVersion: this._browserMajorVersion, page, isAndroid: true, isElectron: false }; - } - - async afterEach({}, testInfo: folio.TestInfo) { - for (const page of this._context!.pages()) - await page.close(); - } -} - const outputDir = path.join(__dirname, '..', '..', 'test-results'); const testDir = path.join(__dirname, '..'); -const config: folio.Config = { +const config: folio.Config = { testDir, snapshotDir: '__snapshots__', outputDir, @@ -62,7 +41,7 @@ const config: folio.Config = { config.projects.push({ name: 'android', - options: { + use: { loopback: '10.0.2.2', mode: 'default', browserName: 'chromium', @@ -72,13 +51,13 @@ config.projects.push({ config.projects.push({ name: 'android', - options: { + use: { loopback: '10.0.2.2', mode: 'default', browserName: 'chromium', }, testDir: path.join(testDir, 'page'), - define: { test: pageTest, env: new AndroidPageEnv() }, + define: { test: pageTest, fixtures: androidFixtures }, }); export default config; diff --git a/tests/config/baseTest.ts b/tests/config/baseTest.ts index 4b1ad8356a..79c11a456d 100644 --- a/tests/config/baseTest.ts +++ b/tests/config/baseTest.ts @@ -23,17 +23,18 @@ import { installCoverageHooks } from './coverage'; import * as childProcess from 'child_process'; import { start } from '../../lib/outofprocess'; import { PlaywrightClient } from '../../lib/remote/playwrightClient'; +import type { LaunchOptions } from '../../index'; export type BrowserName = 'chromium' | 'firefox' | 'webkit'; type Mode = 'default' | 'driver' | 'service'; type BaseOptions = { mode: Mode; browserName: BrowserName; - channel?: string; - video?: boolean; - headless?: boolean; + channel: LaunchOptions['channel']; + video: boolean | undefined; + headless: boolean | undefined; }; -type BaseWorkerArgs = { +type BaseFixtures = { platform: 'win32' | 'darwin' | 'linux'; playwright: typeof import('../../index'); toImpl: (rpcObject: any) => any; @@ -45,7 +46,7 @@ type BaseWorkerArgs = { class DriverMode { private _playwrightObject: any; - async setup(workerInfo: folio.WorkerInfo) { + async setup(workerIndex: number) { this._playwrightObject = await start(); return this._playwrightObject; } @@ -60,8 +61,8 @@ class ServiceMode { private _client: any; private _serviceProcess: childProcess.ChildProcess; - async setup(workerInfo: folio.WorkerInfo) { - const port = 10507 + workerInfo.workerIndex; + async setup(workerIndex: number) { + const port = 10507 + workerIndex; this._serviceProcess = childProcess.fork(path.join(__dirname, '..', '..', 'lib', 'cli', 'cli.js'), ['run-server', String(port)], { stdio: 'pipe' }); @@ -92,7 +93,7 @@ class ServiceMode { } class DefaultMode { - async setup(workerInfo: folio.WorkerInfo) { + async setup(workerIndex: number) { return require('../../index'); } @@ -100,85 +101,67 @@ class DefaultMode { } } -class BaseEnv { - private _mode: DriverMode | ServiceMode | DefaultMode; - private _options: BaseOptions; - private _playwright: typeof import('../../index'); - - hasBeforeAllOptions(options: BaseOptions) { - return 'mode' in options || 'browserName' in options || 'channel' in options || 'video' in options || 'headless' in options; - } - - async beforeAll(options: BaseOptions, workerInfo: folio.WorkerInfo): Promise { - this._options = options; - this._mode = { +const baseFixtures: folio.Fixtures<{ __baseSetup: void }, BaseOptions & BaseFixtures> = { + mode: [ 'default', { scope: 'worker' } ], + browserName: [ 'chromium' , { scope: 'worker' } ], + channel: [ undefined, { scope: 'worker' } ], + video: [ undefined, { scope: 'worker' } ], + headless: [ undefined, { scope: 'worker' } ], + platform: [ process.platform as 'win32' | 'darwin' | 'linux', { scope: 'worker' } ], + playwright: [ async ({ mode }, run, workerInfo) => { + const modeImpl = { default: new DefaultMode(), service: new ServiceMode(), driver: new DriverMode(), - }[this._options.mode]; + }[mode]; require('../../lib/utils/utils').setUnderTest(); - this._playwright = await this._mode.setup(workerInfo); - return { - playwright: this._playwright, - isWindows: process.platform === 'win32', - isMac: process.platform === 'darwin', - isLinux: process.platform === 'linux', - platform: process.platform as ('win32' | 'darwin' | 'linux'), - toImpl: (this._playwright as any)._toImpl, - }; - } - - async beforeEach({}, testInfo: folio.TestInfo) { - testInfo.snapshotPathSegment = this._options.browserName; - testInfo.data = { browserName: this._options.browserName }; - if (!this._options.headless) + const playwright = await modeImpl.setup(workerInfo.workerIndex); + await run(playwright); + await modeImpl.teardown(); + }, { scope: 'worker' } ], + toImpl: [ async ({ playwright }, run) => run((playwright as any)._toImpl), { scope: 'worker' } ], + isWindows: [ process.platform === 'win32', { scope: 'worker' } ], + isMac: [ process.platform === 'darwin', { scope: 'worker' } ], + isLinux: [ process.platform === 'linux', { scope: 'worker' } ], + __baseSetup: [ async ({ browserName, headless, mode, video }, run, testInfo) => { + testInfo.snapshotPathSegment = browserName; + testInfo.data = { browserName }; + if (!headless) testInfo.data.headful = true; - if (this._options.mode !== 'default') - testInfo.data.mode = this._options.mode; - if (this._options.video) + if (mode !== 'default') + testInfo.data.mode = mode; + if (video) testInfo.data.video = true; - return {}; - } - - async afterAll({}, workerInfo: folio.WorkerInfo) { - await this._mode.teardown(); - } -} - -type ServerWorkerArgs = { - asset: (path: string) => string; - socksPort: number; - server: TestServer; - httpsServer: TestServer; + await run(); + }, { auto: true } ], }; type ServerOptions = { loopback?: string; }; +type ServerFixtures = { + server: TestServer; + httpsServer: TestServer; + socksPort: number; + asset: (p: string) => string; +}; -class ServerEnv { - private _server: TestServer; - private _httpsServer: TestServer; - private _socksServer: any; - private _socksPort: number; - - hasBeforeAllOptions(options: ServerOptions) { - return 'loopback' in options; - } - - async beforeAll(options: ServerOptions, workerInfo: folio.WorkerInfo) { +type ServersInternal = ServerFixtures & { socksServer: any }; +const serverFixtures: folio.Fixtures = { + loopback: [ undefined, { scope: 'worker' } ], + __servers: [ async ({ loopback }, run, workerInfo) => { const assetsPath = path.join(__dirname, '..', 'assets'); const cachedPath = path.join(__dirname, '..', 'assets', 'cached'); const port = 8907 + workerInfo.workerIndex * 3; - this._server = await TestServer.create(assetsPath, port, options.loopback); - this._server.enableHTTPCache(cachedPath); + const server = await TestServer.create(assetsPath, port, loopback); + server.enableHTTPCache(cachedPath); const httpsPort = port + 1; - this._httpsServer = await TestServer.createHTTPS(assetsPath, httpsPort, options.loopback); - this._httpsServer.enableHTTPCache(cachedPath); + const httpsServer = await TestServer.createHTTPS(assetsPath, httpsPort, loopback); + httpsServer.enableHTTPCache(cachedPath); - this._socksServer = socks.createServer((info, accept, deny) => { + const socksServer = socks.createServer((info, accept, deny) => { let socket; if ((socket = accept(true))) { // Catch and ignore ECONNRESET errors. @@ -194,62 +177,68 @@ class ServerEnv { ].join('\r\n')); } }); - this._socksPort = port + 2; - this._socksServer.listen(this._socksPort, 'localhost'); - this._socksServer.useAuth(socks.auth.None()); - return { + const socksPort = port + 2; + socksServer.listen(socksPort, 'localhost'); + socksServer.useAuth(socks.auth.None()); + + await run({ asset: (p: string) => path.join(__dirname, '..', 'assets', ...p.split('/')), - server: this._server, - httpsServer: this._httpsServer, - socksPort: this._socksPort, - }; - } + server, + httpsServer, + socksPort, + socksServer, + }); - async beforeEach({}, testInfo: folio.TestInfo) { - this._server.reset(); - this._httpsServer.reset(); - return {}; - } - - async afterAll({}, workerInfo: folio.WorkerInfo) { await Promise.all([ - this._server.stop(), - this._httpsServer.stop(), - this._socksServer.close(), + server.stop(), + httpsServer.stop(), + socksServer.close(), ]); - } -} + }, { scope: 'worker' } ], + + server: async ({ __servers }, run) => { + __servers.server.reset(); + await run(__servers.server); + }, + + httpsServer: async ({ __servers }, run) => { + __servers.httpsServer.reset(); + await run(__servers.httpsServer); + }, + + socksPort: async ({ __servers }, run) => { + await run(__servers.socksPort); + }, + + asset: async ({ __servers }, run) => { + await run(__servers.asset); + }, +}; type CoverageOptions = { coverageName?: string; }; -class CoverageEnv { - private _coverage: ReturnType | undefined; +const coverageFixtures: folio.Fixtures<{}, CoverageOptions & { __collectCoverage: void }> = { + coverageName: [ undefined, { scope: 'worker' } ], - hasBeforeAllOptions(options: CoverageOptions) { - return 'coverageName' in options; - } - - async beforeAll(options: CoverageOptions, workerInfo: folio.WorkerInfo) { - if (options.coverageName) - this._coverage = installCoverageHooks(options.coverageName); - return {}; - } - - async afterAll({}, workerInfo: folio.WorkerInfo) { - if (!this._coverage) + __collectCoverage: [ async ({ coverageName }, run, workerInfo) => { + if (!coverageName) { + await run(); return; - const { coverage, uninstall } = this._coverage; + } + + const { coverage, uninstall } = installCoverageHooks(coverageName); + await run(); uninstall(); const coveragePath = path.join(__dirname, '..', 'coverage-report', workerInfo.workerIndex + '.json'); const coverageJSON = Array.from(coverage.keys()).filter(key => coverage.get(key)); await fs.promises.mkdir(path.dirname(coveragePath), { recursive: true }); await fs.promises.writeFile(coveragePath, JSON.stringify(coverageJSON, undefined, 2), 'utf8'); - } -} + }, { scope: 'worker', auto: true } ], +}; export type CommonOptions = BaseOptions & ServerOptions & CoverageOptions; -export type CommonArgs = CommonOptions & BaseWorkerArgs & ServerWorkerArgs; +export type CommonWorkerFixtures = CommonOptions & BaseFixtures; -export const baseTest = folio.test.extend(new CoverageEnv()).extend(new ServerEnv()).extend(new BaseEnv()); +export const baseTest = folio.test.extend<{}, CoverageOptions>(coverageFixtures).extend(serverFixtures).extend<{}, BaseOptions & BaseFixtures>(baseFixtures); diff --git a/tests/config/browserTest.ts b/tests/config/browserTest.ts index 6eeb29c3af..d2418a65d3 100644 --- a/tests/config/browserTest.ts +++ b/tests/config/browserTest.ts @@ -22,168 +22,145 @@ import * as fs from 'fs'; import * as os from 'os'; import * as util from 'util'; import { RemoteServer, RemoteServerOptions } from './remoteServer'; -import { CommonArgs, baseTest } from './baseTest'; +import { baseTest, CommonWorkerFixtures } from './baseTest'; const mkdtempAsync = util.promisify(fs.mkdtemp); -type PlaywrightTestArgs = { +type PlaywrightWorkerOptions = { + traceDir: LaunchOptions['traceDir']; + executablePath: LaunchOptions['executablePath']; + proxy: LaunchOptions['proxy']; + args: LaunchOptions['args']; +}; +export type PlaywrightWorkerFixtures = { + browserType: BrowserType; + browserOptions: LaunchOptions; + browser: Browser; + browserVersion: string; +}; +type PlaywrightTestOptions = { + hasTouch: BrowserContextOptions['hasTouch']; +}; +type PlaywrightTestFixtures = { createUserDataDir: () => Promise; launchPersistent: (options?: Parameters[1]) => Promise<{ context: BrowserContext, page: Page }>; startRemoteServer: (options?: RemoteServerOptions) => Promise; + contextOptions: BrowserContextOptions; + contextFactory: (options?: BrowserContextOptions) => Promise; + context: BrowserContext; + page: Page; }; +export type PlaywrightOptions = PlaywrightWorkerOptions & PlaywrightTestOptions; -export type PlaywrightEnvOptions = LaunchOptions; -const kLaunchOptionNames = ['args', 'channel', 'chromiumSandbox', 'devtools', 'downloadsPath', 'env', 'executablePath', 'firefoxUserPrefs', 'handleSIGHUP', 'handleSIGINT', 'handleSIGTERM', 'headless', 'ignoreDefaultArgs', 'logger', 'proxy', 'slowMo', 'timeout', 'traceDir']; +export const playwrightFixtures: folio.Fixtures = { + traceDir: [ undefined, { scope: 'worker' } ], + executablePath: [ undefined, { scope: 'worker' } ], + proxy: [ undefined, { scope: 'worker' } ], + args: [ undefined, { scope: 'worker' } ], + hasTouch: undefined, -type PlaywrightWorkerArgs = { - browserType: BrowserType; - browserOptions: LaunchOptions; -}; + browserType: [async ({ playwright, browserName }, run) => { + await run(playwright[browserName]); + }, { scope: 'worker' } ], -class PlaywrightEnv { - protected _browserOptions: LaunchOptions; - protected _browserType: BrowserType; - private _userDataDirs: string[] = []; - private _persistentContext: BrowserContext | undefined; - private _remoteServer: RemoteServer | undefined; - - hasBeforeAllOptions(options: PlaywrightEnvOptions) { - return kLaunchOptionNames.some(key => key in options); - } - - async beforeAll(args: CommonArgs & PlaywrightEnvOptions, workerInfo: folio.WorkerInfo): Promise { - this._browserType = args.playwright[args.browserName]; - this._browserOptions = { + browserOptions: [async ({ headless, channel, executablePath, traceDir, proxy, args }, run) => { + await run({ + headless, + channel, + executablePath, + traceDir, + proxy, + args, handleSIGINT: false, - ...args, - }; - return { - browserType: this._browserType, - browserOptions: this._browserOptions, - }; - } + }); + }, { scope: 'worker' } ], - private async _createUserDataDir() { + browser: [async ({ browserType, browserOptions }, run) => { + const browser = await browserType.launch(browserOptions); + await run(browser); + await browser.close(); + }, { scope: 'worker' } ], + + browserVersion: [async ({ browser }, run) => { + await run(browser.version()); + }, { scope: 'worker' } ], + + createUserDataDir: async ({}, run) => { + const dirs: string[] = []; // We do not put user data dir in testOutputPath, // because we do not want to upload them as test result artifacts. // // Additionally, it is impossible to upload user data dir after test run: // - Firefox removes lock file later, presumably from another watchdog process? // - WebKit has circular symlinks that makes CI go crazy. - const dir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-')); - this._userDataDirs.push(dir); - return dir; - } + await run(async () => { + const dir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-')); + dirs.push(dir); + return dir; + }); + await removeFolders(dirs); + }, - private async _launchPersistent(options?: Parameters[1]) { - if (this._persistentContext) - throw new Error('can only launch one persitent context'); - const userDataDir = await this._createUserDataDir(); - this._persistentContext = await this._browserType.launchPersistentContext(userDataDir, { ...this._browserOptions, ...options }); - const page = this._persistentContext.pages()[0]; - return { context: this._persistentContext, page }; - } + launchPersistent: async ({ createUserDataDir, browserType, browserOptions }, run) => { + let persistentContext: BrowserContext | undefined; + await run(async options => { + if (persistentContext) + throw new Error('can only launch one persitent context'); + const userDataDir = await createUserDataDir(); + persistentContext = await browserType.launchPersistentContext(userDataDir, { ...browserOptions, ...options }); + const page = persistentContext.pages()[0]; + return { context: persistentContext, page }; + }); + if (persistentContext) + await persistentContext.close(); + }, - private async _startRemoteServer(options?: RemoteServerOptions): Promise { - if (this._remoteServer) - throw new Error('can only start one remote server'); - this._remoteServer = new RemoteServer(); - await this._remoteServer._start(this._browserType, this._browserOptions, options); - return this._remoteServer; - } + startRemoteServer: async ({ browserType, browserOptions }, run) => { + let remoteServer: RemoteServer | undefined; + await run(async options => { + if (remoteServer) + throw new Error('can only start one remote server'); + remoteServer = new RemoteServer(); + await remoteServer._start(browserType, browserOptions, options); + return remoteServer; + }); + if (remoteServer) + await remoteServer.close(); + }, - async beforeEach({}, testInfo: folio.TestInfo): Promise { - return { - createUserDataDir: this._createUserDataDir.bind(this), - launchPersistent: this._launchPersistent.bind(this), - startRemoteServer: this._startRemoteServer.bind(this), - }; - } - - async afterEach({}, testInfo: folio.TestInfo) { - if (this._persistentContext) { - await this._persistentContext.close(); - this._persistentContext = undefined; - } - if (this._remoteServer) { - await this._remoteServer.close(); - this._remoteServer = undefined; - } - await removeFolders(this._userDataDirs); - this._userDataDirs = []; - } -} - -type BrowserTestArgs = { - browser: Browser; - browserVersion: string; - contextOptions: BrowserContextOptions; - contextFactory: (options?: BrowserContextOptions) => Promise; -}; - -type BrowserTestOptions = BrowserContextOptions; - -class BrowserEnv { - private _browser: Browser | undefined; - private _contexts: BrowserContext[] = []; - protected _browserVersion: string; - - hasBeforeAllOptions(options: BrowserTestOptions) { - return false; - } - - async beforeAll(args: PlaywrightWorkerArgs, workerInfo: folio.WorkerInfo) { - this._browser = await args.browserType.launch(args.browserOptions); - this._browserVersion = this._browser.version(); - } - - async beforeEach(options: CommonArgs & BrowserTestOptions, testInfo: folio.TestInfo): Promise { + contextOptions: async ({ video, hasTouch, browserVersion }, run, testInfo) => { + testInfo.data.browserVersion = browserVersion; const debugName = path.relative(testInfo.project.outputDir, testInfo.outputDir).replace(/[\/\\]/g, '-'); const contextOptions = { - recordVideo: options.video ? { dir: testInfo.outputPath('') } : undefined, + recordVideo: video ? { dir: testInfo.outputPath('') } : undefined, _debugName: debugName, - ...options, + hasTouch, } as BrowserContextOptions; + await run(contextOptions); + }, - testInfo.data.browserVersion = this._browserVersion; - - const contextFactory = async (options: BrowserContextOptions = {}) => { - const context = await this._browser.newContext({ ...contextOptions, ...options }); - this._contexts.push(context); + contextFactory: async ({ browser, contextOptions }, run) => { + const contexts: BrowserContext[] = []; + await run(async options => { + const context = await browser.newContext({ ...contextOptions, ...options }); + contexts.push(context); return context; - }; + }); + await Promise.all(contexts.map(context => context.close())); + }, - return { - browser: this._browser, - browserVersion: this._browserVersion, - contextFactory, - contextOptions, - }; - } + context: async ({ contextFactory }, run) => { + await run(await contextFactory()); + }, - async afterEach({}, testInfo: folio.TestInfo) { - for (const context of this._contexts) - await context.close(); - this._contexts = []; - } + page: async ({ context }, run) => { + await run(await context.newPage()); + }, +}; - async afterAll({}, workerInfo: folio.WorkerInfo) { - if (this._browser) - await this._browser.close(); - this._browser = undefined; - } -} - -class ContextEnv { - async beforeEach(args: BrowserTestArgs, testInfo: folio.TestInfo) { - const context = await args.contextFactory(); - const page = await context.newPage(); - return { context, page }; - } -} - -export const playwrightTest = baseTest.extend(new PlaywrightEnv()); -export const browserTest = playwrightTest.extend(new BrowserEnv()); -export const contextTest = browserTest.extend(new ContextEnv()); +const test = baseTest.extend(playwrightFixtures); +export const playwrightTest = test; +export const browserTest = test; +export const contextTest = test; export { expect } from 'folio'; diff --git a/tests/config/default.config.ts b/tests/config/default.config.ts index 3f207ebbf1..032f2bfc12 100644 --- a/tests/config/default.config.ts +++ b/tests/config/default.config.ts @@ -16,10 +16,9 @@ import * as folio from 'folio'; import * as path from 'path'; -import { PlaywrightEnvOptions } from './browserTest'; +import { PlaywrightOptions, playwrightFixtures } from './browserTest'; import { test as pageTest } from '../page/pageTest'; -import { BrowserName, CommonArgs, CommonOptions } from './baseTest'; -import type { Browser, BrowserContext } from '../../index'; +import { BrowserName, CommonOptions } from './baseTest'; const getExecutablePath = (browserName: BrowserName) => { if (browserName === 'chromium' && process.env.CRPATH) @@ -30,58 +29,23 @@ const getExecutablePath = (browserName: BrowserName) => { return process.env.WKPATH; }; -class PageEnv { - private _browser: Browser - private _browserVersion: string; - private _browserMajorVersion: number; - private _context: BrowserContext | undefined; - - async beforeAll(args: PlaywrightEnvOptions & CommonArgs, workerInfo: folio.WorkerInfo) { - this._browser = await args.playwright[args.browserName].launch({ - handleSIGINT: false, - ...args, - } as any); - this._browserVersion = this._browser.version(); - this._browserMajorVersion = Number(this._browserVersion.split('.')[0]); - return {}; - } - - async beforeEach(args: CommonArgs, testInfo: folio.TestInfo) { - testInfo.data.browserVersion = this._browserVersion; - this._context = await this._browser.newContext({ - recordVideo: args.video ? { dir: testInfo.outputPath('') } : undefined, - ...args, - }); - const page = await this._context.newPage(); - return { - context: this._context, - page, - browserVersion: this._browserVersion, - browserMajorVersion: this._browserMajorVersion, - isAndroid: false, - isElectron: false, - }; - } - - async afterEach({}) { - if (this._context) - await this._context.close(); - this._context = undefined; - } - - async afterAll({}, workerInfo: folio.WorkerInfo) { - await this._browser.close(); - } -} +const pageFixtures = { + ...playwrightFixtures, + browserMajorVersion: async ({ browserVersion }, run) => { + await run(Number(browserVersion.split('.')[0])); + }, + isAndroid: false, + isElectron: false, +}; const mode = (folio.registerCLIOption('mode', 'Transport mode: default, driver or service').value || 'default') as ('default' | 'driver' | 'service'); const headed = folio.registerCLIOption('headed', 'Run tests in headed mode (default: headless)', { type: 'boolean' }).value || !!process.env.HEADFUL; -const channel = folio.registerCLIOption('channel', 'Browser channel (default: no channel)').value; +const channel = folio.registerCLIOption('channel', 'Browser channel (default: no channel)').value as any; const video = !!folio.registerCLIOption('video', 'Record videos for all tests', { type: 'boolean' }).value; const outputDir = path.join(__dirname, '..', '..', 'test-results'); const testDir = path.join(__dirname, '..'); -const config: folio.Config = { +const config: folio.Config = { testDir, snapshotDir: '__snapshots__', outputDir, @@ -108,7 +72,7 @@ for (const browserName of browserNames) { name: browserName, testDir, testIgnore, - options: { + use: { mode, browserName, headless: !headed, @@ -118,7 +82,7 @@ for (const browserName of browserNames) { traceDir: process.env.PWTRACE ? path.join(outputDir, 'trace') : undefined, coverageName: browserName, }, - define: { test: pageTest, env: new PageEnv() }, + define: { test: pageTest, fixtures: pageFixtures }, }); } diff --git a/tests/config/electron.config.ts b/tests/config/electron.config.ts index 1450c026f2..c42bb8dd59 100644 --- a/tests/config/electron.config.ts +++ b/tests/config/electron.config.ts @@ -16,29 +16,14 @@ import * as folio from 'folio'; import * as path from 'path'; -import { ElectronEnv } from '../electron/electronTest'; +import { electronFixtures } from '../electron/electronTest'; import { test as pageTest } from '../page/pageTest'; -import { PlaywrightEnvOptions } from './browserTest'; +import { PlaywrightOptions } from './browserTest'; import { CommonOptions } from './baseTest'; -class ElectronPageEnv extends ElectronEnv { - async beforeEach(args: any, testInfo: folio.TestInfo) { - const result = await super.beforeEach(args, testInfo); - const page = await result.newWindow(); - return { - ...result, - browserVersion: this._browserVersion, - browserMajorVersion: this._browserMajorVersion, - page, - isAndroid: false, - isElectron: true, - }; - } -} - const outputDir = path.join(__dirname, '..', '..', 'test-results'); const testDir = path.join(__dirname, '..'); -const config: folio.Config = { +const config: folio.Config = { testDir, snapshotDir: '__snapshots__', outputDir, @@ -56,7 +41,7 @@ const config: folio.Config = { config.projects.push({ name: 'electron', - options: { + use: { mode: 'default', browserName: 'chromium', coverageName: 'electron', @@ -66,13 +51,13 @@ config.projects.push({ config.projects.push({ name: 'electron', - options: { + use: { mode: 'default', browserName: 'chromium', coverageName: 'electron', }, testDir: path.join(testDir, 'page'), - define: { test: pageTest, env: new ElectronPageEnv() }, + define: { test: pageTest, fixtures: electronFixtures }, }); export default config; diff --git a/tests/electron/electronTest.ts b/tests/electron/electronTest.ts index 2bd92e30c0..4680c23ac4 100644 --- a/tests/electron/electronTest.ts +++ b/tests/electron/electronTest.ts @@ -14,69 +14,62 @@ * limitations under the License. */ -import { baseTest, CommonArgs } from '../config/baseTest'; +import { baseTest, CommonWorkerFixtures } from '../config/baseTest'; import { ElectronApplication, Page } from '../../index'; import * as folio from 'folio'; import * as path from 'path'; +import { PageTestFixtures } from '../page/pageTest'; export { expect } from 'folio'; -type ElectronTestArgs = { +type ElectronTestFixtures = PageTestFixtures & { electronApp: ElectronApplication; newWindow: () => Promise; }; -export class ElectronEnv { - private _electronApp: ElectronApplication | undefined; - private _windows: Page[] = []; - protected _browserVersion: string; - protected _browserMajorVersion: number; +const electronVersion = require('electron/package.json').version; +export const electronFixtures: folio.Fixtures = { + browserVersion: electronVersion, + browserMajorVersion: Number(electronVersion.split('.')[0]), + isAndroid: false, + isElectron: true, - private async _newWindow() { - const [ window ] = await Promise.all([ - this._electronApp!.waitForEvent('window'), - this._electronApp!.evaluate(electron => { - const window = new electron.BrowserWindow({ - width: 800, - height: 600, - // Sandboxed windows share process with their window.open() children - // and can script them. We use that heavily in our tests. - webPreferences: { sandbox: true } - }); - window.loadURL('about:blank'); - }) - ]); - this._windows.push(window); - return window; - } - - async beforeAll() { + electronApp: async ({ playwright }, run) => { // This env prevents 'Electron Security Policy' console message. process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'; - this._browserVersion = require('electron/package.json').version; - this._browserMajorVersion = Number(this._browserVersion.split('.')[0]); - return {}; - } - - async beforeEach(args: CommonArgs, testInfo: folio.TestInfo): Promise { - this._electronApp = await args.playwright._electron.launch({ + const electronApp = await playwright._electron.launch({ args: [path.join(__dirname, 'electron-app.js')], }); - testInfo.data.browserVersion = this._browserVersion; - return { - electronApp: this._electronApp, - newWindow: this._newWindow.bind(this), - }; - } + await run(electronApp); + await electronApp.close(); + }, - async afterEach({}, testInfo: folio.TestInfo) { - for (const window of this._windows) + newWindow: async ({ electronApp }, run) => { + const windows: Page[] = []; + await run(async () => { + const [ window ] = await Promise.all([ + electronApp.waitForEvent('window'), + electronApp.evaluate(electron => { + const window = new electron.BrowserWindow({ + width: 800, + height: 600, + // Sandboxed windows share process with their window.open() children + // and can script them. We use that heavily in our tests. + webPreferences: { sandbox: true } + }); + window.loadURL('about:blank'); + }) + ]); + windows.push(window); + return window; + }); + for (const window of windows) await window.close(); - this._windows = []; - if (this._electronApp) { - await this._electronApp.close(); - this._electronApp = undefined; - } - } -} + }, -export const electronTest = baseTest.extend(new ElectronEnv()); + + page: async ({ newWindow }, run) => { + await run(await newWindow()); + }, +}; + +export const electronTest = baseTest.extend(electronFixtures); diff --git a/tests/inspector/inspectorTest.ts b/tests/inspector/inspectorTest.ts index 510545132c..5d006ec3e3 100644 --- a/tests/inspector/inspectorTest.ts +++ b/tests/inspector/inspectorTest.ts @@ -20,7 +20,6 @@ import * as path from 'path'; import type { Source } from '../../src/server/supplements/recorder/recorderTypes'; import { ChildProcess, spawn } from 'child_process'; import { chromium } from '../../index'; -import * as folio from 'folio'; export { expect } from 'folio'; type CLITestArgs = { @@ -29,39 +28,40 @@ type CLITestArgs = { runCLI: (args: string[]) => CLIMock; }; -export const test = contextTest.extend({ - async beforeAll({}, workerInfo: folio.WorkerInfo) { - process.env.PWTEST_RECORDER_PORT = String(10907 + workerInfo.workerIndex); - }, - - async beforeEach({ page, context, toImpl, browserName, channel, headless, mode, executablePath }, testInfo: folio.TestInfo): Promise { - testInfo.skip(mode === 'service'); - const recorderPageGetter = async () => { +export const test = contextTest.extend({ + recorderPageGetter: async ({ page, context, toImpl, browserName, channel, headless, mode, executablePath }, run, testInfo) => { + process.env.PWTEST_RECORDER_PORT = String(10907 + testInfo.workerIndex); + if (mode === 'service') + testInfo.skip(); + await run(async () => { while (!toImpl(context).recorderAppForTest) await new Promise(f => setTimeout(f, 100)); const wsEndpoint = toImpl(context).recorderAppForTest.wsEndpoint; const browser = await chromium.connectOverCDP({ wsEndpoint }); const c = browser.contexts()[0]; return c.pages()[0] || await c.waitForEvent('page'); - }; - return { - runCLI: (cliArgs: string[]) => { - this._cli = new CLIMock(browserName, channel, headless, cliArgs, executablePath); - return this._cli; - }, - openRecorder: async () => { - await (page.context() as any)._enableRecorder({ language: 'javascript', startRecording: true }); - return new Recorder(page, await recorderPageGetter()); - }, - recorderPageGetter, - }; + }); }, - async afterEach({}, testInfo: folio.TestInfo) { - if (this._cli) { - await this._cli.exited; - this._cli = undefined; - } + runCLI: async ({ browserName, channel, headless, mode, executablePath }, run, testInfo) => { + process.env.PWTEST_RECORDER_PORT = String(10907 + testInfo.workerIndex); + if (mode === 'service') + testInfo.skip(); + + let cli: CLIMock | undefined; + await run(cliArgs => { + cli = new CLIMock(browserName, channel, headless, cliArgs, executablePath); + return cli; + }); + if (cli) + await cli.exited; + }, + + openRecorder: async ({ page, recorderPageGetter }, run) => { + await run(async () => { + await (page.context() as any)._enableRecorder({ language: 'javascript', startRecording: true }); + return new Recorder(page, await recorderPageGetter()); + }); }, }); diff --git a/tests/page/page-event-crash.spec.ts b/tests/page/page-event-crash.spec.ts index 4c77974785..115da312dc 100644 --- a/tests/page/page-event-crash.spec.ts +++ b/tests/page/page-event-crash.spec.ts @@ -32,51 +32,46 @@ function crash({ page, toImpl, browserName, platform, mode }: any) { } it.describe('', () => { - it('should emit crash event when page crashes', async args => { - const { page } = args; + it('should emit crash event when page crashes', async ({ page, toImpl, browserName, platform, mode }) => { await page.setContent(`
This page should crash
`); - crash(args); + crash({ page, toImpl, browserName, platform, mode }); const crashedPage = await new Promise(f => page.on('crash', f)); expect(crashedPage).toBe(page); }); - it('should throw on any action after page crashes', async args => { - const { page } = args; + it('should throw on any action after page crashes', async ({ page, toImpl, browserName, platform, mode }) => { await page.setContent(`
This page should crash
`); - crash(args); + crash({ page, toImpl, browserName, platform, mode }); await page.waitForEvent('crash'); const err = await page.evaluate(() => {}).then(() => null, e => e); expect(err).toBeTruthy(); expect(err.message).toContain('crash'); }); - it('should cancel waitForEvent when page crashes', async args => { - const { page } = args; + it('should cancel waitForEvent when page crashes', async ({ page, toImpl, browserName, platform, mode }) => { await page.setContent(`
This page should crash
`); const promise = page.waitForEvent('response').catch(e => e); - crash(args); + crash({ page, toImpl, browserName, platform, mode }); const error = await promise; expect(error.message).toContain('Page crashed'); }); - it('should cancel navigation when page crashes', async args => { - const { page, server } = args; + it('should cancel navigation when page crashes', async ({ server, page, toImpl, browserName, platform, mode }) => { await page.setContent(`
This page should crash
`); server.setRoute('/one-style.css', () => {}); const promise = page.goto(server.PREFIX + '/one-style.html').catch(e => e); await page.waitForNavigation({ waitUntil: 'domcontentloaded' }); - crash(args); + crash({ page, toImpl, browserName, platform, mode }); const error = await promise; expect(error.message).toContain('Navigation failed because page crashed'); }); - it('should be able to close context when page crashes', async args => { - it.skip(args.isAndroid); - it.skip(args.isElectron); + it('should be able to close context when page crashes', async ({ isAndroid, isElectron, page, toImpl, browserName, platform, mode }) => { + it.skip(isAndroid); + it.skip(isElectron); - const { page } = args; await page.setContent(`
This page should crash
`); - crash(args); + crash({ page, toImpl, browserName, platform, mode }); await page.waitForEvent('crash'); await page.context().close(); }); diff --git a/tests/page/pageTest.ts b/tests/page/pageTest.ts index 077991466b..4692e0dd7b 100644 --- a/tests/page/pageTest.ts +++ b/tests/page/pageTest.ts @@ -19,7 +19,7 @@ import type { Page } from '../../index'; export { expect } from 'folio'; // Page test does not guarantee an isolated context, just a new page (because Android). -export type PageTestArgs = { +export type PageTestFixtures = { browserVersion: string; browserMajorVersion: number; page: Page; @@ -27,4 +27,4 @@ export type PageTestArgs = { isElectron: boolean; }; -export const test = baseTest.declare(); +export const test = baseTest.declare(); diff --git a/tests/snapshotter.spec.ts b/tests/snapshotter.spec.ts index e96c77677f..ffd901647e 100644 --- a/tests/snapshotter.spec.ts +++ b/tests/snapshotter.spec.ts @@ -19,25 +19,22 @@ import { InMemorySnapshotter } from '../lib/server/snapshot/inMemorySnapshotter' import { HttpServer } from '../lib/utils/httpServer'; import { SnapshotServer } from '../lib/server/snapshot/snapshotServer'; -const it = contextTest.extend({ - async beforeEach({ context, toImpl, mode }, testInfo) { - testInfo.skip(mode !== 'default'); - const snapshotter = new InMemorySnapshotter(toImpl(context)); - await snapshotter.initialize(); - this.httpServer = new HttpServer(); - new SnapshotServer(this.httpServer, snapshotter); - const snapshotPort = 11000 + testInfo.workerIndex; - await this.httpServer.start(snapshotPort); - this.snapshotter = snapshotter; - return { - snapshotter, - snapshotPort, - }; +const it = contextTest.extend<{ snapshotPort: number, snapshotter: InMemorySnapshotter }>({ + snapshotPort: async ({}, run, testInfo) => { + await run(11000 + testInfo.workerIndex); }, - async afterEach() { - await this.snapshotter.dispose(); - await this.httpServer.stop(); + snapshotter: async ({ mode, toImpl, context, snapshotPort }, run, testInfo) => { + if (mode !== 'default') + testInfo.skip(); + const snapshotter = new InMemorySnapshotter(toImpl(context)); + await snapshotter.initialize(); + const httpServer = new HttpServer(); + new SnapshotServer(httpServer, snapshotter); + await httpServer.start(snapshotPort); + await run(snapshotter); + await snapshotter.dispose(); + await httpServer.stop(); }, }); diff --git a/tests/tap.spec.ts b/tests/tap.spec.ts index e2653bb53e..5fe2eddab9 100644 --- a/tests/tap.spec.ts +++ b/tests/tap.spec.ts @@ -18,7 +18,7 @@ import { contextTest as it, expect } from './config/browserTest'; import { ElementHandle } from '../index'; import type { ServerResponse } from 'http'; -it.useOptions({ hasTouch: true }); +it.use({ hasTouch: true }); it('should send all of the correct events', async ({ page }) => { await page.setContent(` diff --git a/tests/tracing.spec.ts b/tests/tracing.spec.ts index 9c3d1a418b..f9e5917255 100644 --- a/tests/tracing.spec.ts +++ b/tests/tracing.spec.ts @@ -21,7 +21,7 @@ import removeFolder from 'rimraf'; import jpeg from 'jpeg-js'; const traceDir = path.join(__dirname, '..', 'test-results', 'trace-' + process.env.FOLIO_WORKER_INDEX); -test.useOptions({ traceDir }); +test.use({ traceDir }); test.beforeEach(async ({ browserName, headless }) => { test.fixme(browserName === 'chromium' && !headless, 'Chromium screencast on headed has a min width issue'); @@ -29,13 +29,13 @@ test.beforeEach(async ({ browserName, headless }) => { }); test('should collect trace', async ({ context, page, server, browserName }, testInfo) => { - await (context as any).tracing.start({ name: 'test', screenshots: true, snapshots: true }); + await context.tracing.start({ name: 'test', screenshots: true, snapshots: true }); await page.goto(server.EMPTY_PAGE); await page.setContent(''); await page.click('"Click"'); await page.close(); - await (context as any).tracing.stop(); - await (context as any).tracing.export(testInfo.outputPath('trace.zip')); + await context.tracing.stop(); + await context.tracing.export(testInfo.outputPath('trace.zip')); const { events } = await parseTrace(testInfo.outputPath('trace.zip')); expect(events[0].type).toBe('context-options'); @@ -50,13 +50,13 @@ test('should collect trace', async ({ context, page, server, browserName }, test }); test('should collect trace', async ({ context, page, server }, testInfo) => { - await (context as any).tracing.start({ name: 'test' }); + await context.tracing.start({ name: 'test' }); await page.goto(server.EMPTY_PAGE); await page.setContent(''); await page.click('"Click"'); await page.close(); - await (context as any).tracing.stop(); - await (context as any).tracing.export(testInfo.outputPath('trace.zip')); + await context.tracing.stop(); + await context.tracing.export(testInfo.outputPath('trace.zip')); const { events } = await parseTrace(testInfo.outputPath('trace.zip')); expect(events.some(e => e.type === 'frame-snapshot')).toBeFalsy(); @@ -64,18 +64,18 @@ test('should collect trace', async ({ context, page, server }, testInfo) => { }); test('should collect two traces', async ({ context, page, server }, testInfo) => { - await (context as any).tracing.start({ name: 'test1', screenshots: true, snapshots: true }); + await context.tracing.start({ name: 'test1', screenshots: true, snapshots: true }); await page.goto(server.EMPTY_PAGE); await page.setContent(''); await page.click('"Click"'); - await (context as any).tracing.stop(); - await (context as any).tracing.export(testInfo.outputPath('trace1.zip')); + await context.tracing.stop(); + await context.tracing.export(testInfo.outputPath('trace1.zip')); - await (context as any).tracing.start({ name: 'test2', screenshots: true, snapshots: true }); + await context.tracing.start({ name: 'test2', screenshots: true, snapshots: true }); await page.dblclick('"Click"'); await page.close(); - await (context as any).tracing.stop(); - await (context as any).tracing.export(testInfo.outputPath('trace2.zip')); + await context.tracing.stop(); + await context.tracing.export(testInfo.outputPath('trace2.zip')); { const { events } = await parseTrace(testInfo.outputPath('trace1.zip')); @@ -124,15 +124,15 @@ for (const params of [ const previewHeight = params.height * scale; const context = await contextFactory({ viewport: { width: params.width, height: params.height }}); - await (context as any).tracing.start({ name: 'test', screenshots: true, snapshots: true }); + await context.tracing.start({ name: 'test', screenshots: true, snapshots: true }); const page = await context.newPage(); // Make sure we have a chance to paint. for (let i = 0; i < 10; ++i) { await page.setContent(''); await page.evaluate(() => new Promise(requestAnimationFrame)); } - await (context as any).tracing.stop(); - await (context as any).tracing.export(testInfo.outputPath('trace.zip')); + await context.tracing.stop(); + await context.tracing.export(testInfo.outputPath('trace.zip')); const { events, resources } = await parseTrace(testInfo.outputPath('trace.zip')); const frames = events.filter(e => e.type === 'screencast-frame');