diff --git a/package-lock.json b/package-lock.json
index b1b800883e..65832f4246 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3483,9 +3483,9 @@
}
},
"folio": {
- "version": "0.4.0-alpha11",
- "resolved": "https://registry.npmjs.org/folio/-/folio-0.4.0-alpha11.tgz",
- "integrity": "sha512-4kXdO+Ndbn++vCbzuMbn8bGqQLQ9J/Vni/1r9UwvirE4HydfxP1PHkvx9qb7wsB2hQbXmPkU5qM0eyGWFKpmog==",
+ "version": "0.4.0-alpha13",
+ "resolved": "https://registry.npmjs.org/folio/-/folio-0.4.0-alpha13.tgz",
+ "integrity": "sha512-ujrTuD4bSY3jNB2QVf5B2JSZFz2PNtNR0LIIbD+o4vCNutU9IAK0vn1WAiM5uLMt47CadAuFEb7260nanrTCcw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.12.13",
diff --git a/package.json b/package.json
index 5e9e1b0910..815d5de143 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-alpha11",
+ "folio": "=0.4.0-alpha13",
"formidable": "^1.2.2",
"html-webpack-plugin": "^4.4.1",
"ncp": "^2.0.0",
diff --git a/tests/browsercontext-device.spec.ts b/tests/browsercontext-device.spec.ts
index 56d75b3739..610e90d80e 100644
--- a/tests/browsercontext-device.spec.ts
+++ b/tests/browsercontext-device.spec.ts
@@ -60,12 +60,9 @@ it.describe('device', () => {
await context.close();
});
- it('should scroll twice when emulated', async ({server, contextFactory, playwright, contextOptions}) => {
+ it('should scroll twice when emulated', async ({server, contextFactory, playwright}) => {
const device = playwright.devices['iPhone 6'];
- const context = await contextFactory({
- ...contextOptions,
- ...device,
- });
+ const context = await contextFactory(device);
const page = await context.newPage();
await page.setContent(`
@@ -81,14 +78,11 @@ it.describe('device', () => {
await context.close();
});
- it('should reset scroll top after a navigation', async ({server, contextFactory, playwright, contextOptions, browserName}) => {
+ it('should reset scroll top after a navigation', async ({server, contextFactory, playwright, browserName}) => {
it.skip(browserName === 'webkit');
const device = playwright.devices['iPhone 6'];
- const context = await contextFactory({
- ...contextOptions,
- ...device,
- });
+ const context = await contextFactory(device);
const page = await context.newPage();
await page.goto(server.PREFIX + '/input/scrollable.html');
await page.evaluate(() => window.scroll(0, 100));
@@ -98,14 +92,11 @@ it.describe('device', () => {
await context.close();
});
- it('should scroll to a precise position with mobile scale', async ({server, contextFactory, playwright, contextOptions, browserName}) => {
+ it('should scroll to a precise position with mobile scale', async ({server, contextFactory, playwright, browserName}) => {
it.skip(browserName === 'webkit');
const device = playwright.devices['iPhone 6'];
- const context = await contextFactory({
- ...contextOptions,
- ...device,
- });
+ const context = await contextFactory(device);
const page = await context.newPage();
await page.goto(server.PREFIX + '/input/scrollable.html');
expect(await page.evaluate(() => document.body.scrollHeight)).toBeGreaterThan(1000);
@@ -114,12 +105,9 @@ it.describe('device', () => {
await context.close();
});
- it('should emulate viewport and screen size', async ({server, contextFactory, playwright, contextOptions}) => {
+ it('should emulate viewport and screen size', async ({server, contextFactory, playwright}) => {
const device = playwright.devices['iPhone 12'];
- const context = await contextFactory({
- ...contextOptions,
- ...device,
- });
+ const context = await contextFactory(device);
const page = await context.newPage();
await page.setContent(``);
@@ -136,12 +124,9 @@ it.describe('device', () => {
await context.close();
});
- it('should emulate viewport without screen size', async ({server, contextFactory, playwright, contextOptions}) => {
+ it('should emulate viewport without screen size', async ({server, contextFactory, playwright}) => {
const device = playwright.devices['iPhone 6'];
- const context = await contextFactory({
- ...contextOptions,
- ...device,
- });
+ const context = await contextFactory(device);
const page = await context.newPage();
await page.setContent(``);
diff --git a/tests/browsercontext-proxy.spec.ts b/tests/browsercontext-proxy.spec.ts
index 6e1d5f4400..c0a8b06051 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({ launchOptions: { proxy: { server: 'per-context' } } });
+it.useOptions({ 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 b669f7cba6..4e57914867 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({ launchOptions: { args: ['--site-per-process'] } });
+it.useOptions({ 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 810d6783ed..24cfd2f9c6 100644
--- a/tests/config/android.config.ts
+++ b/tests/config/android.config.ts
@@ -42,11 +42,9 @@ class AndroidPageEnv extends AndroidEnv {
}
}
-type AllOptions = PlaywrightEnvOptions & CommonOptions;
-
const outputDir = path.join(__dirname, '..', '..', 'test-results');
const testDir = path.join(__dirname, '..');
-const config: folio.Config = {
+const config: folio.Config = {
testDir,
snapshotDir: '__snapshots__',
outputDir,
@@ -66,6 +64,7 @@ config.projects.push({
name: 'android',
options: {
loopback: '10.0.2.2',
+ mode: 'default',
browserName: 'chromium',
},
testDir: path.join(testDir, 'android'),
@@ -75,6 +74,7 @@ config.projects.push({
name: 'android',
options: {
loopback: '10.0.2.2',
+ mode: 'default',
browserName: 'chromium',
},
testDir: path.join(testDir, 'page'),
diff --git a/tests/config/baseTest.ts b/tests/config/baseTest.ts
index 13cb014ae7..4b1ad8356a 100644
--- a/tests/config/baseTest.ts
+++ b/tests/config/baseTest.ts
@@ -26,17 +26,17 @@ import { PlaywrightClient } from '../../lib/remote/playwrightClient';
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
type Mode = 'default' | 'driver' | 'service';
-type BaseWorkerArgs = {
+type BaseOptions = {
mode: Mode;
+ browserName: BrowserName;
+ channel?: string;
+ video?: boolean;
+ headless?: boolean;
+};
+type BaseWorkerArgs = {
platform: 'win32' | 'darwin' | 'linux';
- video: boolean | undefined;
- headless: boolean | undefined;
-
playwright: typeof import('../../index');
toImpl: (rpcObject: any) => any;
- browserName: BrowserName;
- channel: string | undefined;
-
isWindows: boolean;
isMac: boolean;
isLinux: boolean;
@@ -100,17 +100,8 @@ class DefaultMode {
}
}
-type BaseOptions = {
- mode?: Mode;
- browserName?: BrowserName;
- channel?: string;
- video?: boolean;
- headless?: boolean;
-};
-
class BaseEnv {
private _mode: DriverMode | ServiceMode | DefaultMode;
- private _browserName: BrowserName;
private _options: BaseOptions;
private _playwright: typeof import('../../index');
@@ -120,36 +111,30 @@ class BaseEnv {
async beforeAll(options: BaseOptions, workerInfo: folio.WorkerInfo): Promise {
this._options = options;
- this._browserName = options.browserName || 'chromium';
this._mode = {
default: new DefaultMode(),
service: new ServiceMode(),
driver: new DriverMode(),
- }[this._options.mode || 'default'];
+ }[this._options.mode];
require('../../lib/utils/utils').setUnderTest();
this._playwright = await this._mode.setup(workerInfo);
return {
playwright: this._playwright,
- browserName: this._browserName,
- channel: this._options.channel,
isWindows: process.platform === 'win32',
isMac: process.platform === 'darwin',
isLinux: process.platform === 'linux',
- headless: this._options.headless,
- video: this._options.video,
- mode: this._options.mode || 'default',
platform: process.platform as ('win32' | 'darwin' | 'linux'),
toImpl: (this._playwright as any)._toImpl,
};
}
async beforeEach({}, testInfo: folio.TestInfo) {
- testInfo.snapshotPathSegment = this._browserName;
- testInfo.data = { browserName: this._browserName };
+ testInfo.snapshotPathSegment = this._options.browserName;
+ testInfo.data = { browserName: this._options.browserName };
if (!this._options.headless)
testInfo.data.headful = true;
- if ((this._options.mode || 'default') !== 'default')
- testInfo.data.mode = this._options.mode || 'default';
+ if (this._options.mode !== 'default')
+ testInfo.data.mode = this._options.mode;
if (this._options.video)
testInfo.data.video = true;
return {};
@@ -265,6 +250,6 @@ class CoverageEnv {
}
export type CommonOptions = BaseOptions & ServerOptions & CoverageOptions;
-export type CommonArgs = BaseWorkerArgs & ServerWorkerArgs;
+export type CommonArgs = CommonOptions & BaseWorkerArgs & ServerWorkerArgs;
export const baseTest = folio.test.extend(new CoverageEnv()).extend(new ServerEnv()).extend(new BaseEnv());
diff --git a/tests/config/browserTest.ts b/tests/config/browserTest.ts
index 9cdf457efc..6eeb29c3af 100644
--- a/tests/config/browserTest.ts
+++ b/tests/config/browserTest.ts
@@ -32,10 +32,8 @@ type PlaywrightTestArgs = {
startRemoteServer: (options?: RemoteServerOptions) => Promise;
};
-export type PlaywrightEnvOptions = {
- launchOptions?: LaunchOptions;
- traceDir?: string;
-};
+export type PlaywrightEnvOptions = LaunchOptions;
+const kLaunchOptionNames = ['args', 'channel', 'chromiumSandbox', 'devtools', 'downloadsPath', 'env', 'executablePath', 'firefoxUserPrefs', 'handleSIGHUP', 'handleSIGINT', 'handleSIGTERM', 'headless', 'ignoreDefaultArgs', 'logger', 'proxy', 'slowMo', 'timeout', 'traceDir'];
type PlaywrightWorkerArgs = {
browserType: BrowserType;
@@ -50,18 +48,15 @@ class PlaywrightEnv {
private _remoteServer: RemoteServer | undefined;
hasBeforeAllOptions(options: PlaywrightEnvOptions) {
- return 'launchOptions' in options || 'traceDir' in options;
+ return kLaunchOptionNames.some(key => key in options);
}
async beforeAll(args: CommonArgs & PlaywrightEnvOptions, workerInfo: folio.WorkerInfo): Promise {
this._browserType = args.playwright[args.browserName];
this._browserOptions = {
- traceDir: args.traceDir,
- channel: args.channel,
- headless: args.headless,
handleSIGINT: false,
- ...args.launchOptions,
- } as any;
+ ...args,
+ };
return {
browserType: this._browserType,
browserOptions: this._browserOptions,
@@ -126,9 +121,7 @@ type BrowserTestArgs = {
contextFactory: (options?: BrowserContextOptions) => Promise;
};
-type BrowserTestOptions = {
- contextOptions?: BrowserContextOptions;
-};
+type BrowserTestOptions = BrowserContextOptions;
class BrowserEnv {
private _browser: Browser | undefined;
@@ -149,7 +142,7 @@ class BrowserEnv {
const contextOptions = {
recordVideo: options.video ? { dir: testInfo.outputPath('') } : undefined,
_debugName: debugName,
- ...options.contextOptions,
+ ...options,
} as BrowserContextOptions;
testInfo.data.browserVersion = this._browserVersion;
@@ -163,8 +156,8 @@ class BrowserEnv {
return {
browser: this._browser,
browserVersion: this._browserVersion,
- contextOptions,
contextFactory,
+ contextOptions,
};
}
diff --git a/tests/config/default.config.ts b/tests/config/default.config.ts
index db4a2474d6..3f207ebbf1 100644
--- a/tests/config/default.config.ts
+++ b/tests/config/default.config.ts
@@ -30,21 +30,16 @@ const getExecutablePath = (browserName: BrowserName) => {
return process.env.WKPATH;
};
-type AllOptions = PlaywrightEnvOptions & CommonOptions;
-
class PageEnv {
private _browser: Browser
private _browserVersion: string;
private _browserMajorVersion: number;
private _context: BrowserContext | undefined;
- async beforeAll(args: AllOptions & CommonArgs, workerInfo: folio.WorkerInfo) {
+ async beforeAll(args: PlaywrightEnvOptions & CommonArgs, workerInfo: folio.WorkerInfo) {
this._browser = await args.playwright[args.browserName].launch({
- ...args.launchOptions,
- traceDir: args.traceDir,
- channel: args.channel,
- headless: args.headless,
handleSIGINT: false,
+ ...args,
} as any);
this._browserVersion = this._browser.version();
this._browserMajorVersion = Number(this._browserVersion.split('.')[0]);
@@ -55,6 +50,7 @@ class PageEnv {
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 {
@@ -78,14 +74,14 @@ class PageEnv {
}
}
-const mode = folio.registerCLIOption('mode', 'Transport mode: default, driver or service').value as ('default' | 'driver' | 'service' | undefined);
+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 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,
@@ -118,10 +114,8 @@ for (const browserName of browserNames) {
headless: !headed,
channel,
video,
+ executablePath,
traceDir: process.env.PWTRACE ? path.join(outputDir, 'trace') : undefined,
- launchOptions: {
- executablePath,
- },
coverageName: browserName,
},
define: { test: pageTest, env: new PageEnv() },
diff --git a/tests/config/electron.config.ts b/tests/config/electron.config.ts
index a9dec538d5..1450c026f2 100644
--- a/tests/config/electron.config.ts
+++ b/tests/config/electron.config.ts
@@ -36,11 +36,9 @@ class ElectronPageEnv extends ElectronEnv {
}
}
-type AllOptions = PlaywrightEnvOptions & CommonOptions;
-
const outputDir = path.join(__dirname, '..', '..', 'test-results');
const testDir = path.join(__dirname, '..');
-const config: folio.Config = {
+const config: folio.Config = {
testDir,
snapshotDir: '__snapshots__',
outputDir,
@@ -59,6 +57,7 @@ const config: folio.Config = {
config.projects.push({
name: 'electron',
options: {
+ mode: 'default',
browserName: 'chromium',
coverageName: 'electron',
},
@@ -68,6 +67,7 @@ config.projects.push({
config.projects.push({
name: 'electron',
options: {
+ mode: 'default',
browserName: 'chromium',
coverageName: 'electron',
},
diff --git a/tests/config/remoteServer.ts b/tests/config/remoteServer.ts
index 1ec8bde955..1523f1f6b8 100644
--- a/tests/config/remoteServer.ts
+++ b/tests/config/remoteServer.ts
@@ -44,8 +44,13 @@ export class RemoteServer {
this._didExit = false;
this._browserType = browserType;
- const launchOptions = {
- ...browserOptions,
+ // Copy options to prevent a large JSON string when launching subprocess.
+ // Otherwise, we get `Error: spawn ENAMETOOLONG` on Windows.
+ const launchOptions: LaunchOptions = {
+ args: browserOptions.args,
+ headless: browserOptions.headless,
+ channel: browserOptions.channel,
+ traceDir: browserOptions.traceDir,
handleSIGINT: true,
handleSIGTERM: true,
handleSIGHUP: true,
diff --git a/tests/inspector/inspectorTest.ts b/tests/inspector/inspectorTest.ts
index 63b4ea49f5..510545132c 100644
--- a/tests/inspector/inspectorTest.ts
+++ b/tests/inspector/inspectorTest.ts
@@ -27,7 +27,6 @@ type CLITestArgs = {
recorderPageGetter: () => Promise;
openRecorder: () => Promise;
runCLI: (args: string[]) => CLIMock;
- executablePath: string | undefined;
};
export const test = contextTest.extend({
@@ -35,7 +34,7 @@ export const test = contextTest.extend({
process.env.PWTEST_RECORDER_PORT = String(10907 + workerInfo.workerIndex);
},
- async beforeEach({ page, context, toImpl, browserName, channel, headless, mode, launchOptions: { executablePath } }, testInfo: folio.TestInfo): Promise {
+ async beforeEach({ page, context, toImpl, browserName, channel, headless, mode, executablePath }, testInfo: folio.TestInfo): Promise {
testInfo.skip(mode === 'service');
const recorderPageGetter = async () => {
while (!toImpl(context).recorderAppForTest)
@@ -55,7 +54,6 @@ export const test = contextTest.extend({
return new Recorder(page, await recorderPageGetter());
},
recorderPageGetter,
- executablePath
};
},
@@ -180,7 +178,7 @@ class CLIMock {
private waitForCallback: () => void;
exited: Promise;
- constructor(browserName: string, channel: string | undefined, headless: boolean | undefined, args: string[], executablePath?: string) {
+ constructor(browserName: string, channel: string | undefined, headless: boolean | undefined, args: string[], executablePath: string | undefined) {
this.data = '';
const nodeArgs = [
path.join(__dirname, '..', '..', 'lib', 'cli', 'cli.js'),
diff --git a/tests/tap.spec.ts b/tests/tap.spec.ts
index 5ffc97c773..e2653bb53e 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({ contextOptions: { hasTouch: true } });
+it.useOptions({ hasTouch: true });
it('should send all of the correct events', async ({ page }) => {
await page.setContent(`