chore: roll test fixtures, replace trace w/ video (#4129)

This commit is contained in:
Pavel Feldman 2020-10-13 13:18:36 -07:00 committed by GitHub
parent a4474f6752
commit 9daedaca08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 149 additions and 154 deletions

View file

@ -186,8 +186,8 @@ jobs:
name: wire-${{ matrix.browser }}-linux-test-results name: wire-${{ matrix.browser }}-linux-test-results
path: test-results path: test-results
tracing_linux: video_linux:
name: "Tracing Linux" name: "Video Linux"
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -207,13 +207,12 @@ jobs:
# XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR # XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR
# Wrap `npm run` in a subshell to redirect STDERR to file. # Wrap `npm run` in a subshell to redirect STDERR to file.
# Enable core dumps in the subshell. # Enable core dumps in the subshell.
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- bash -c "ulimit -c unlimited && npx folio test/ --workers=1 --forbid-only --timeout=60000 --global-timeout=5400000 --retries=3 --reporter=dot,json" - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- bash -c "ulimit -c unlimited && npx folio test/ --workers=1 --forbid-only --timeout=60000 --global-timeout=5400000 --retries=3 --reporter=dot,json -p video"
env: env:
BROWSER: ${{ matrix.browser }} BROWSER: ${{ matrix.browser }}
TRACING: true
FOLIO_JSON_OUTPUT_NAME: "test-results/report.json" FOLIO_JSON_OUTPUT_NAME: "test-results/report.json"
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
if: ${{ always() }} if: ${{ always() }}
with: with:
name: tracing-${{ matrix.browser }}-linux-test-results name: video-${{ matrix.browser }}-linux-test-results
path: test-results path: test-results

View file

@ -139,15 +139,15 @@ it('should isolate send cookie header', async ({server, context, browser}) => {
} }
}); });
it('should isolate cookies between launches', (test, parameters) => { it('should isolate cookies between launches', test => {
test.slow(); test.slow();
}, async ({browserType, server, defaultBrowserOptions}) => { }, async ({browserType, server, browserOptions}) => {
const browser1 = await browserType.launch(defaultBrowserOptions); const browser1 = await browserType.launch(browserOptions);
const context1 = await browser1.newContext(); const context1 = await browser1.newContext();
await context1.addCookies([{url: server.EMPTY_PAGE, name: 'cookie-in-context-1', value: 'value', expires: Date.now() / 1000 + 10000}]); await context1.addCookies([{url: server.EMPTY_PAGE, name: 'cookie-in-context-1', value: 'value', expires: Date.now() / 1000 + 10000}]);
await browser1.close(); await browser1.close();
const browser2 = await browserType.launch(defaultBrowserOptions); const browser2 = await browserType.launch(browserOptions);
const context2 = await browser2.newContext(); const context2 = await browser2.newContext();
const cookies = await context2.cookies(); const cookies = await context2.cookies();
expect(cookies.length).toBe(0); expect(cookies.length).toBe(0);

View file

@ -20,21 +20,21 @@ import { it, expect, describe } from './fixtures';
describe('lauch server', (suite, { wire }) => { describe('lauch server', (suite, { wire }) => {
suite.skip(wire); suite.skip(wire);
}, () => { }, () => {
it('should work', async ({browserType, defaultBrowserOptions}) => { it('should work', async ({browserType, browserOptions}) => {
const browserServer = await browserType.launchServer(defaultBrowserOptions); const browserServer = await browserType.launchServer(browserOptions);
expect(browserServer.wsEndpoint()).not.toBe(null); expect(browserServer.wsEndpoint()).not.toBe(null);
await browserServer.close(); await browserServer.close();
}); });
it('should work with port', async ({browserType, defaultBrowserOptions, testWorkerIndex}) => { it('should work with port', async ({browserType, browserOptions, testWorkerIndex}) => {
const browserServer = await browserType.launchServer({ ...defaultBrowserOptions, port: 8800 + testWorkerIndex }); const browserServer = await browserType.launchServer({ ...browserOptions, port: 8800 + testWorkerIndex });
expect(browserServer.wsEndpoint()).toContain(String(8800 + testWorkerIndex)); expect(browserServer.wsEndpoint()).toContain(String(8800 + testWorkerIndex));
await browserServer.close(); await browserServer.close();
}); });
it('should fire "close" event during kill', async ({browserType, defaultBrowserOptions}) => { it('should fire "close" event during kill', async ({browserType, browserOptions}) => {
const order = []; const order = [];
const browserServer = await browserType.launchServer(defaultBrowserOptions); const browserServer = await browserType.launchServer(browserOptions);
const closedPromise = new Promise(f => browserServer.on('close', () => { const closedPromise = new Promise(f => browserServer.on('close', () => {
order.push('closed'); order.push('closed');
f(); f();
@ -46,14 +46,14 @@ describe('lauch server', (suite, { wire }) => {
expect(order).toEqual(['closed', 'killed']); expect(order).toEqual(['closed', 'killed']);
}); });
it('should return child_process instance', async ({browserType, defaultBrowserOptions}) => { it('should return child_process instance', async ({browserType, browserOptions}) => {
const browserServer = await browserType.launchServer(defaultBrowserOptions); const browserServer = await browserType.launchServer(browserOptions);
expect(browserServer.process().pid).toBeGreaterThan(0); expect(browserServer.process().pid).toBeGreaterThan(0);
await browserServer.close(); await browserServer.close();
}); });
it('should fire close event', async ({browserType, defaultBrowserOptions}) => { it('should fire close event', async ({browserType, browserOptions}) => {
const browserServer = await browserType.launchServer(defaultBrowserOptions); const browserServer = await browserType.launchServer(browserOptions);
const [result] = await Promise.all([ const [result] = await Promise.all([
// @ts-expect-error The signal parameter is not documented. // @ts-expect-error The signal parameter is not documented.
new Promise(f => browserServer.on('close', (exitCode, signal) => f({ exitCode, signal }))), new Promise(f => browserServer.on('close', (exitCode, signal) => f({ exitCode, signal }))),

View file

@ -18,8 +18,8 @@
import path from 'path'; import path from 'path';
import { it, expect } from './fixtures'; import { it, expect } from './fixtures';
it('should reject all promises when browser is closed', async ({browserType, defaultBrowserOptions}) => { it('should reject all promises when browser is closed', async ({browserType, browserOptions}) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
const page = await (await browser.newContext()).newPage(); const page = await (await browser.newContext()).newPage();
let error = null; let error = null;
const neverResolves = page.evaluate(() => new Promise(r => {})).catch(e => error = e); const neverResolves = page.evaluate(() => new Promise(r => {})).catch(e => error = e);
@ -29,54 +29,54 @@ it('should reject all promises when browser is closed', async ({browserType, def
expect(error.message).toContain('Protocol error'); expect(error.message).toContain('Protocol error');
}); });
it('should throw if userDataDir option is passed', async ({browserType, defaultBrowserOptions}) => { it('should throw if userDataDir option is passed', async ({browserType, browserOptions}) => {
let waitError = null; let waitError = null;
const options = Object.assign({}, defaultBrowserOptions, {userDataDir: 'random-path'}); const options = Object.assign({}, browserOptions, {userDataDir: 'random-path'});
await browserType.launch(options).catch(e => waitError = e); await browserType.launch(options).catch(e => waitError = e);
expect(waitError.message).toContain('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead'); expect(waitError.message).toContain('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
}); });
it('should throw if port option is passed', async ({browserType, defaultBrowserOptions}) => { it('should throw if port option is passed', async ({browserType, browserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions, {port: 1234}); const options = Object.assign({}, browserOptions, {port: 1234});
const error = await browserType.launch(options).catch(e => e); const error = await browserType.launch(options).catch(e => e);
expect(error.message).toContain('Cannot specify a port without launching as a server.'); expect(error.message).toContain('Cannot specify a port without launching as a server.');
}); });
it('should throw if port option is passed for persistent context', async ({browserType, defaultBrowserOptions}) => { it('should throw if port option is passed for persistent context', async ({browserType, browserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions, {port: 1234}); const options = Object.assign({}, browserOptions, {port: 1234});
const error = await browserType.launchPersistentContext('foo', options).catch(e => e); const error = await browserType.launchPersistentContext('foo', options).catch(e => e);
expect(error.message).toContain('Cannot specify a port without launching as a server.'); expect(error.message).toContain('Cannot specify a port without launching as a server.');
}); });
it('should throw if page argument is passed', (test, { browserName }) => { it('should throw if page argument is passed', (test, { browserName }) => {
test.skip(browserName === 'firefox'); test.skip(browserName === 'firefox');
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
let waitError = null; let waitError = null;
const options = Object.assign({}, defaultBrowserOptions, { args: ['http://example.com'] }); const options = Object.assign({}, browserOptions, { args: ['http://example.com'] });
await browserType.launch(options).catch(e => waitError = e); await browserType.launch(options).catch(e => waitError = e);
expect(waitError.message).toContain('can not specify page'); expect(waitError.message).toContain('can not specify page');
}); });
it('should reject if launched browser fails immediately', (test, parameters) => { it('should reject if launched browser fails immediately', (test, parameters) => {
test.fixme(`I'm getting ENCONRESET on this one.`); test.fixme(`I'm getting ENCONRESET on this one.`);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions, {executablePath: path.join(__dirname, 'assets', 'dummy_bad_browser_executable.js')}); const options = Object.assign({}, browserOptions, {executablePath: path.join(__dirname, 'assets', 'dummy_bad_browser_executable.js')});
let waitError = null; let waitError = null;
await browserType.launch(options).catch(e => waitError = e); await browserType.launch(options).catch(e => waitError = e);
expect(waitError.message).toContain('== logs =='); expect(waitError.message).toContain('== logs ==');
}); });
it('should reject if executable path is invalid', async ({browserType, defaultBrowserOptions}) => { it('should reject if executable path is invalid', async ({browserType, browserOptions}) => {
let waitError = null; let waitError = null;
const options = Object.assign({}, defaultBrowserOptions, {executablePath: 'random-invalid-path'}); const options = Object.assign({}, browserOptions, {executablePath: 'random-invalid-path'});
await browserType.launch(options).catch(e => waitError = e); await browserType.launch(options).catch(e => waitError = e);
expect(waitError.message).toContain('Failed to launch'); expect(waitError.message).toContain('Failed to launch');
}); });
it('should handle timeout', (test, { wire }) => { it('should handle timeout', (test, { wire }) => {
test.skip(wire); test.skip(wire);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) }; const options = { ...browserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
const error = await browserType.launch(options).catch(e => e); const error = await browserType.launch(options).catch(e => e);
expect(error.message).toContain(`browserType.launch: Timeout 5000ms exceeded.`); expect(error.message).toContain(`browserType.launch: Timeout 5000ms exceeded.`);
expect(error.message).toContain(`<launching>`); expect(error.message).toContain(`<launching>`);
@ -85,32 +85,32 @@ it('should handle timeout', (test, { wire }) => {
it('should handle exception', (test, { wire }) => { it('should handle exception', (test, { wire }) => {
test.skip(wire); test.skip(wire);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const e = new Error('Dummy'); const e = new Error('Dummy');
const options = { ...defaultBrowserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 }; const options = { ...browserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
const error = await browserType.launch(options).catch(e => e); const error = await browserType.launch(options).catch(e => e);
expect(error.message).toContain('Dummy'); expect(error.message).toContain('Dummy');
}); });
it('should report launch log', (test, { wire }) => { it('should report launch log', (test, { wire }) => {
test.skip(wire); test.skip(wire);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const e = new Error('Dummy'); const e = new Error('Dummy');
const options = { ...defaultBrowserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 }; const options = { ...browserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
const error = await browserType.launch(options).catch(e => e); const error = await browserType.launch(options).catch(e => e);
expect(error.message).toContain('<launching>'); expect(error.message).toContain('<launching>');
}); });
it('should accept objects as options', (test, parameters) => { it('should accept objects as options', (test, parameters) => {
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
// @ts-expect-error process is not a real option. // @ts-expect-error process is not a real option.
const browser = await browserType.launch({ ...defaultBrowserOptions, process }); const browser = await browserType.launch({ ...browserOptions, process });
await browser.close(); await browser.close();
}); });
it('should fire close event for all contexts', async ({browserType, defaultBrowserOptions}) => { it('should fire close event for all contexts', async ({browserType, browserOptions}) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
const context = await browser.newContext(); const context = await browser.newContext();
let closed = false; let closed = false;
context.on('close', () => closed = true); context.on('close', () => closed = true);
@ -118,8 +118,8 @@ it('should fire close event for all contexts', async ({browserType, defaultBrows
expect(closed).toBe(true); expect(closed).toBe(true);
}); });
it('should be callable twice', async ({browserType, defaultBrowserOptions}) => { it('should be callable twice', async ({browserType, browserOptions}) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
await Promise.all([ await Promise.all([
browser.close(), browser.close(),
browser.close(), browser.close(),

View file

@ -118,7 +118,7 @@ it('should scope CDPSession handles', (test, { browserName }) => {
await expectScopeState(browserType, GOLDEN_PRECONDITION); await expectScopeState(browserType, GOLDEN_PRECONDITION);
}); });
it('should scope browser handles', async ({browserType, defaultBrowserOptions}) => { it('should scope browser handles', async ({browserType, browserOptions}) => {
const GOLDEN_PRECONDITION = { const GOLDEN_PRECONDITION = {
_guid: '', _guid: '',
objects: [ objects: [
@ -135,7 +135,7 @@ it('should scope browser handles', async ({browserType, defaultBrowserOptions})
}; };
await expectScopeState(browserType, GOLDEN_PRECONDITION); await expectScopeState(browserType, GOLDEN_PRECONDITION);
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
await browser.newContext(); await browser.newContext();
await expectScopeState(browserType, { await expectScopeState(browserType, {
_guid: '', _guid: '',
@ -161,8 +161,8 @@ it('should scope browser handles', async ({browserType, defaultBrowserOptions})
await expectScopeState(browserType, GOLDEN_PRECONDITION); await expectScopeState(browserType, GOLDEN_PRECONDITION);
}); });
it('should work with the domain module', async ({ domain, browserType, defaultBrowserOptions }) => { it('should work with the domain module', async ({ domain, browserType, browserOptions }) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
const page = await browser.newPage(); const page = await browser.newPage();
const result = await page.evaluate(() => 1 + 1); const result = await page.evaluate(() => 1 + 1);
expect(result).toBe(2); expect(result).toBe(2);

View file

@ -20,8 +20,8 @@ import type { ChromiumBrowser, ChromiumBrowserContext } from '../..';
it('should throw with remote-debugging-pipe argument', (test, { browserName, wire }) => { it('should throw with remote-debugging-pipe argument', (test, { browserName, wire }) => {
test.skip(wire || browserName !== 'chromium'); test.skip(wire || browserName !== 'chromium');
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, browserOptions);
options.args = ['--remote-debugging-pipe'].concat(options.args || []); options.args = ['--remote-debugging-pipe'].concat(options.args || []);
const error = await browserType.launchServer(options).catch(e => e); const error = await browserType.launchServer(options).catch(e => e);
expect(error.message).toContain('Playwright manages remote debugging connection itself'); expect(error.message).toContain('Playwright manages remote debugging connection itself');
@ -29,8 +29,8 @@ it('should throw with remote-debugging-pipe argument', (test, { browserName, wir
it('should not throw with remote-debugging-port argument', (test, { browserName, wire }) => { it('should not throw with remote-debugging-port argument', (test, { browserName, wire }) => {
test.skip(wire || browserName !== 'chromium'); test.skip(wire || browserName !== 'chromium');
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, browserOptions);
options.args = ['--remote-debugging-port=0'].concat(options.args || []); options.args = ['--remote-debugging-port=0'].concat(options.args || []);
const browser = await browserType.launchServer(options); const browser = await browserType.launchServer(options);
await browser.close(); await browser.close();
@ -38,14 +38,14 @@ it('should not throw with remote-debugging-port argument', (test, { browserName,
it('should open devtools when "devtools: true" option is given', (test, { wire, browserName, platform}) => { it('should open devtools when "devtools: true" option is given', (test, { wire, browserName, platform}) => {
test.skip(browserName !== 'chromium' || wire || platform === 'win32'); test.skip(browserName !== 'chromium' || wire || platform === 'win32');
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
let devtoolsCallback; let devtoolsCallback;
const devtoolsPromise = new Promise(f => devtoolsCallback = f); const devtoolsPromise = new Promise(f => devtoolsCallback = f);
const __testHookForDevTools = devtools => devtools.__testHookOnBinding = parsed => { const __testHookForDevTools = devtools => devtools.__testHookOnBinding = parsed => {
if (parsed.method === 'getPreferences') if (parsed.method === 'getPreferences')
devtoolsCallback(); devtoolsCallback();
}; };
const browser = await browserType.launch({...defaultBrowserOptions, headless: false, devtools: true, __testHookForDevTools} as any); const browser = await browserType.launch({...browserOptions, headless: false, devtools: true, __testHookForDevTools} as any);
const context = await browser.newContext(); const context = await browser.newContext();
await Promise.all([ await Promise.all([
devtoolsPromise, devtoolsPromise,
@ -56,10 +56,10 @@ it('should open devtools when "devtools: true" option is given', (test, { wire,
it('should return background pages', (test, { browserName }) => { it('should return background pages', (test, { browserName }) => {
test.skip(browserName !== 'chromium'); test.skip(browserName !== 'chromium');
}, async ({browserType, defaultBrowserOptions, createUserDataDir}) => { }, async ({browserType, browserOptions, createUserDataDir}) => {
const userDataDir = await createUserDataDir(); const userDataDir = await createUserDataDir();
const extensionPath = path.join(__dirname, '..', 'assets', 'simple-extension'); const extensionPath = path.join(__dirname, '..', 'assets', 'simple-extension');
const extensionOptions = {...defaultBrowserOptions, const extensionOptions = {...browserOptions,
headless: false, headless: false,
args: [ args: [
`--disable-extensions-except=${extensionPath}`, `--disable-extensions-except=${extensionPath}`,
@ -79,8 +79,8 @@ it('should return background pages', (test, { browserName }) => {
it('should not create pages automatically', (test, { browserName }) => { it('should not create pages automatically', (test, { browserName }) => {
test.skip(browserName !== 'chromium'); test.skip(browserName !== 'chromium');
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
const browserSession = await (browser as ChromiumBrowser).newBrowserCDPSession(); const browserSession = await (browser as ChromiumBrowser).newBrowserCDPSession();
const targets = []; const targets = [];
browserSession.on('Target.targetCreated', async ({targetInfo}) => { browserSession.on('Target.targetCreated', async ({targetInfo}) => {

View file

@ -17,10 +17,10 @@
import { folio } from '../fixtures'; import { folio } from '../fixtures';
const fixtures = folio.extend(); const fixtures = folio.extend();
fixtures.browser.override(async ({browserType, defaultBrowserOptions}, run) => { fixtures.browser.override(async ({browserType, browserOptions}, run) => {
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
args: (defaultBrowserOptions.args || []).concat(['--site-per-process']) args: (browserOptions.args || []).concat(['--site-per-process'])
}); });
await run(browser); await run(browser);
await browser.close(); await browser.close();
@ -240,10 +240,10 @@ describe('oopif', (suite, { browserName }) => {
expect(await page.evaluate(() => window['BUTTON_CLICKED'])).toBe(true); expect(await page.evaluate(() => window['BUTTON_CLICKED'])).toBe(true);
}); });
it('should report google.com frame with headful', async ({browserType, defaultBrowserOptions, server}) => { it('should report google.com frame with headful', async ({browserType, browserOptions, server}) => {
// @see https://github.com/GoogleChrome/puppeteer/issues/2548 // @see https://github.com/GoogleChrome/puppeteer/issues/2548
// https://google.com is isolated by default in Chromium embedder. // https://google.com is isolated by default in Chromium embedder.
const browser = await browserType.launch({...defaultBrowserOptions, headless: false}); const browser = await browserType.launch({...browserOptions, headless: false});
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.route('**/*', route => { await page.route('**/*', route => {

View file

@ -79,9 +79,9 @@ it('should support extraHTTPHeaders option', (test, { browserName, platform, hea
it('should accept userDataDir', (test, { browserName }) => { it('should accept userDataDir', (test, { browserName }) => {
test.flaky(browserName === 'chromium'); test.flaky(browserName === 'chromium');
}, async ({createUserDataDir, browserType, defaultBrowserOptions}) => { }, async ({createUserDataDir, browserType, browserOptions}) => {
const userDataDir = await createUserDataDir(); const userDataDir = await createUserDataDir();
const context = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions); const context = await browserType.launchPersistentContext(userDataDir, browserOptions);
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
await context.close(); await context.close();
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0); expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
@ -89,22 +89,22 @@ it('should accept userDataDir', (test, { browserName }) => {
it('should restore state from userDataDir', (test, { browserName }) => { it('should restore state from userDataDir', (test, { browserName }) => {
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions, server, createUserDataDir}) => { }, async ({browserType, browserOptions, server, createUserDataDir}) => {
const userDataDir = await createUserDataDir(); const userDataDir = await createUserDataDir();
const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions); const browserContext = await browserType.launchPersistentContext(userDataDir, browserOptions);
const page = await browserContext.newPage(); const page = await browserContext.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => localStorage.hey = 'hello'); await page.evaluate(() => localStorage.hey = 'hello');
await browserContext.close(); await browserContext.close();
const browserContext2 = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions); const browserContext2 = await browserType.launchPersistentContext(userDataDir, browserOptions);
const page2 = await browserContext2.newPage(); const page2 = await browserContext2.newPage();
await page2.goto(server.EMPTY_PAGE); await page2.goto(server.EMPTY_PAGE);
expect(await page2.evaluate(() => localStorage.hey)).toBe('hello'); expect(await page2.evaluate(() => localStorage.hey)).toBe('hello');
await browserContext2.close(); await browserContext2.close();
const userDataDir2 = await createUserDataDir(); const userDataDir2 = await createUserDataDir();
const browserContext3 = await browserType.launchPersistentContext(userDataDir2, defaultBrowserOptions); const browserContext3 = await browserType.launchPersistentContext(userDataDir2, browserOptions);
const page3 = await browserContext3.newPage(); const page3 = await browserContext3.newPage();
await page3.goto(server.EMPTY_PAGE); await page3.goto(server.EMPTY_PAGE);
expect(await page3.evaluate(() => localStorage.hey)).not.toBe('hello'); expect(await page3.evaluate(() => localStorage.hey)).not.toBe('hello');
@ -114,9 +114,9 @@ it('should restore state from userDataDir', (test, { browserName }) => {
it('should restore cookies from userDataDir', (test, { browserName }) => { it('should restore cookies from userDataDir', (test, { browserName }) => {
test.slow(); test.slow();
test.flaky(browserName === 'chromium'); test.flaky(browserName === 'chromium');
}, async ({browserType, defaultBrowserOptions, server, createUserDataDir}) => { }, async ({browserType, browserOptions, server, createUserDataDir}) => {
const userDataDir = await createUserDataDir(); const userDataDir = await createUserDataDir();
const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions); const browserContext = await browserType.launchPersistentContext(userDataDir, browserOptions);
const page = await browserContext.newPage(); const page = await browserContext.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const documentCookie = await page.evaluate(() => { const documentCookie = await page.evaluate(() => {
@ -126,14 +126,14 @@ it('should restore cookies from userDataDir', (test, { browserName }) => {
expect(documentCookie).toBe('doSomethingOnlyOnce=true'); expect(documentCookie).toBe('doSomethingOnlyOnce=true');
await browserContext.close(); await browserContext.close();
const browserContext2 = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions); const browserContext2 = await browserType.launchPersistentContext(userDataDir, browserOptions);
const page2 = await browserContext2.newPage(); const page2 = await browserContext2.newPage();
await page2.goto(server.EMPTY_PAGE); await page2.goto(server.EMPTY_PAGE);
expect(await page2.evaluate(() => document.cookie)).toBe('doSomethingOnlyOnce=true'); expect(await page2.evaluate(() => document.cookie)).toBe('doSomethingOnlyOnce=true');
await browserContext2.close(); await browserContext2.close();
const userDataDir2 = await createUserDataDir(); const userDataDir2 = await createUserDataDir();
const browserContext3 = await browserType.launchPersistentContext(userDataDir2, defaultBrowserOptions); const browserContext3 = await browserType.launchPersistentContext(userDataDir2, browserOptions);
const page3 = await browserContext3.newPage(); const page3 = await browserContext3.newPage();
await page3.goto(server.EMPTY_PAGE); await page3.goto(server.EMPTY_PAGE);
expect(await page3.evaluate(() => document.cookie)).not.toBe('doSomethingOnlyOnce=true'); expect(await page3.evaluate(() => document.cookie)).not.toBe('doSomethingOnlyOnce=true');
@ -148,19 +148,19 @@ it('should have default URL when launching browser', async ({launchPersistent})
it('should throw if page argument is passed', (test, { browserName }) => { it('should throw if page argument is passed', (test, { browserName }) => {
test.skip(browserName === 'firefox'); test.skip(browserName === 'firefox');
}, async ({browserType, defaultBrowserOptions, server, createUserDataDir}) => { }, async ({browserType, browserOptions, server, createUserDataDir}) => {
const options = {...defaultBrowserOptions, args: [server.EMPTY_PAGE] }; const options = {...browserOptions, args: [server.EMPTY_PAGE] };
const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e); const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e);
expect(error.message).toContain('can not specify page'); expect(error.message).toContain('can not specify page');
}); });
it('should have passed URL when launching with ignoreDefaultArgs: true', (test, { wire }) => { it('should have passed URL when launching with ignoreDefaultArgs: true', (test, { wire }) => {
test.skip(wire); test.skip(wire);
}, async ({browserType, defaultBrowserOptions, server, createUserDataDir, toImpl}) => { }, async ({browserType, browserOptions, server, createUserDataDir, toImpl}) => {
const userDataDir = await createUserDataDir(); const userDataDir = await createUserDataDir();
const args = toImpl(browserType)._defaultArgs(defaultBrowserOptions, 'persistent', userDataDir, 0).filter(a => a !== 'about:blank'); const args = toImpl(browserType)._defaultArgs(browserOptions, 'persistent', userDataDir, 0).filter(a => a !== 'about:blank');
const options = { const options = {
...defaultBrowserOptions, ...browserOptions,
args: [...args, server.EMPTY_PAGE], args: [...args, server.EMPTY_PAGE],
ignoreDefaultArgs: true, ignoreDefaultArgs: true,
}; };
@ -175,17 +175,17 @@ it('should have passed URL when launching with ignoreDefaultArgs: true', (test,
it('should handle timeout', (test, { wire }) => { it('should handle timeout', (test, { wire }) => {
test.skip(wire); test.skip(wire);
}, async ({browserType, defaultBrowserOptions, createUserDataDir}) => { }, async ({browserType, browserOptions, createUserDataDir}) => {
const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) }; const options = { ...browserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e); const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e);
expect(error.message).toContain(`browserType.launchPersistentContext: Timeout 5000ms exceeded.`); expect(error.message).toContain(`browserType.launchPersistentContext: Timeout 5000ms exceeded.`);
}); });
it('should handle exception', (test, { wire }) => { it('should handle exception', (test, { wire }) => {
test.skip(wire); test.skip(wire);
}, async ({browserType, defaultBrowserOptions, createUserDataDir}) => { }, async ({browserType, browserOptions, createUserDataDir}) => {
const e = new Error('Dummy'); const e = new Error('Dummy');
const options = { ...defaultBrowserOptions, __testHookBeforeCreateBrowser: () => { throw e; } }; const options = { ...browserOptions, __testHookBeforeCreateBrowser: () => { throw e; } };
const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e); const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e);
expect(error.message).toContain('Dummy'); expect(error.message).toContain('Dummy');
}); });

View file

@ -344,8 +344,8 @@ describe('download event', () => {
expect(fs.existsSync(path2)).toBeFalsy(); expect(fs.existsSync(path2)).toBeFalsy();
}); });
it('should delete downloads on browser gone', async ({ server, browserType, defaultBrowserOptions }) => { it('should delete downloads on browser gone', async ({ server, browserType, browserOptions }) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
const page = await browser.newPage({ acceptDownloads: true }); const page = await browser.newPage({ acceptDownloads: true });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`); await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
const [ download1 ] = await Promise.all([ const [ download1 ] = await Promise.all([

View file

@ -25,14 +25,14 @@ type TestState = {
}; };
const fixtures = folio.extend<{}, TestState>(); const fixtures = folio.extend<{}, TestState>();
fixtures.downloadsBrowser.init(async ({ server, browserType, defaultBrowserOptions, testInfo }, test) => { fixtures.downloadsBrowser.init(async ({ server, browserType, browserOptions, testInfo }, test) => {
server.setRoute('/download', (req, res) => { server.setRoute('/download', (req, res) => {
res.setHeader('Content-Type', 'application/octet-stream'); res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', 'attachment; filename=file.txt'); res.setHeader('Content-Disposition', 'attachment; filename=file.txt');
res.end(`Hello world`); res.end(`Hello world`);
}); });
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
downloadsPath: testInfo.outputPath(''), downloadsPath: testInfo.outputPath(''),
}); });
await test(browser); await test(browser);

View file

@ -17,9 +17,9 @@ import { it, expect } from '../fixtures';
it('should pass firefox user preferences', (test, { browserName }) => { it('should pass firefox user preferences', (test, { browserName }) => {
test.skip(browserName !== 'firefox'); test.skip(browserName !== 'firefox');
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, browserOptions}) => {
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
firefoxUserPrefs: { firefoxUserPrefs: {
'network.proxy.type': 1, 'network.proxy.type': 1,
'network.proxy.http': '127.0.0.1', 'network.proxy.http': '127.0.0.1',

View file

@ -72,13 +72,13 @@ fixtures.createUserDataDir.init(async ({ }, run) => {
await Promise.all(dirs.map(dir => removeFolderAsync(dir).catch(e => { }))); await Promise.all(dirs.map(dir => removeFolderAsync(dir).catch(e => { })));
}); });
fixtures.launchPersistent.init(async ({ createUserDataDir, defaultBrowserOptions, browserType }, run) => { fixtures.launchPersistent.init(async ({ createUserDataDir, browserOptions, browserType }, run) => {
let context; let context;
async function launchPersistent(options) { async function launchPersistent(options) {
if (context) if (context)
throw new Error('can only launch one persitent context'); throw new Error('can only launch one persitent context');
const userDataDir = await createUserDataDir(); const userDataDir = await createUserDataDir();
context = await browserType.launchPersistentContext(userDataDir, { ...defaultBrowserOptions, ...options }); context = await browserType.launchPersistentContext(userDataDir, { ...browserOptions, ...options });
const page = context.pages()[0]; const page = context.pages()[0];
return { context, page }; return { context, page };
} }
@ -87,7 +87,7 @@ fixtures.launchPersistent.init(async ({ createUserDataDir, defaultBrowserOptions
await context.close(); await context.close();
}); });
fixtures.defaultBrowserOptions.override(async ({ browserName, headful, slowMo }, run) => { fixtures.browserOptions.override(async ({ browserName, headful, slowMo }, run) => {
const executablePath = getExecutablePath(browserName); const executablePath = getExecutablePath(browserName);
if (executablePath) if (executablePath)
console.error(`Using executable at ${executablePath}`); console.error(`Using executable at ${executablePath}`);

View file

@ -16,8 +16,8 @@
import { it, expect } from './fixtures'; import { it, expect } from './fixtures';
it('should have default url when launching browser', async ({browserType, defaultBrowserOptions, createUserDataDir}) => { it('should have default url when launching browser', async ({browserType, browserOptions, createUserDataDir}) => {
const browserContext = await browserType.launchPersistentContext(await createUserDataDir(), {...defaultBrowserOptions, headless: false }); const browserContext = await browserType.launchPersistentContext(await createUserDataDir(), {...browserOptions, headless: false });
const urls = browserContext.pages().map(page => page.url()); const urls = browserContext.pages().map(page => page.url());
expect(urls).toEqual(['about:blank']); expect(urls).toEqual(['about:blank']);
await browserContext.close(); await browserContext.close();
@ -27,17 +27,17 @@ it('headless should be able to read cookies written by headful', (test, { browse
test.fail(platform === 'win32' && browserName === 'chromium'); test.fail(platform === 'win32' && browserName === 'chromium');
test.flaky(browserName === 'firefox'); test.flaky(browserName === 'firefox');
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions, server, createUserDataDir}) => { }, async ({browserType, browserOptions, server, createUserDataDir}) => {
// see https://github.com/microsoft/playwright/issues/717 // see https://github.com/microsoft/playwright/issues/717
const userDataDir = await createUserDataDir(); const userDataDir = await createUserDataDir();
// Write a cookie in headful chrome // Write a cookie in headful chrome
const headfulContext = await browserType.launchPersistentContext(userDataDir, {...defaultBrowserOptions, headless: false}); const headfulContext = await browserType.launchPersistentContext(userDataDir, {...browserOptions, headless: false});
const headfulPage = await headfulContext.newPage(); const headfulPage = await headfulContext.newPage();
await headfulPage.goto(server.EMPTY_PAGE); await headfulPage.goto(server.EMPTY_PAGE);
await headfulPage.evaluate(() => document.cookie = 'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'); await headfulPage.evaluate(() => document.cookie = 'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT');
await headfulContext.close(); await headfulContext.close();
// Read the cookie from headless chrome // Read the cookie from headless chrome
const headlessContext = await browserType.launchPersistentContext(userDataDir, {...defaultBrowserOptions, headless: true}); const headlessContext = await browserType.launchPersistentContext(userDataDir, {...browserOptions, headless: true});
const headlessPage = await headlessContext.newPage(); const headlessPage = await headlessContext.newPage();
await headlessPage.goto(server.EMPTY_PAGE); await headlessPage.goto(server.EMPTY_PAGE);
const cookie = await headlessPage.evaluate(() => document.cookie); const cookie = await headlessPage.evaluate(() => document.cookie);
@ -47,8 +47,8 @@ it('headless should be able to read cookies written by headful', (test, { browse
it('should close browser with beforeunload page', (test, parameters) => { it('should close browser with beforeunload page', (test, parameters) => {
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions, server, createUserDataDir}) => { }, async ({browserType, browserOptions, server, createUserDataDir}) => {
const browserContext = await browserType.launchPersistentContext(await createUserDataDir(), {...defaultBrowserOptions, headless: false}); const browserContext = await browserType.launchPersistentContext(await createUserDataDir(), {...browserOptions, headless: false});
const page = await browserContext.newPage(); const page = await browserContext.newPage();
await page.goto(server.PREFIX + '/beforeunload.html'); await page.goto(server.PREFIX + '/beforeunload.html');
// We have to interact with a page so that 'beforeunload' handlers // We have to interact with a page so that 'beforeunload' handlers
@ -57,8 +57,8 @@ it('should close browser with beforeunload page', (test, parameters) => {
await browserContext.close(); await browserContext.close();
}); });
it('should not crash when creating second context', async ({browserType, defaultBrowserOptions}) => { it('should not crash when creating second context', async ({browserType, browserOptions}) => {
const browser = await browserType.launch({...defaultBrowserOptions, headless: false }); const browser = await browserType.launch({...browserOptions, headless: false });
{ {
const browserContext = await browser.newContext(); const browserContext = await browser.newContext();
await browserContext.newPage(); await browserContext.newPage();
@ -72,8 +72,8 @@ it('should not crash when creating second context', async ({browserType, default
await browser.close(); await browser.close();
}); });
it('should click background tab', async ({browserType, defaultBrowserOptions, server}) => { it('should click background tab', async ({browserType, browserOptions, server}) => {
const browser = await browserType.launch({...defaultBrowserOptions, headless: false }); const browser = await browserType.launch({...browserOptions, headless: false });
const page = await browser.newPage(); const page = await browser.newPage();
await page.setContent(`<button>Hello</button><a target=_blank href="${server.EMPTY_PAGE}">empty.html</a>`); await page.setContent(`<button>Hello</button><a target=_blank href="${server.EMPTY_PAGE}">empty.html</a>`);
await page.click('a'); await page.click('a');
@ -81,16 +81,16 @@ it('should click background tab', async ({browserType, defaultBrowserOptions, se
await browser.close(); await browser.close();
}); });
it('should close browser after context menu was triggered', async ({browserType, defaultBrowserOptions, server}) => { it('should close browser after context menu was triggered', async ({browserType, browserOptions, server}) => {
const browser = await browserType.launch({...defaultBrowserOptions, headless: false }); const browser = await browserType.launch({...browserOptions, headless: false });
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
await page.click('body', {button: 'right'}); await page.click('body', {button: 'right'});
await browser.close(); await browser.close();
}); });
it('should(not) block third party cookies', async ({browserType, defaultBrowserOptions, server, isChromium, isFirefox}) => { it('should(not) block third party cookies', async ({browserType, browserOptions, server, isChromium, isFirefox}) => {
const browser = await browserType.launch({...defaultBrowserOptions, headless: false }); const browser = await browserType.launch({...browserOptions, headless: false });
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(src => { await page.evaluate(src => {
@ -131,9 +131,9 @@ it('should(not) block third party cookies', async ({browserType, defaultBrowserO
it('should not override viewport size when passed null', (test, { browserName }) => { it('should not override viewport size when passed null', (test, { browserName }) => {
test.fixme(browserName === 'webkit'); test.fixme(browserName === 'webkit');
}, async function({browserType, defaultBrowserOptions, server}) { }, async function({browserType, browserOptions, server}) {
// Our WebKit embedder does not respect window features. // Our WebKit embedder does not respect window features.
const browser = await browserType.launch({...defaultBrowserOptions, headless: false }); const browser = await browserType.launch({...browserOptions, headless: false });
const context = await browser.newContext({ viewport: null }); const context = await browser.newContext({ viewport: null });
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -150,8 +150,8 @@ it('should not override viewport size when passed null', (test, { browserName })
await browser.close(); await browser.close();
}); });
it('Page.bringToFront should work', async ({browserType, defaultBrowserOptions}) => { it('Page.bringToFront should work', async ({browserType, browserOptions}) => {
const browser = await browserType.launch({...defaultBrowserOptions, headless: false }); const browser = await browserType.launch({...browserOptions, headless: false });
const page1 = await browser.newPage(); const page1 = await browser.newPage();
await page1.setContent('Page1'); await page1.setContent('Page1');
const page2 = await browser.newPage(); const page2 = await browser.newPage();

View file

@ -16,9 +16,9 @@
import { it, expect } from './fixtures'; import { it, expect } from './fixtures';
it('should log', async ({browserType, defaultBrowserOptions}) => { it('should log', async ({browserType, browserOptions}) => {
const log = []; const log = [];
const browser = await browserType.launch({...defaultBrowserOptions, logger: { const browser = await browserType.launch({...browserOptions, logger: {
log: (name, severity, message) => log.push({name, severity, message}), log: (name, severity, message) => log.push({name, severity, message}),
isEnabled: (name, severity) => severity !== 'verbose' isEnabled: (name, severity) => severity !== 'verbose'
}}); }});
@ -30,9 +30,9 @@ it('should log', async ({browserType, defaultBrowserOptions}) => {
expect(log.filter(item => item.message.includes('browserType.launch succeeded')).length > 0).toBeTruthy(); expect(log.filter(item => item.message.includes('browserType.launch succeeded')).length > 0).toBeTruthy();
}); });
it('should log context-level', async ({browserType, defaultBrowserOptions}) => { it('should log context-level', async ({browserType, browserOptions}) => {
const log = []; const log = [];
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
const context = await browser.newContext({ const context = await browser.newContext({
logger: { logger: {
log: (name, severity, message) => log.push({name, severity, message}), log: (name, severity, message) => log.push({name, severity, message}),

View file

@ -361,7 +361,6 @@ it('should not leak listeners during bad navigation', async ({page, server}) =>
}); });
it('should not leak listeners during navigation of 20 pages', (test, parameters) => { it('should not leak listeners during navigation of 20 pages', (test, parameters) => {
test.flaky(parameters.trace, 'Flakes on tracing');
test.slow('We open 20 pages here'); test.slow('We open 20 pages here');
}, async ({page, context, server}) => { }, async ({page, context, server}) => {
let warning = null; let warning = null;

View file

@ -23,7 +23,6 @@
import { config, folio as baseFolio } from 'folio'; import { config, folio as baseFolio } from 'folio';
import type { Browser, BrowserContext, BrowserContextOptions, BrowserType, LaunchOptions, Page } from '../index'; import type { Browser, BrowserContext, BrowserContextOptions, BrowserType, LaunchOptions, Page } from '../index';
import * as path from 'path';
export { expect, config } from 'folio'; export { expect, config } from 'folio';
// Test timeout for e2e tests is 30 seconds. // Test timeout for e2e tests is 30 seconds.
@ -43,8 +42,8 @@ type PlaywrightParameters = {
screenshotOnFailure: boolean; screenshotOnFailure: boolean;
// Slows down Playwright operations by the specified amount of milliseconds. // Slows down Playwright operations by the specified amount of milliseconds.
slowMo: number; slowMo: number;
// Whether to record the execution trace. // Whether to record videos for all tests.
trace: boolean; video: boolean;
}; };
@ -57,7 +56,7 @@ type PlaywrightWorkerFixtures = {
// Browser type (Chromium / WebKit / Firefox) // Browser type (Chromium / WebKit / Firefox)
browserType: BrowserType<Browser>; browserType: BrowserType<Browser>;
// Default browserType.launch() options. // Default browserType.launch() options.
defaultBrowserOptions: LaunchOptions; browserOptions: LaunchOptions;
// Browser instance, shared for the worker. // Browser instance, shared for the worker.
browser: Browser; browser: Browser;
// True iff browserName is Chromium // True iff browserName is Chromium
@ -79,7 +78,7 @@ type PlaywrightWorkerFixtures = {
type PlaywrightTestFixtures = { type PlaywrightTestFixtures = {
// Default browser.newContext() options. // Default browser.newContext() options.
defaultContextOptions: BrowserContextOptions; contextOptions: BrowserContextOptions;
// Factory for creating a context with given additional options. // Factory for creating a context with given additional options.
contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>; contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
// Context instance for test. // Context instance for test.
@ -94,9 +93,9 @@ fixtures.headful.initParameter('Whether to run tests headless or headful', proce
fixtures.platform.initParameter('Operating system', process.platform as ('win32' | 'linux' | 'darwin')); fixtures.platform.initParameter('Operating system', process.platform as ('win32' | 'linux' | 'darwin'));
fixtures.screenshotOnFailure.initParameter('Generate screenshot on failure', false); fixtures.screenshotOnFailure.initParameter('Generate screenshot on failure', false);
fixtures.slowMo.initParameter('Slows down Playwright operations by the specified amount of milliseconds', 0); fixtures.slowMo.initParameter('Slows down Playwright operations by the specified amount of milliseconds', 0);
fixtures.trace.initParameter('Whether to record the execution trace', !!process.env.TRACING); fixtures.video.initParameter('Record videos while running tests', false);
fixtures.defaultBrowserOptions.init(async ({ headful, slowMo }, run) => { fixtures.browserOptions.init(async ({ headful, slowMo }, run) => {
await run({ await run({
handleSIGINT: false, handleSIGINT: false,
slowMo, slowMo,
@ -105,7 +104,7 @@ fixtures.defaultBrowserOptions.init(async ({ headful, slowMo }, run) => {
}, { scope: 'worker' }); }, { scope: 'worker' });
fixtures.playwright.init(async ({ }, run) => { fixtures.playwright.init(async ({ }, run) => {
const playwright = require('../index'); const playwright = require('playwright');
await run(playwright); await run(playwright);
}, { scope: 'worker' }); }, { scope: 'worker' });
@ -114,8 +113,8 @@ fixtures.browserType.init(async ({ playwright, browserName }, run) => {
await run(browserType); await run(browserType);
}, { scope: 'worker' }); }, { scope: 'worker' });
fixtures.browser.init(async ({ browserType, defaultBrowserOptions }, run) => { fixtures.browser.init(async ({ browserType, browserOptions }, run) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(browserOptions);
await run(browser); await run(browser);
await browser.close(); await browser.close();
}, { scope: 'worker' }); }, { scope: 'worker' });
@ -144,22 +143,20 @@ fixtures.isLinux.init(async ({ platform }, run) => {
await run(platform === 'linux'); await run(platform === 'linux');
}, { scope: 'worker' }); }, { scope: 'worker' });
fixtures.defaultContextOptions.init(async ({ trace, testInfo }, run) => { fixtures.contextOptions.init(async ({ video, testInfo }, run) => {
if (trace || testInfo.retry) { if (video) {
await run({ await run({
_traceResourcesPath: path.join(config.outputDir, 'trace-resources'),
_tracePath: testInfo.outputPath('playwright.trace'),
videosPath: testInfo.outputPath(''), videosPath: testInfo.outputPath(''),
} as any); });
} else { } else {
await run({}); await run({});
} }
}); });
fixtures.contextFactory.init(async ({ browser, defaultContextOptions, testInfo, screenshotOnFailure }, run) => { fixtures.contextFactory.init(async ({ browser, contextOptions, testInfo, screenshotOnFailure }, run) => {
const contexts: BrowserContext[] = []; const contexts: BrowserContext[] = [];
async function contextFactory(options: BrowserContextOptions = {}) { async function contextFactory(options: BrowserContextOptions = {}) {
const context = await browser.newContext({ ...defaultContextOptions, ...options }); const context = await browser.newContext({ ...contextOptions, ...options });
contexts.push(context); contexts.push(context);
return context; return context;
} }

View file

@ -18,21 +18,21 @@ import { it, expect } from './fixtures';
import socks from 'socksv5'; import socks from 'socksv5';
it('should throw for bad server value', async ({browserType, defaultBrowserOptions}) => { it('should throw for bad server value', async ({browserType, browserOptions}) => {
const error = await browserType.launch({ const error = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
// @ts-expect-error server must be a string // @ts-expect-error server must be a string
proxy: { server: 123 } proxy: { server: 123 }
}).catch(e => e); }).catch(e => e);
expect(error.message).toContain('proxy.server: expected string, got number'); expect(error.message).toContain('proxy.server: expected string, got number');
}); });
it('should use proxy', async ({browserType, defaultBrowserOptions, server}) => { it('should use proxy', async ({browserType, browserOptions, server}) => {
server.setRoute('/target.html', async (req, res) => { server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>'); res.end('<html><title>Served by the proxy</title></html>');
}); });
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
proxy: { server: `localhost:${server.PORT}` } proxy: { server: `localhost:${server.PORT}` }
}); });
const page = await browser.newPage(); const page = await browser.newPage();
@ -41,12 +41,12 @@ it('should use proxy', async ({browserType, defaultBrowserOptions, server}) => {
await browser.close(); await browser.close();
}); });
it('should work with IP:PORT notion', async ({browserType, defaultBrowserOptions, server}) => { it('should work with IP:PORT notion', async ({browserType, browserOptions, server}) => {
server.setRoute('/target.html', async (req, res) => { server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>'); res.end('<html><title>Served by the proxy</title></html>');
}); });
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
proxy: { server: `127.0.0.1:${server.PORT}` } proxy: { server: `127.0.0.1:${server.PORT}` }
}); });
const page = await browser.newPage(); const page = await browser.newPage();
@ -55,7 +55,7 @@ it('should work with IP:PORT notion', async ({browserType, defaultBrowserOptions
await browser.close(); await browser.close();
}); });
it('should authenticate', async ({browserType, defaultBrowserOptions, server}) => { it('should authenticate', async ({browserType, browserOptions, server}) => {
server.setRoute('/target.html', async (req, res) => { server.setRoute('/target.html', async (req, res) => {
const auth = req.headers['proxy-authorization']; const auth = req.headers['proxy-authorization'];
if (!auth) { if (!auth) {
@ -68,7 +68,7 @@ it('should authenticate', async ({browserType, defaultBrowserOptions, server}) =
} }
}); });
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
proxy: { server: `localhost:${server.PORT}`, username: 'user', password: 'secret' } proxy: { server: `localhost:${server.PORT}`, username: 'user', password: 'secret' }
}); });
const page = await browser.newPage(); const page = await browser.newPage();
@ -79,7 +79,7 @@ it('should authenticate', async ({browserType, defaultBrowserOptions, server}) =
it('should exclude patterns', (test, { browserName, headful }) => { it('should exclude patterns', (test, { browserName, headful }) => {
test.flaky(browserName === 'chromium' && headful, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.'); test.flaky(browserName === 'chromium' && headful, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.');
}, async ({browserType, defaultBrowserOptions, server}) => { }, async ({browserType, browserOptions, server}) => {
server.setRoute('/target.html', async (req, res) => { server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>'); res.end('<html><title>Served by the proxy</title></html>');
}); });
@ -88,7 +88,7 @@ it('should exclude patterns', (test, { browserName, headful }) => {
// //
// @see https://gist.github.com/CollinChaffin/24f6c9652efb3d6d5ef2f5502720ef00 // @see https://gist.github.com/CollinChaffin/24f6c9652efb3d6d5ef2f5502720ef00
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
proxy: { server: `localhost:${server.PORT}`, bypass: '1.non.existent.domain.for.the.test, 2.non.existent.domain.for.the.test, .another.test' } proxy: { server: `localhost:${server.PORT}`, bypass: '1.non.existent.domain.for.the.test, 2.non.existent.domain.for.the.test, .another.test' }
}); });
@ -121,7 +121,7 @@ it('should exclude patterns', (test, { browserName, headful }) => {
it('should use socks proxy', (test, { browserName, platform }) => { it('should use socks proxy', (test, { browserName, platform }) => {
test.flaky(platform === 'darwin' && browserName === 'webkit', 'Intermittent page.goto: The network connection was lost error on bots'); test.flaky(platform === 'darwin' && browserName === 'webkit', 'Intermittent page.goto: The network connection was lost error on bots');
}, async ({ browserType, defaultBrowserOptions, testWorkerIndex }) => { }, async ({ browserType, browserOptions, testWorkerIndex }) => {
const server = socks.createServer((info, accept, deny) => { const server = socks.createServer((info, accept, deny) => {
let socket; let socket;
if ((socket = accept(true))) { if ((socket = accept(true))) {
@ -143,7 +143,7 @@ it('should use socks proxy', (test, { browserName, platform }) => {
server.useAuth(socks.auth.None()); server.useAuth(socks.auth.None());
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
proxy: { server: `socks5://localhost:${socksPort}` } proxy: { server: `socks5://localhost:${socksPort}` }
}); });
const page = await browser.newPage(); const page = await browser.newPage();
@ -153,9 +153,9 @@ it('should use socks proxy', (test, { browserName, platform }) => {
server.close(); server.close();
}); });
it('does launch without a port', async ({ browserType, defaultBrowserOptions }) => { it('does launch without a port', async ({ browserType, browserOptions }) => {
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...browserOptions,
proxy: { server: 'http://localhost' } proxy: { server: 'http://localhost' }
}); });
await browser.close(); await browser.close();

View file

@ -26,16 +26,16 @@ type ServerFixtures = {
}; };
const fixtures = base.extend<{}, ServerFixtures>(); const fixtures = base.extend<{}, ServerFixtures>();
fixtures.remoteServer.init(async ({ browserType, defaultBrowserOptions }, run) => { fixtures.remoteServer.init(async ({ browserType, browserOptions }, run) => {
const remoteServer = new RemoteServer(); const remoteServer = new RemoteServer();
await remoteServer._start(browserType, defaultBrowserOptions); await remoteServer._start(browserType, browserOptions);
await run(remoteServer); await run(remoteServer);
await remoteServer.close(); await remoteServer.close();
}); });
fixtures.stallingRemoteServer.init(async ({ browserType, defaultBrowserOptions }, run) => { fixtures.stallingRemoteServer.init(async ({ browserType, browserOptions }, run) => {
const remoteServer = new RemoteServer(); const remoteServer = new RemoteServer();
await remoteServer._start(browserType, defaultBrowserOptions, { stallOnClose: true }); await remoteServer._start(browserType, browserOptions, { stallOnClose: true });
await run(remoteServer); await run(remoteServer);
await remoteServer.close(); await remoteServer.close();
}); });
@ -55,17 +55,17 @@ export class RemoteServer {
_didExit: boolean; _didExit: boolean;
_wsEndpoint: string; _wsEndpoint: string;
async _start(browserType: BrowserType<Browser>, defaultBrowserOptions: LaunchOptions, extraOptions?: { stallOnClose: boolean; }) { async _start(browserType: BrowserType<Browser>, browserOptions: LaunchOptions, extraOptions?: { stallOnClose: boolean; }) {
this._output = new Map(); this._output = new Map();
this._outputCallback = new Map(); this._outputCallback = new Map();
this._didExit = false; this._didExit = false;
this._browserType = browserType; this._browserType = browserType;
const launchOptions = {...defaultBrowserOptions, const launchOptions = {...browserOptions,
handleSIGINT: true, handleSIGINT: true,
handleSIGTERM: true, handleSIGTERM: true,
handleSIGHUP: true, handleSIGHUP: true,
executablePath: defaultBrowserOptions.executablePath || browserType.executablePath(), executablePath: browserOptions.executablePath || browserType.executablePath(),
logger: undefined, logger: undefined,
}; };
const options = { const options = {