chore: roll test runner to 0.3.9 (#3847)

This commit is contained in:
Pavel Feldman 2020-09-11 10:02:07 -07:00 committed by GitHub
parent 38ed8de23d
commit f94df318d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
77 changed files with 446 additions and 441 deletions

12
package-lock.json generated
View file

@ -1168,9 +1168,9 @@
} }
}, },
"@playwright/test-runner": { "@playwright/test-runner": {
"version": "0.3.5", "version": "0.3.9",
"resolved": "https://registry.npmjs.org/@playwright/test-runner/-/test-runner-0.3.5.tgz", "resolved": "https://registry.npmjs.org/@playwright/test-runner/-/test-runner-0.3.9.tgz",
"integrity": "sha512-G/X9fjqr4ZOyZojQpKAlid7KC8Bw+S834KxSD9nQSqLaN8QFpebFr9xqVhEs/G82RP8DRzxlp8vi5CqLhGrU0w==", "integrity": "sha512-+kFADjH/g7GQ4uXzCJ5/1ke79n2WCnwRsccbrRgCYcUW96/r97FQnywfYZjJnPcTbvJf4DqYBZ2/0wS7pAEmvQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.10.4", "@babel/code-frame": "^7.10.4",
@ -3050,9 +3050,9 @@
} }
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.3.564", "version": "1.3.565",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.564.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.565.tgz",
"integrity": "sha512-fNaYN3EtKQWLQsrKXui8mzcryJXuA0LbCLoizeX6oayG2emBaS5MauKjCPAvc29NEY4FpLHIUWiP+Y0Bfrs5dg==", "integrity": "sha512-me5dGlHFd8Q7mKhqbWRLIYnKjw4i0fO6hmW0JBxa7tM87fBfNEjWokRnDF7V+Qme/9IYpwhfMn+soWs40tXWqg==",
"dev": true "dev": true
}, },
"elliptic": { "elliptic": {

View file

@ -49,7 +49,7 @@
"ws": "^7.3.1" "ws": "^7.3.1"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test-runner": "^0.3.5", "@playwright/test-runner": "^0.3.9",
"@types/debug": "^4.1.5", "@types/debug": "^4.1.5",
"@types/extract-zip": "^1.6.2", "@types/extract-zip": "^1.6.2",
"@types/mime": "^2.0.3", "@types/mime": "^2.0.3",

View file

@ -17,7 +17,7 @@
import { it, expect, describe, options } from './playwright.fixtures'; import { it, expect, describe, options } from './playwright.fixtures';
it('should work', async function({page}) { it('should work', async ({ page, isFirefox, isChromium }) => {
await page.setContent(` await page.setContent(`
<head> <head>
<title>Accessibility Test</title> <title>Accessibility Test</title>
@ -36,7 +36,7 @@ it('should work', async function({page}) {
// autofocus happens after a delay in chrome these days // autofocus happens after a delay in chrome these days
await page.waitForFunction(() => document.activeElement.hasAttribute('autofocus')); await page.waitForFunction(() => document.activeElement.hasAttribute('autofocus'));
const golden = options.FIREFOX ? { const golden = isFirefox ? {
role: 'document', role: 'document',
name: 'Accessibility Test', name: 'Accessibility Test',
children: [ children: [
@ -49,7 +49,7 @@ it('should work', async function({page}) {
{role: 'textbox', name: '', value: 'and a value'}, // firefox doesn't use aria-placeholder for the name {role: 'textbox', name: '', value: 'and a value'}, // firefox doesn't use aria-placeholder for the name
{role: 'textbox', name: '', value: 'and a value', description: 'This is a description!'}, // and here {role: 'textbox', name: '', value: 'and a value', description: 'This is a description!'}, // and here
] ]
} : options.CHROMIUM ? { } : isChromium ? {
role: 'WebArea', role: 'WebArea',
name: 'Accessibility Test', name: 'Accessibility Test',
children: [ children: [
@ -79,11 +79,11 @@ it('should work', async function({page}) {
expect(await page.accessibility.snapshot()).toEqual(golden); expect(await page.accessibility.snapshot()).toEqual(golden);
}); });
it('should work with regular text', async ({page}) => { it('should work with regular text', async ({page, isFirefox}) => {
await page.setContent(`<div>Hello World</div>`); await page.setContent(`<div>Hello World</div>`);
const snapshot = await page.accessibility.snapshot(); const snapshot = await page.accessibility.snapshot();
expect(snapshot.children[0]).toEqual({ expect(snapshot.children[0]).toEqual({
role: options.FIREFOX ? 'text leaf' : 'text', role: isFirefox ? 'text leaf' : 'text',
name: 'Hello World', name: 'Hello World',
}); });
}); });
@ -118,14 +118,14 @@ it('keyshortcuts', async ({page}) => {
expect(snapshot.children[0].keyshortcuts).toEqual('foo'); expect(snapshot.children[0].keyshortcuts).toEqual('foo');
}); });
it('should not report text nodes inside controls', async function({page}) { it('should not report text nodes inside controls', async function({page, isFirefox}) {
await page.setContent(` await page.setContent(`
<div role="tablist"> <div role="tablist">
<div role="tab" aria-selected="true"><b>Tab1</b></div> <div role="tab" aria-selected="true"><b>Tab1</b></div>
<div role="tab">Tab2</div> <div role="tab">Tab2</div>
</div>`); </div>`);
const golden = { const golden = {
role: options.FIREFOX ? 'document' : 'WebArea', role: isFirefox ? 'document' : 'WebArea',
name: '', name: '',
children: [{ children: [{
role: 'tab', role: 'tab',
@ -139,14 +139,14 @@ it('should not report text nodes inside controls', async function({page}) {
expect(await page.accessibility.snapshot()).toEqual(golden); expect(await page.accessibility.snapshot()).toEqual(golden);
}); });
it('rich text editable fields should have children', test => { it('rich text editable fields should have children', (test, parameters) => {
test.skip(options.WEBKIT, 'WebKit rich text accessibility is iffy'); test.skip(options.WEBKIT(parameters), 'WebKit rich text accessibility is iffy');
}, async function({page}) { }, async function({page, isFirefox}) {
await page.setContent(` await page.setContent(`
<div contenteditable="true"> <div contenteditable="true">
Edit this image: <img src="fakeimage.png" alt="my fake image"> Edit this image: <img src="fakeimage.png" alt="my fake image">
</div>`); </div>`);
const golden = options.FIREFOX ? { const golden = isFirefox ? {
role: 'section', role: 'section',
name: '', name: '',
children: [{ children: [{
@ -172,14 +172,14 @@ it('rich text editable fields should have children', test => {
expect(snapshot.children[0]).toEqual(golden); expect(snapshot.children[0]).toEqual(golden);
}); });
it('rich text editable fields with role should have children', test => { it('rich text editable fields with role should have children', (test, parameters) => {
test.skip(options.WEBKIT, 'WebKit rich text accessibility is iffy'); test.skip(options.WEBKIT(parameters), 'WebKit rich text accessibility is iffy');
}, async function({page}) { }, async function({page, isFirefox}) {
await page.setContent(` await page.setContent(`
<div contenteditable="true" role='textbox'> <div contenteditable="true" role='textbox'>
Edit this image: <img src="fakeimage.png" alt="my fake image"> Edit this image: <img src="fakeimage.png" alt="my fake image">
</div>`); </div>`);
const golden = options.FIREFOX ? { const golden = isFirefox ? {
role: 'textbox', role: 'textbox',
name: '', name: '',
value: 'Edit this image: my fake image', value: 'Edit this image: my fake image',
@ -203,9 +203,9 @@ it('rich text editable fields with role should have children', test => {
expect(snapshot.children[0]).toEqual(golden); expect(snapshot.children[0]).toEqual(golden);
}); });
describe('contenteditable', suite => { describe('contenteditable', (suite, parameters) => {
suite.skip(options.FIREFOX, 'Firefox does not support contenteditable="plaintext-only"'); suite.skip(options.FIREFOX(parameters), 'Firefox does not support contenteditable="plaintext-only"');
suite.skip(options.WEBKIT, 'WebKit rich text accessibility is iffy'); suite.skip(options.WEBKIT(parameters), 'WebKit rich text accessibility is iffy');
}, () => { }, () => {
it('plain text field with role should not have children', async function({page}) { it('plain text field with role should not have children', async function({page}) {
await page.setContent(` await page.setContent(`
@ -239,17 +239,17 @@ describe('contenteditable', suite => {
}); });
}); });
it('non editable textbox with role and tabIndex and label should not have children', async function({page}) { it('non editable textbox with role and tabIndex and label should not have children', async function({page, isChromium, isFirefox}) {
await page.setContent(` await page.setContent(`
<div role="textbox" tabIndex=0 aria-checked="true" aria-label="my favorite textbox"> <div role="textbox" tabIndex=0 aria-checked="true" aria-label="my favorite textbox">
this is the inner content this is the inner content
<img alt="yo" src="fakeimg.png"> <img alt="yo" src="fakeimg.png">
</div>`); </div>`);
const golden = options.FIREFOX ? { const golden = isFirefox ? {
role: 'textbox', role: 'textbox',
name: 'my favorite textbox', name: 'my favorite textbox',
value: 'this is the inner content yo' value: 'this is the inner content yo'
} : options.CHROMIUM ? { } : isChromium ? {
role: 'textbox', role: 'textbox',
name: 'my favorite textbox', name: 'my favorite textbox',
value: 'this is the inner content ' value: 'this is the inner content '
@ -277,13 +277,13 @@ it('checkbox with and tabIndex and label should not have children', async functi
expect(snapshot.children[0]).toEqual(golden); expect(snapshot.children[0]).toEqual(golden);
}); });
it('checkbox without label should not have children', async function({page}) { it('checkbox without label should not have children', async ({page, isFirefox}) => {
await page.setContent(` await page.setContent(`
<div role="checkbox" aria-checked="true"> <div role="checkbox" aria-checked="true">
this is the inner content this is the inner content
<img alt="yo" src="fakeimg.png"> <img alt="yo" src="fakeimg.png">
</div>`); </div>`);
const golden = options.FIREFOX ? { const golden = isFirefox ? {
role: 'checkbox', role: 'checkbox',
name: 'this is the inner content yo', name: 'this is the inner content yo',
checked: true checked: true
@ -317,7 +317,7 @@ it('should work an input', async ({page}) => {
}); });
}); });
it('should work on a menu', async ({page}) => { it('should work on a menu', async ({page, isWebKit}) => {
await page.setContent(` await page.setContent(`
<div role="menu" title="My Menu"> <div role="menu" title="My Menu">
<div role="menuitem">First Item</div> <div role="menuitem">First Item</div>
@ -334,7 +334,7 @@ it('should work on a menu', async ({page}) => {
[ { role: 'menuitem', name: 'First Item' }, [ { role: 'menuitem', name: 'First Item' },
{ role: 'menuitem', name: 'Second Item' }, { role: 'menuitem', name: 'Second Item' },
{ role: 'menuitem', name: 'Third Item' } ], { role: 'menuitem', name: 'Third Item' } ],
orientation: options.WEBKIT ? 'vertical' : undefined orientation: isWebKit ? 'vertical' : undefined
}); });
}); });

View file

@ -201,7 +201,7 @@ it('should work with goto following click', async ({page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
}); });
it('should report navigation in the log when clicking anchor', test => { it('should report navigation in the log when clicking anchor', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.setContent(`<a href="${server.PREFIX + '/frames/one-frame.html'}">click me</a>`); await page.setContent(`<a href="${server.PREFIX + '/frames/one-frame.html'}">click me</a>`);

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('should create new page', async function({browser}) { it('should create new page', async function({browser}) {
const page1 = await browser.newPage(); const page1 = await browser.newPage();
@ -38,9 +38,9 @@ it('should throw upon second create new page', async function({browser}) {
expect(error.message).toContain('Please use browser.newContext()'); expect(error.message).toContain('Please use browser.newContext()');
}); });
it('version should work', async function({browser}) { it('version should work', async function({browser, isChromium}) {
const version = browser.version(); const version = browser.version();
if (options.CHROMIUM) if (isChromium)
expect(version.match(/^\d+\.\d+\.\d+\.\d+$/)).toBeTruthy(); expect(version.match(/^\d+\.\d+\.\d+\.\d+$/)).toBeTruthy();
else else
expect(version.match(/^\d+\.\d+/)).toBeTruthy(); expect(version.match(/^\d+\.\d+/)).toBeTruthy();

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('should work', async ({context, page, server}) => { it('should work', async ({context, page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -139,7 +139,7 @@ it('should isolate send cookie header', async ({server, context, browser}) => {
} }
}); });
it('should isolate cookies between launches', test => { it('should isolate cookies between launches', (test, parameters) => {
test.slow(); test.slow();
}, async ({browserType, server, defaultBrowserOptions}) => { }, async ({browserType, server, defaultBrowserOptions}) => {
const browser1 = await browserType.launch(defaultBrowserOptions); const browser1 = await browserType.launch(defaultBrowserOptions);
@ -315,7 +315,7 @@ it('should set cookies for a frame', async ({context, page, server}) => {
expect(await page.frames()[1].evaluate('document.cookie')).toBe('frame-cookie=value'); expect(await page.frames()[1].evaluate('document.cookie')).toBe('frame-cookie=value');
}); });
it('should(not) block third party cookies', async ({context, page, server}) => { it('should(not) block third party cookies', async ({context, page, server, isChromium, isFirefox}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(src => { await page.evaluate(src => {
let fulfill; let fulfill;
@ -328,7 +328,7 @@ it('should(not) block third party cookies', async ({context, page, server}) => {
}, server.CROSS_PROCESS_PREFIX + '/grid.html'); }, server.CROSS_PROCESS_PREFIX + '/grid.html');
await page.frames()[1].evaluate(`document.cookie = 'username=John Doe'`); await page.frames()[1].evaluate(`document.cookie = 'username=John Doe'`);
await page.waitForTimeout(2000); await page.waitForTimeout(2000);
const allowsThirdParty = options.CHROMIUM || options.FIREFOX; const allowsThirdParty = isChromium || isFirefox;
const cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + '/grid.html'); const cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + '/grid.html');
if (allowsThirdParty) { if (allowsThirdParty) {
expect(cookies).toEqual([ expect(cookies).toEqual([

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
import utils from './utils'; import utils from './utils';
@ -178,14 +178,14 @@ it('should close all belonging pages once closing context', async function({brow
expect(context.pages().length).toBe(0); expect(context.pages().length).toBe(0);
}); });
it('should disable javascript', async ({browser}) => { it('should disable javascript', async ({browser, isWebKit}) => {
{ {
const context = await browser.newContext({ javaScriptEnabled: false }); const context = await browser.newContext({ javaScriptEnabled: false });
const page = await context.newPage(); const page = await context.newPage();
await page.goto('data:text/html, <script>var something = "forbidden"</script>'); await page.goto('data:text/html, <script>var something = "forbidden"</script>');
let error = null; let error = null;
await page.evaluate('something').catch(e => error = e); await page.evaluate('something').catch(e => error = e);
if (options.WEBKIT) if (isWebKit)
expect(error.message).toContain('Can\'t find variable: something'); expect(error.message).toContain('Can\'t find variable: something');
else else
expect(error.message).toContain('something is not defined'); expect(error.message).toContain('something is not defined');

View file

@ -73,8 +73,8 @@ it('should properly report httpOnly cookie', async ({context, page, server}) =>
expect(cookies[0].httpOnly).toBe(true); expect(cookies[0].httpOnly).toBe(true);
}); });
it('should properly report "Strict" sameSite cookie', test => { it('should properly report "Strict" sameSite cookie', (test, parameters) => {
test.fail(options.WEBKIT && WIN); test.fail(options.WEBKIT(parameters) && WIN);
}, async ({context, page, server}) => { }, async ({context, page, server}) => {
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', 'name=value;SameSite=Strict'); res.setHeader('Set-Cookie', 'name=value;SameSite=Strict');
@ -86,8 +86,8 @@ it('should properly report "Strict" sameSite cookie', test => {
expect(cookies[0].sameSite).toBe('Strict'); expect(cookies[0].sameSite).toBe('Strict');
}); });
it('should properly report "Lax" sameSite cookie', test => { it('should properly report "Lax" sameSite cookie', (test, parameters) => {
test.fail(options.WEBKIT && WIN); test.fail(options.WEBKIT(parameters) && WIN);
}, async ({context, page, server}) => { }, async ({context, page, server}) => {
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', 'name=value;SameSite=Lax'); res.setHeader('Set-Cookie', 'name=value;SameSite=Lax');

View file

@ -17,8 +17,8 @@
import { it, expect, options } from './playwright.fixtures'; import { it, expect, options } from './playwright.fixtures';
it('should fail without credentials', test => { it('should fail without credentials', (test, parameters) => {
test.fail(options.CHROMIUM && !options.HEADLESS); test.fail(options.CHROMIUM(parameters) && !options.HEADLESS);
}, async ({browser, server}) => { }, async ({browser, server}) => {
server.setAuth('/empty.html', 'user', 'pass'); server.setAuth('/empty.html', 'user', 'pass');
const context = await browser.newContext(); const context = await browser.newContext();
@ -28,8 +28,8 @@ it('should fail without credentials', test => {
await context.close(); await context.close();
}); });
it('should work with setHTTPCredentials', test => { it('should work with setHTTPCredentials', (test, parameters) => {
test.fail(options.CHROMIUM && !options.HEADLESS); test.fail(options.CHROMIUM(parameters) && !options.HEADLESS);
}, async ({browser, server}) => { }, async ({browser, server}) => {
server.setAuth('/empty.html', 'user', 'pass'); server.setAuth('/empty.html', 'user', 'pass');
const context = await browser.newContext(); const context = await browser.newContext();

View file

@ -17,8 +17,8 @@
import { it, expect, describe, options } from './playwright.fixtures'; import { it, expect, describe, options } from './playwright.fixtures';
describe('device', suite => { describe('device', (suite, parameters) => {
suite.skip(options.FIREFOX); suite.skip(options.FIREFOX(parameters));
}, () => { }, () => {
it('should work', async ({playwright, browser, server}) => { it('should work', async ({playwright, browser, server}) => {
const iPhone = playwright.devices['iPhone 6']; const iPhone = playwright.devices['iPhone 6'];

View file

@ -157,8 +157,8 @@ it('should fire page lifecycle events', async function({browser, server}) {
await context.close(); await context.close();
}); });
it('should work with Shift-clicking', test => { it('should work with Shift-clicking', (test, parameters) => {
test.fixme(options.WEBKIT, 'WebKit: Shift+Click does not open a new window.'); test.fixme(options.WEBKIT(parameters), 'WebKit: Shift+Click does not open a new window.');
}, async ({browser, server}) => { }, async ({browser, server}) => {
const context = await browser.newContext(); const context = await browser.newContext();
const page = await context.newPage(); const page = await context.newPage();
@ -172,9 +172,9 @@ it('should work with Shift-clicking', test => {
await context.close(); await context.close();
}); });
it('should work with Ctrl-clicking', test => { it('should work with Ctrl-clicking', (test, parameters) => {
test.fixme(options.WEBKIT, 'Ctrl+Click does not open a new tab.'); test.fixme(options.WEBKIT(parameters), 'Ctrl+Click does not open a new tab.');
test.fixme(options.FIREFOX, 'Reports an opener in this case.'); test.fixme(options.FIREFOX(parameters), 'Reports an opener in this case.');
}, async ({browser, server}) => { }, async ({browser, server}) => {
const context = await browser.newContext(); const context = await browser.newContext();
const page = await context.newPage(); const page = await context.newPage();

View file

@ -17,8 +17,8 @@
import { it, expect, describe, options } from './playwright.fixtures'; import { it, expect, describe, options } from './playwright.fixtures';
describe('mobile viewport', suite => { describe('mobile viewport', (suite, parameters) => {
suite.skip(options.FIREFOX); suite.skip(options.FIREFOX(parameters));
}, () => { }, () => {
it('should support mobile emulation', async ({playwright, browser, server}) => { it('should support mobile emulation', async ({playwright, browser, server}) => {
const iPhone = playwright.devices['iPhone 6']; const iPhone = playwright.devices['iPhone 6'];

View file

@ -16,7 +16,7 @@
*/ */
import fs from 'fs'; import fs from 'fs';
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('browserType.executablePath should work', test => { it('browserType.executablePath should work', test => {
test.skip(Boolean(process.env.CRPATH || process.env.FFPATH || process.env.WKPATH)); test.skip(Boolean(process.env.CRPATH || process.env.FFPATH || process.env.WKPATH));
@ -26,12 +26,12 @@ it('browserType.executablePath should work', test => {
expect(fs.realpathSync(executablePath)).toBe(executablePath); expect(fs.realpathSync(executablePath)).toBe(executablePath);
}); });
it('browserType.name should work', async ({browserType}) => { it('browserType.name should work', async ({browserType, isChromium, isFirefox, isWebKit}) => {
if (options.WEBKIT) if (isWebKit)
expect(browserType.name()).toBe('webkit'); expect(browserType.name()).toBe('webkit');
else if (options.FIREFOX) else if (isFirefox)
expect(browserType.name()).toBe('firefox'); expect(browserType.name()).toBe('firefox');
else if (options.CHROMIUM) else if (isChromium)
expect(browserType.name()).toBe('chromium'); expect(browserType.name()).toBe('chromium');
else else
throw new Error('Unknown browser'); throw new Error('Unknown browser');

View file

@ -36,8 +36,8 @@ it('should throw if userDataDir option is passed', async ({browserType, defaultB
expect(waitError.message).toContain('launchPersistentContext'); expect(waitError.message).toContain('launchPersistentContext');
}); });
it('should throw if page argument is passed', test => { it('should throw if page argument is passed', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
let waitError = null; let waitError = null;
const options = Object.assign({}, defaultBrowserOptions, { args: ['http://example.com'] }); const options = Object.assign({}, defaultBrowserOptions, { args: ['http://example.com'] });
@ -45,7 +45,7 @@ it('should throw if page argument is passed', test => {
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 => { 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, defaultBrowserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions, {executablePath: path.join(__dirname, 'assets', 'dummy_bad_browser_executable.js')}); const options = Object.assign({}, defaultBrowserOptions, {executablePath: path.join(__dirname, 'assets', 'dummy_bad_browser_executable.js')});
@ -61,7 +61,7 @@ it('should reject if executable path is invalid', async ({browserType, defaultBr
expect(waitError.message).toContain('Failed to launch'); expect(waitError.message).toContain('Failed to launch');
}); });
it('should handle timeout', test => { it('should handle timeout', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) }; const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
@ -71,7 +71,7 @@ it('should handle timeout', test => {
expect(error.message).toContain(`<launched> pid=`); expect(error.message).toContain(`<launched> pid=`);
}); });
it('should handle exception', test => { it('should handle exception', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const e = new Error('Dummy'); const e = new Error('Dummy');
@ -80,7 +80,7 @@ it('should handle exception', test => {
expect(error.message).toContain('Dummy'); expect(error.message).toContain('Dummy');
}); });
it('should report launch log', test => { it('should report launch log', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const e = new Error('Dummy'); const e = new Error('Dummy');
@ -89,7 +89,7 @@ it('should report launch log', test => {
expect(error.message).toContain('<launching>'); expect(error.message).toContain('<launching>');
}); });
it('should accept objects as options', test => { it('should accept objects as options', (test, parameters) => {
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
// @ts-expect-error process is not a real option. // @ts-expect-error process is not a real option.

View file

@ -17,8 +17,8 @@
import url from 'url'; import url from 'url';
import { it, expect, options } from './playwright.fixtures'; import { it, expect, options } from './playwright.fixtures';
it('Web Assembly should work', test => { it('Web Assembly should work', (test, parameters) => {
test.fail(options.WEBKIT && WIN); test.fail(options.WEBKIT(parameters) && WIN);
}, async function({page, server}) { }, async function({page, server}) {
await page.goto(server.PREFIX + '/wasm/table2.html'); await page.goto(server.PREFIX + '/wasm/table2.html');
expect(await page.evaluate('loadTable()')).toBe('42, 83'); expect(await page.evaluate('loadTable()')).toBe('42, 83');
@ -50,15 +50,15 @@ it('should respect CSP', async ({page, server}) => {
expect(await page.evaluate(() => window['testStatus'])).toBe('SUCCESS'); expect(await page.evaluate(() => window['testStatus'])).toBe('SUCCESS');
}); });
it('should play video', test => { it('should play video', (test, parameters) => {
test.fixme(options.WEBKIT && (WIN || LINUX)); test.fixme(options.WEBKIT(parameters) && (WIN || LINUX));
}, async ({page, asset}) => { }, async ({page, asset, isWebKit}) => {
// TODO: the test passes on Windows locally but fails on GitHub Action bot, // TODO: the test passes on Windows locally but fails on GitHub Action bot,
// apparently due to a Media Pack issue in the Windows Server. // apparently due to a Media Pack issue in the Windows Server.
// Also the test is very flaky on Linux WebKit. // Also the test is very flaky on Linux WebKit.
// //
// Safari only plays mp4 so we test WebKit with an .mp4 clip. // Safari only plays mp4 so we test WebKit with an .mp4 clip.
const fileName = options.WEBKIT ? 'video_mp4.html' : 'video.html'; const fileName = isWebKit ? 'video_mp4.html' : 'video.html';
const absolutePath = asset(fileName); const absolutePath = asset(fileName);
// Our test server doesn't support range requests required to play on Mac, // Our test server doesn't support range requests required to play on Mac,
// so we load the page using a file url. // so we load the page using a file url.

View file

@ -66,8 +66,8 @@ it('should scope context handles', async ({browserType, browser, server}) => {
await expectScopeState(browser, GOLDEN_PRECONDITION); await expectScopeState(browser, GOLDEN_PRECONDITION);
}); });
it('should scope CDPSession handles', test => { it('should scope CDPSession handles', (test, parameters) => {
test.skip(!options.CHROMIUM); test.skip(!options.CHROMIUM(parameters));
}, async ({browserType, browser}) => { }, async ({browserType, browser}) => {
const GOLDEN_PRECONDITION = { const GOLDEN_PRECONDITION = {
_guid: '', _guid: '',

View file

@ -16,8 +16,8 @@
import { it, expect, describe, options } from './playwright.fixtures'; import { it, expect, describe, options } from './playwright.fixtures';
describe('oopif', suite => { describe('oopif', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should work', async function({browserType, page, server}) { it('should work', async function({browserType, page, server}) {
await page.coverage.startCSSCoverage(); await page.coverage.startCSSCoverage();

View file

@ -16,15 +16,15 @@
import { it, expect, describe, options } from './playwright.fixtures'; import { it, expect, describe, options } from './playwright.fixtures';
it('should be missing', test => { it('should be missing', (test, parameters) => {
test.skip(options.CHROMIUM); test.skip(options.CHROMIUM(parameters));
}, },
async function({page}) { async function({page}) {
expect(page.coverage).toBe(null); expect(page.coverage).toBe(null);
}); });
describe('oopif', suite => { describe('oopif', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should work', async function({page, server}) { it('should work', async function({page, server}) {
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();

View file

@ -16,8 +16,8 @@
import { it, expect, describe, options } from '../playwright.fixtures'; import { it, expect, describe, options } from '../playwright.fixtures';
import type { ChromiumBrowserContext } from '../..'; import type { ChromiumBrowserContext } from '../..';
describe('chromium', suite => { describe('chromium', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should create a worker from a service worker', async ({page, server, context}) => { it('should create a worker from a service worker', async ({page, server, context}) => {
const [worker] = await Promise.all([ const [worker] = await Promise.all([

View file

@ -20,8 +20,8 @@ import utils from '../utils';
import type { ChromiumBrowser, ChromiumBrowserContext } from '../..'; import type { ChromiumBrowser, ChromiumBrowserContext } from '../..';
const { makeUserDataDir, removeUserDataDir } = utils; const { makeUserDataDir, removeUserDataDir } = utils;
it('should throw with remote-debugging-pipe argument', test => { it('should throw with remote-debugging-pipe argument', (test, parameters) => {
test.skip(options.WIRE || !options.CHROMIUM); test.skip(options.WIRE || !options.CHROMIUM(parameters));
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, defaultBrowserOptions);
options.args = ['--remote-debugging-pipe'].concat(options.args || []); options.args = ['--remote-debugging-pipe'].concat(options.args || []);
@ -29,8 +29,8 @@ it('should throw with remote-debugging-pipe argument', test => {
expect(error.message).toContain('Playwright manages remote debugging connection itself'); expect(error.message).toContain('Playwright manages remote debugging connection itself');
}); });
it('should not throw with remote-debugging-port argument', test => { it('should not throw with remote-debugging-port argument', (test, parameters) => {
test.skip(options.WIRE || !options.CHROMIUM); test.skip(options.WIRE || !options.CHROMIUM(parameters));
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const options = Object.assign({}, defaultBrowserOptions); const options = Object.assign({}, defaultBrowserOptions);
options.args = ['--remote-debugging-port=0'].concat(options.args || []); options.args = ['--remote-debugging-port=0'].concat(options.args || []);
@ -38,8 +38,8 @@ it('should not throw with remote-debugging-port argument', test => {
await browser.close(); await browser.close();
}); });
it('should open devtools when "devtools: true" option is given', test => { it('should open devtools when "devtools: true" option is given', (test, parameters) => {
test.skip(!options.CHROMIUM || options.WIRE || WIN); test.skip(!options.CHROMIUM(parameters) || options.WIRE || WIN);
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
let devtoolsCallback; let devtoolsCallback;
const devtoolsPromise = new Promise(f => devtoolsCallback = f); const devtoolsPromise = new Promise(f => devtoolsCallback = f);
@ -56,8 +56,8 @@ it('should open devtools when "devtools: true" option is given', test => {
await browser.close(); await browser.close();
}); });
it('should return background pages', test => { it('should return background pages', (test, parameters) => {
test.skip(!options.CHROMIUM); test.skip(!options.CHROMIUM(parameters));
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const userDataDir = await makeUserDataDir(); const userDataDir = await makeUserDataDir();
const extensionPath = path.join(__dirname, '..', 'assets', 'simple-extension'); const extensionPath = path.join(__dirname, '..', 'assets', 'simple-extension');
@ -80,8 +80,8 @@ it('should return background pages', test => {
await removeUserDataDir(userDataDir); await removeUserDataDir(userDataDir);
}); });
it('should not create pages automatically', test => { it('should not create pages automatically', (test, parameters) => {
test.skip(!options.CHROMIUM); test.skip(!options.CHROMIUM(parameters));
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(defaultBrowserOptions);
const browserSession = await (browser as ChromiumBrowser).newBrowserCDPSession(); const browserSession = await (browser as ChromiumBrowser).newBrowserCDPSession();

View file

@ -15,9 +15,9 @@
*/ */
import { options, playwrightFixtures } from '../playwright.fixtures'; import { options, playwrightFixtures } from '../playwright.fixtures';
const { it, expect, describe, registerWorkerFixture } = playwrightFixtures; const { it, expect, describe, overrideWorkerFixture } = playwrightFixtures;
registerWorkerFixture('browser', async ({browserType, defaultBrowserOptions}, test) => { overrideWorkerFixture('browser', async ({browserType, defaultBrowserOptions}, test) => {
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...defaultBrowserOptions,
args: (defaultBrowserOptions.args || []).concat(['--site-per-process']) args: (defaultBrowserOptions.args || []).concat(['--site-per-process'])
@ -26,8 +26,8 @@ registerWorkerFixture('browser', async ({browserType, defaultBrowserOptions}, te
await browser.close(); await browser.close();
}); });
describe('oopif', suite => { describe('oopif', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should report oopif frames', async function({browser, page, server}) { it('should report oopif frames', async function({browser, page, server}) {
await page.goto(server.PREFIX + '/dynamic-oopif.html'); await page.goto(server.PREFIX + '/dynamic-oopif.html');
@ -68,9 +68,9 @@ describe('oopif', suite => {
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
}); });
it('should get the proper viewport', test => { it('should get the proper viewport', (test, parameters) => {
test.fixme(options.CHROMIUM); test.fixme(options.CHROMIUM(parameters));
test.skip(!options.CHROMIUM); test.skip(!options.CHROMIUM(parameters));
}, async ({browser, page, server}) => { }, async ({browser, page, server}) => {
expect(page.viewportSize()).toEqual({width: 1280, height: 720}); expect(page.viewportSize()).toEqual({width: 1280, height: 720});
await page.goto(server.PREFIX + '/dynamic-oopif.html'); await page.goto(server.PREFIX + '/dynamic-oopif.html');

View file

@ -16,8 +16,8 @@
import { it, expect, describe, options } from '../playwright.fixtures'; import { it, expect, describe, options } from '../playwright.fixtures';
import type { ChromiumBrowserContext, ChromiumBrowser } from '../../types/types'; import type { ChromiumBrowserContext, ChromiumBrowser } from '../../types/types';
describe('session', suite => { describe('session', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should work', async function({page}) { it('should work', async function({page}) {
const client = await (page.context() as ChromiumBrowserContext).newCDPSession(page); const client = await (page.context() as ChromiumBrowserContext).newCDPSession(page);

View file

@ -22,19 +22,19 @@ import type { ChromiumBrowser } from '../..';
type TestState = { type TestState = {
outputTraceFile: string; outputTraceFile: string;
}; };
const fixtures = playwrightFixtures.extend<{}, TestState>(); const fixtures = playwrightFixtures.declareTestFixtures<TestState>();
const { it, expect, describe, registerFixture } = fixtures; const { it, expect, describe, defineTestFixture } = fixtures;
registerFixture('outputTraceFile', async ({tmpDir}, test) => { defineTestFixture('outputTraceFile', async ({tmpDir}, test) => {
const outputTraceFile = path.join(tmpDir, `trace.json`); const outputTraceFile = path.join(tmpDir, `trace.json`);
await test(outputTraceFile); await test(outputTraceFile);
if (fs.existsSync(outputTraceFile)) if (fs.existsSync(outputTraceFile))
fs.unlinkSync(outputTraceFile); fs.unlinkSync(outputTraceFile);
}); });
describe('oopif', suite => { describe('oopif', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should output a trace', async ({browser, page, server, outputTraceFile}) => { it('should output a trace', async ({browser, page, server, outputTraceFile}) => {
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile}); await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile});

View file

@ -20,7 +20,7 @@ declare const renderComponent;
declare const e; declare const e;
declare const MyButton; declare const MyButton;
it('should report that selector does not match anymore', test => { it('should report that selector does not match anymore', (test, parameters) => {
test.fail(true); test.fail(true);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/react.html'); await page.goto(server.PREFIX + '/react.html');
@ -41,7 +41,7 @@ it('should report that selector does not match anymore', test => {
expect(error.message).toContain('element does not match the selector anymore'); expect(error.message).toContain('element does not match the selector anymore');
}); });
it('should not retarget the handle when element is recycled', test => { it('should not retarget the handle when element is recycled', (test, parameters) => {
test.fixme(true); test.fixme(true);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/react.html'); await page.goto(server.PREFIX + '/react.html');
@ -70,7 +70,7 @@ it('should timeout when click opens alert', async ({page, server}) => {
await dialog.dismiss(); await dialog.dismiss();
}); });
it('should retarget when element is recycled during hit testing', test => { it('should retarget when element is recycled during hit testing', (test, parameters) => {
test.fixme(true); test.fixme(true);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/react.html'); await page.goto(server.PREFIX + '/react.html');
@ -87,7 +87,7 @@ it('should retarget when element is recycled during hit testing', test => {
expect(await page.evaluate('window.button2')).toBe(undefined); expect(await page.evaluate('window.button2')).toBe(undefined);
}); });
it('should retarget when element is recycled before enabled check', test => { it('should retarget when element is recycled before enabled check', (test, parameters) => {
test.fixme(true); test.fixme(true);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/react.html'); await page.goto(server.PREFIX + '/react.html');

View file

@ -17,7 +17,7 @@
import { it, expect, options } from './playwright.fixtures'; import { it, expect, options } from './playwright.fixtures';
it('should avoid side effects after timeout', test => { it('should avoid side effects after timeout', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');

View file

@ -17,7 +17,7 @@
import { it, expect, options } from './playwright.fixtures'; import { it, expect, options } from './playwright.fixtures';
it('should fail when element jumps during hit testing', test => { it('should fail when element jumps during hit testing', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({page}) => { }, async ({page}) => {
await page.setContent('<button>Click me</button>'); await page.setContent('<button>Click me</button>');

View file

@ -322,8 +322,8 @@ it('should click the button inside an iframe', async ({page, server}) => {
expect(await frame.evaluate(() => window['result'])).toBe('Clicked'); expect(await frame.evaluate(() => window['result'])).toBe('Clicked');
}); });
it('should click the button with fixed position inside an iframe', test => { it('should click the button with fixed position inside an iframe', (test, parameters) => {
test.fixme(options.CHROMIUM || options.WEBKIT); test.fixme(options.CHROMIUM(parameters) || options.WEBKIT(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
// @see https://github.com/GoogleChrome/puppeteer/issues/4110 // @see https://github.com/GoogleChrome/puppeteer/issues/4110
// @see https://bugs.chromium.org/p/chromium/issues/detail?id=986390 // @see https://bugs.chromium.org/p/chromium/issues/detail?id=986390
@ -351,39 +351,39 @@ it('should click the button with deviceScaleFactor set', async ({browser, server
await context.close(); await context.close();
}); });
it('should click the button with px border with offset', async ({page, server}) => { it('should click the button with px border with offset', async ({page, server, isWebKit}) => {
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.$eval('button', button => button.style.borderWidth = '8px'); await page.$eval('button', button => button.style.borderWidth = '8px');
await page.click('button', { position: { x: 20, y: 10 } }); await page.click('button', { position: { x: 20, y: 10 } });
expect(await page.evaluate('result')).toBe('Clicked'); expect(await page.evaluate('result')).toBe('Clicked');
// Safari reports border-relative offsetX/offsetY. // Safari reports border-relative offsetX/offsetY.
expect(await page.evaluate('offsetX')).toBe(options.WEBKIT ? 20 + 8 : 20); expect(await page.evaluate('offsetX')).toBe(isWebKit ? 20 + 8 : 20);
expect(await page.evaluate('offsetY')).toBe(options.WEBKIT ? 10 + 8 : 10); expect(await page.evaluate('offsetY')).toBe(isWebKit ? 10 + 8 : 10);
}); });
it('should click the button with em border with offset', async ({page, server}) => { it('should click the button with em border with offset', async ({page, server, isWebKit}) => {
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.$eval('button', button => button.style.borderWidth = '2em'); await page.$eval('button', button => button.style.borderWidth = '2em');
await page.$eval('button', button => button.style.fontSize = '12px'); await page.$eval('button', button => button.style.fontSize = '12px');
await page.click('button', { position: { x: 20, y: 10 } }); await page.click('button', { position: { x: 20, y: 10 } });
expect(await page.evaluate('result')).toBe('Clicked'); expect(await page.evaluate('result')).toBe('Clicked');
// Safari reports border-relative offsetX/offsetY. // Safari reports border-relative offsetX/offsetY.
expect(await page.evaluate('offsetX')).toBe(options.WEBKIT ? 12 * 2 + 20 : 20); expect(await page.evaluate('offsetX')).toBe(isWebKit ? 12 * 2 + 20 : 20);
expect(await page.evaluate('offsetY')).toBe(options.WEBKIT ? 12 * 2 + 10 : 10); expect(await page.evaluate('offsetY')).toBe(isWebKit ? 12 * 2 + 10 : 10);
}); });
it('should click a very large button with offset', async ({page, server}) => { it('should click a very large button with offset', async ({page, server, isWebKit}) => {
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.$eval('button', button => button.style.borderWidth = '8px'); await page.$eval('button', button => button.style.borderWidth = '8px');
await page.$eval('button', button => button.style.height = button.style.width = '2000px'); await page.$eval('button', button => button.style.height = button.style.width = '2000px');
await page.click('button', { position: { x: 1900, y: 1910 } }); await page.click('button', { position: { x: 1900, y: 1910 } });
expect(await page.evaluate(() => window['result'])).toBe('Clicked'); expect(await page.evaluate(() => window['result'])).toBe('Clicked');
// Safari reports border-relative offsetX/offsetY. // Safari reports border-relative offsetX/offsetY.
expect(await page.evaluate('offsetX')).toBe(options.WEBKIT ? 1900 + 8 : 1900); expect(await page.evaluate('offsetX')).toBe(isWebKit ? 1900 + 8 : 1900);
expect(await page.evaluate('offsetY')).toBe(options.WEBKIT ? 1910 + 8 : 1910); expect(await page.evaluate('offsetY')).toBe(isWebKit ? 1910 + 8 : 1910);
}); });
it('should click a button in scrolling container with offset', async ({page, server}) => { it('should click a button in scrolling container with offset', async ({page, server, isWebKit}) => {
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
await page.$eval('button', button => { await page.$eval('button', button => {
const container = document.createElement('div'); const container = document.createElement('div');
@ -399,13 +399,13 @@ it('should click a button in scrolling container with offset', async ({page, ser
await page.click('button', { position: { x: 1900, y: 1910 } }); await page.click('button', { position: { x: 1900, y: 1910 } });
expect(await page.evaluate(() => window['result'])).toBe('Clicked'); expect(await page.evaluate(() => window['result'])).toBe('Clicked');
// Safari reports border-relative offsetX/offsetY. // Safari reports border-relative offsetX/offsetY.
expect(await page.evaluate('offsetX')).toBe(options.WEBKIT ? 1900 + 8 : 1900); expect(await page.evaluate('offsetX')).toBe(isWebKit ? 1900 + 8 : 1900);
expect(await page.evaluate('offsetY')).toBe(options.WEBKIT ? 1910 + 8 : 1910); expect(await page.evaluate('offsetY')).toBe(isWebKit ? 1910 + 8 : 1910);
}); });
it('should click the button with offset with page scale', test => { it('should click the button with offset with page scale', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browser, server}) => { }, async ({browser, server, isWebKit, isChromium}) => {
const context = await browser.newContext({ viewport: { width: 400, height: 400 }, isMobile: true }); const context = await browser.newContext({ viewport: { width: 400, height: 400 }, isMobile: true });
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
@ -417,10 +417,10 @@ it('should click the button with offset with page scale', test => {
expect(await page.evaluate('result')).toBe('Clicked'); expect(await page.evaluate('result')).toBe('Clicked');
const round = x => Math.round(x + 0.01); const round = x => Math.round(x + 0.01);
let expected = { x: 28, y: 18 }; // 20;10 + 8px of border in each direction let expected = { x: 28, y: 18 }; // 20;10 + 8px of border in each direction
if (options.WEBKIT) { if (isWebKit) {
// WebKit rounds up during css -> dip -> css conversion. // WebKit rounds up during css -> dip -> css conversion.
expected = { x: 29, y: 19 }; expected = { x: 29, y: 19 };
} else if (options.CHROMIUM && options.HEADLESS) { } else if (isChromium && options.HEADLESS) {
// Headless Chromium rounds down during css -> dip -> css conversion. // Headless Chromium rounds down during css -> dip -> css conversion.
expected = { x: 27, y: 18 }; expected = { x: 27, y: 18 };
} }

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
import fs from 'fs'; import fs from 'fs';
import utils from './utils'; import utils from './utils';
@ -79,7 +79,7 @@ it('context.clearCookies() should work', async ({server, launchPersistent}) => {
expect(await page.evaluate('document.cookie')).toBe(''); expect(await page.evaluate('document.cookie')).toBe('');
}); });
it('should(not) block third party cookies', async ({server, launchPersistent}) => { it('should(not) block third party cookies', async ({server, launchPersistent, isChromium, isFirefox}) => {
const {page, context} = await launchPersistent(); const {page, context} = await launchPersistent();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(src => { await page.evaluate(src => {
@ -96,7 +96,7 @@ it('should(not) block third party cookies', async ({server, launchPersistent}) =
return document.cookie; return document.cookie;
}); });
await page.waitForTimeout(2000); await page.waitForTimeout(2000);
const allowsThirdParty = options.CHROMIUM || options.FIREFOX; const allowsThirdParty = isChromium || isFirefox;
expect(documentCookie).toBe(allowsThirdParty ? 'username=John Doe' : ''); expect(documentCookie).toBe(allowsThirdParty ? 'username=John Doe' : '');
const cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + '/grid.html'); const cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + '/grid.html');
if (allowsThirdParty) { if (allowsThirdParty) {
@ -146,12 +146,12 @@ it('should support bypassCSP option', async ({server, launchPersistent}) => {
expect(await page.evaluate('__injected')).toBe(42); expect(await page.evaluate('__injected')).toBe(42);
}); });
it('should support javascriptEnabled option', async ({launchPersistent}) => { it('should support javascriptEnabled option', async ({launchPersistent, isWebKit}) => {
const {page} = await launchPersistent({javaScriptEnabled: false}); const {page} = await launchPersistent({javaScriptEnabled: false});
await page.goto('data:text/html, <script>var something = "forbidden"</script>'); await page.goto('data:text/html, <script>var something = "forbidden"</script>');
let error = null; let error = null;
await page.evaluate('something').catch(e => error = e); await page.evaluate('something').catch(e => error = e);
if (options.WEBKIT) if (isWebKit)
expect(error.message).toContain('Can\'t find variable: something'); expect(error.message).toContain('Can\'t find variable: something');
else else
expect(error.message).toContain('something is not defined'); expect(error.message).toContain('something is not defined');
@ -170,7 +170,7 @@ it('should support offline option', async ({server, launchPersistent}) => {
expect(error).toBeTruthy(); expect(error).toBeTruthy();
}); });
it('should support acceptDownloads option', test => { it('should support acceptDownloads option', (test, parameters) => {
test.skip('Unskip once we support downloads in persistent context.'); test.skip('Unskip once we support downloads in persistent context.');
}, async ({server, launchPersistent}) => { }, async ({server, launchPersistent}) => {
const {page} = await launchPersistent({acceptDownloads: true}); const {page} = await launchPersistent({acceptDownloads: true});

View file

@ -26,8 +26,8 @@ it('should support hasTouch option', async ({server, launchPersistent}) => {
expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(true); expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(true);
}); });
it('should work in persistent context', test => { it('should work in persistent context', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({server, launchPersistent}) => { }, async ({server, launchPersistent}) => {
// Firefox does not support mobile. // Firefox does not support mobile.
const {page} = await launchPersistent({viewport: {width: 320, height: 480}, isMobile: true}); const {page} = await launchPersistent({viewport: {width: 320, height: 480}, isMobile: true});
@ -68,8 +68,8 @@ it('should support ignoreHTTPSErrors option', async ({httpsServer, launchPersist
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
}); });
it('should support extraHTTPHeaders option', test => { it('should support extraHTTPHeaders option', (test, parameters) => {
test.flaky(options.FIREFOX && !options.HEADLESS && LINUX, 'Intermittent timeout on bots'); test.flaky(options.FIREFOX(parameters) && !options.HEADLESS && LINUX, 'Intermittent timeout on bots');
}, async ({server, launchPersistent}) => { }, async ({server, launchPersistent}) => {
const {page} = await launchPersistent({extraHTTPHeaders: { foo: 'bar' }}); const {page} = await launchPersistent({extraHTTPHeaders: { foo: 'bar' }});
const [request] = await Promise.all([ const [request] = await Promise.all([
@ -79,8 +79,8 @@ it('should support extraHTTPHeaders option', test => {
expect(request.headers['foo']).toBe('bar'); expect(request.headers['foo']).toBe('bar');
}); });
it('should accept userDataDir', test => { it('should accept userDataDir', (test, parameters) => {
test.flaky(options.CHROMIUM); test.flaky(options.CHROMIUM(parameters));
}, async ({launchPersistent, tmpDir}) => { }, async ({launchPersistent, tmpDir}) => {
const {context} = await launchPersistent(); const {context} = await launchPersistent();
// Note: we need an open page to make sure its functional. // Note: we need an open page to make sure its functional.
@ -91,7 +91,7 @@ it('should accept userDataDir', test => {
await removeUserDataDir(tmpDir); await removeUserDataDir(tmpDir);
}); });
it('should restore state from userDataDir', test => { it('should restore state from userDataDir', (test, parameters) => {
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions, server, launchPersistent}) => { }, async ({browserType, defaultBrowserOptions, server, launchPersistent}) => {
const userDataDir = await makeUserDataDir(); const userDataDir = await makeUserDataDir();
@ -119,9 +119,9 @@ it('should restore state from userDataDir', test => {
await removeUserDataDir(userDataDir2); await removeUserDataDir(userDataDir2);
}); });
it('should restore cookies from userDataDir', test => { it('should restore cookies from userDataDir', (test, parameters) => {
test.slow(); test.slow();
test.flaky(options.CHROMIUM); test.flaky(options.CHROMIUM(parameters));
}, async ({browserType, defaultBrowserOptions, server, launchPersistent}) => { }, async ({browserType, defaultBrowserOptions, server, launchPersistent}) => {
const userDataDir = await makeUserDataDir(); const userDataDir = await makeUserDataDir();
const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions); const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
@ -158,15 +158,15 @@ it('should have default URL when launching browser', async ({launchPersistent})
expect(urls).toEqual(['about:blank']); expect(urls).toEqual(['about:blank']);
}); });
it('should throw if page argument is passed', test => { it('should throw if page argument is passed', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browserType, defaultBrowserOptions, server, tmpDir}) => { }, async ({browserType, defaultBrowserOptions, server, tmpDir}) => {
const options = {...defaultBrowserOptions, args: [server.EMPTY_PAGE] }; const options = {...defaultBrowserOptions, args: [server.EMPTY_PAGE] };
const error = await browserType.launchPersistentContext(tmpDir, options).catch(e => e); const error = await browserType.launchPersistentContext(tmpDir, 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 => { it('should have passed URL when launching with ignoreDefaultArgs: true', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({browserType, defaultBrowserOptions, server, tmpDir, toImpl}) => { }, async ({browserType, defaultBrowserOptions, server, tmpDir, toImpl}) => {
const args = toImpl(browserType)._defaultArgs(defaultBrowserOptions, 'persistent', tmpDir, 0).filter(a => a !== 'about:blank'); const args = toImpl(browserType)._defaultArgs(defaultBrowserOptions, 'persistent', tmpDir, 0).filter(a => a !== 'about:blank');
@ -184,7 +184,7 @@ it('should have passed URL when launching with ignoreDefaultArgs: true', test =>
await browserContext.close(); await browserContext.close();
}); });
it('should handle timeout', test => { it('should handle timeout', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({browserType, defaultBrowserOptions, tmpDir}) => { }, async ({browserType, defaultBrowserOptions, tmpDir}) => {
const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) }; const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
@ -192,7 +192,7 @@ it('should handle timeout', test => {
expect(error.message).toContain(`browserType.launchPersistentContext: Timeout 5000ms exceeded.`); expect(error.message).toContain(`browserType.launchPersistentContext: Timeout 5000ms exceeded.`);
}); });
it('should handle exception', test => { it('should handle exception', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({browserType, defaultBrowserOptions, tmpDir}) => { }, async ({browserType, defaultBrowserOptions, tmpDir}) => {
const e = new Error('Dummy'); const e = new Error('Dummy');
@ -209,8 +209,8 @@ it('should fire close event for a persistent context', async ({launchPersistent}
expect(closed).toBe(true); expect(closed).toBe(true);
}); });
it('coverage should work', test => { it('coverage should work', (test, parameters) => {
test.skip(!options.CHROMIUM); test.skip(!options.CHROMIUM(parameters));
}, async ({server, launchPersistent}) => { }, async ({server, launchPersistent}) => {
const {page} = await launchPersistent(); const {page} = await launchPersistent();
await page.coverage.startJSCoverage(); await page.coverage.startJSCoverage();
@ -221,8 +221,8 @@ it('coverage should work', test => {
expect(coverage[0].functions.find(f => f.functionName === 'foo').ranges[0].count).toEqual(1); expect(coverage[0].functions.find(f => f.functionName === 'foo').ranges[0].count).toEqual(1);
}); });
it('coverage should be missing', test => { it('coverage should be missing', (test, parameters) => {
test.skip(options.CHROMIUM); test.skip(options.CHROMIUM(parameters));
}, async ({launchPersistent}) => { }, async ({launchPersistent}) => {
const {page} = await launchPersistent(); const {page} = await launchPersistent();
expect(page.coverage).toBe(null); expect(page.coverage).toBe(null);

View file

@ -62,8 +62,8 @@ it('should dismiss the confirm prompt', async ({page}) => {
expect(result).toBe(false); expect(result).toBe(false);
}); });
it('should be able to close context with open alert', test => { it('should be able to close context with open alert', (test, parameters) => {
test.fixme(options.WEBKIT && MAC); test.fixme(options.WEBKIT(parameters) && MAC);
}, async ({browser}) => { }, async ({browser}) => {
const context = await browser.newContext(); const context = await browser.newContext();
const page = await context.newPage(); const page = await context.newPage();

View file

@ -127,8 +127,8 @@ it('should be atomic', async ({playwright, page}) => {
expect(await page.evaluate(() => window['_clicked'])).toBe(true); expect(await page.evaluate(() => window['_clicked'])).toBe(true);
}); });
it('should dispatch drag drop events', test => { it('should dispatch drag drop events', (test, parameters) => {
test.fail(options.WEBKIT); test.fail(options.WEBKIT(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/drag-n-drop.html'); await page.goto(server.PREFIX + '/drag-n-drop.html');
const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
@ -141,8 +141,8 @@ it('should dispatch drag drop events', test => {
}, {source, target})).toBeTruthy(); }, {source, target})).toBeTruthy();
}); });
it('should dispatch drag drop events', test => { it('should dispatch drag drop events', (test, parameters) => {
test.fail(options.WEBKIT); test.fail(options.WEBKIT(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/drag-n-drop.html'); await page.goto(server.PREFIX + '/drag-n-drop.html');
const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); const dataTransfer = await page.evaluateHandle(() => new DataTransfer());

View file

@ -144,7 +144,7 @@ it('should create subdirectories when saving to non-existent user-specified path
await page.close(); await page.close();
}); });
it('should save when connected remotely', test => { it('should save when connected remotely', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({tmpDir, server, browserType, remoteServer}) => { }, async ({tmpDir, server, browserType, remoteServer}) => {
const browser = await browserType.connect({ wsEndpoint: remoteServer.wsEndpoint() }); const browser = await browserType.connect({ wsEndpoint: remoteServer.wsEndpoint() });
@ -190,7 +190,7 @@ it('should error when saving after deletion', async ({tmpDir, browser, server})
await page.close(); await page.close();
}); });
it('should error when saving after deletion when connected remotely', test => { it('should error when saving after deletion when connected remotely', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({tmpDir, server, browserType, remoteServer}) => { }, async ({tmpDir, server, browserType, remoteServer}) => {
const browser = await browserType.connect({ wsEndpoint: remoteServer.wsEndpoint() }); const browser = await browserType.connect({ wsEndpoint: remoteServer.wsEndpoint() });
@ -254,8 +254,8 @@ it(`should report download path within page.on('download', …) handler for Blob
expect(fs.readFileSync(path).toString()).toBe('Hello world'); expect(fs.readFileSync(path).toString()).toBe('Hello world');
await page.close(); await page.close();
}); });
it('should report alt-click downloads', test => { it('should report alt-click downloads', (test, parameters) => {
test.fixme(options.FIREFOX || options.WEBKIT); test.fixme(options.FIREFOX(parameters) || options.WEBKIT(parameters));
}, async ({browser, server}) => { }, async ({browser, server}) => {
// Firefox does not download on alt-click by default. // Firefox does not download on alt-click by default.
// Our WebKit embedder does not download on alt-click, although Safari does. // Our WebKit embedder does not download on alt-click, although Safari does.
@ -277,8 +277,8 @@ it('should report alt-click downloads', test => {
await page.close(); await page.close();
}); });
it('should report new window downloads', test => { it('should report new window downloads', (test, parameters) => {
test.fixme(options.CHROMIUM && !options.HEADLESS); test.fixme(options.CHROMIUM(parameters) && !options.HEADLESS);
}, async ({browser, server}) => { }, async ({browser, server}) => {
// TODO: - the test fails in headful Chromium as the popup page gets closed along // TODO: - the test fails in headful Chromium as the popup page gets closed along
// with the session before download completed event arrives. // with the session before download completed event arrives.

View file

@ -26,10 +26,10 @@ type TestState = {
downloadsBrowser: Browser; downloadsBrowser: Browser;
persistentDownloadsContext: BrowserContext; persistentDownloadsContext: BrowserContext;
}; };
const fixtures = playwrightFixtures.extend<{}, TestState>(); const fixtures = playwrightFixtures.declareTestFixtures<TestState>();
const { it, expect, registerFixture } = fixtures; const { it, expect, defineTestFixture } = fixtures;
registerFixture('downloadsBrowser', async ({server, browserType, defaultBrowserOptions, tmpDir}, test) => { defineTestFixture('downloadsBrowser', async ({server, browserType, defaultBrowserOptions, tmpDir}, 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');
@ -43,7 +43,7 @@ registerFixture('downloadsBrowser', async ({server, browserType, defaultBrowserO
await browser.close(); await browser.close();
}); });
registerFixture('persistentDownloadsContext', async ({server, browserType, defaultBrowserOptions, tmpDir}, test) => { defineTestFixture('persistentDownloadsContext', async ({server, browserType, defaultBrowserOptions, tmpDir}, test) => {
const userDataDir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-')); const userDataDir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-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');

View file

@ -21,8 +21,8 @@ const { it, expect, describe } = electronFixtures;
import path from 'path'; import path from 'path';
const electronName = process.platform === 'win32' ? 'electron.cmd' : 'electron'; const electronName = process.platform === 'win32' ? 'electron.cmd' : 'electron';
describe('electron app', suite => { describe('electron app', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should fire close event', async ({ playwright }) => { it('should fire close event', async ({ playwright }) => {
const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName); const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName);

View file

@ -18,8 +18,8 @@ import { options } from '../playwright.fixtures';
import { electronFixtures } from './electron.fixture'; import { electronFixtures } from './electron.fixture';
const { it, expect, describe } = electronFixtures; const { it, expect, describe } = electronFixtures;
describe('electron window', suite => { describe('electron window', (suite, parameters) => {
suite.skip(!options.CHROMIUM); suite.skip(!options.CHROMIUM(parameters));
}, () => { }, () => {
it('should click the button', async ({window, server}) => { it('should click the button', async ({window, server}) => {
await window.goto(server.PREFIX + '/input/button.html'); await window.goto(server.PREFIX + '/input/button.html');

View file

@ -25,14 +25,14 @@ type TestState = {
window: ElectronPage; window: ElectronPage;
}; };
export const electronFixtures = playwrightFixtures.extend<{}, TestState>(); export const electronFixtures = playwrightFixtures.declareTestFixtures<TestState>();
const { registerFixture } = electronFixtures; const { defineTestFixture } = electronFixtures;
declare module '../../index' { declare module '../../index' {
const electron: ElectronLauncher; const electron: ElectronLauncher;
} }
registerFixture('application', async ({playwright}, test) => { defineTestFixture('application', async ({playwright}, test) => {
const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName); const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName);
const application = await playwright.electron.launch(electronPath, { const application = await playwright.electron.launch(electronPath, {
args: [path.join(__dirname, 'testApp.js')], args: [path.join(__dirname, 'testApp.js')],
@ -41,7 +41,7 @@ registerFixture('application', async ({playwright}, test) => {
await application.close(); await application.close();
}); });
registerFixture('window', async ({application}, test) => { defineTestFixture('window', async ({application}, test) => {
const page = await application.newBrowserWindow({ width: 800, height: 600 }); const page = await application.newBrowserWindow({ width: 800, height: 600 });
await test(page); await test(page);
await page.close(); await page.close();

View file

@ -18,8 +18,8 @@
import { it, expect, options } from './playwright.fixtures'; import { it, expect, options } from './playwright.fixtures';
it('should work', test => { it('should work', (test, parameters) => {
test.fail(options.FIREFOX && !options.HEADLESS); test.fail(options.FIREFOX(parameters) && !options.HEADLESS);
}, async ({ page, server }) => { }, async ({ page, server }) => {
await page.setViewportSize({ width: 500, height: 500 }); await page.setViewportSize({ width: 500, height: 500 });
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
@ -67,8 +67,8 @@ it('should work with SVG nodes', async ({ page, server }) => {
expect(pwBoundingBox).toEqual(webBoundingBox); expect(pwBoundingBox).toEqual(webBoundingBox);
}); });
it('should work with page scale', test => { it('should work with page scale', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({ browser, server }) => { }, async ({ browser, server }) => {
const context = await browser.newContext({ viewport: { width: 400, height: 400 }, isMobile: true }); const context = await browser.newContext({ viewport: { width: 400, height: 400 }, isMobile: true });
const page = await context.newPage(); const page = await context.newPage();

View file

@ -34,8 +34,8 @@ it('should work for cross-process iframes', async ({ page, server }) => {
expect(await elementHandle.ownerFrame()).toBe(frame); expect(await elementHandle.ownerFrame()).toBe(frame);
}); });
it('should work for document', test => { it('should work for document', (test, parameters) => {
test.flaky(WIN && options.WEBKIT); test.flaky(WIN && options.WEBKIT(parameters));
}, async ({ page, server }) => { }, async ({ page, server }) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);

View file

@ -22,11 +22,8 @@ import {PNG} from 'pngjs';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
// Firefox headful produces a different image. describe('element screenshot', (suite, parameters) => {
const ffheadful = options.FIREFOX && !options.HEADLESS; suite.skip(parameters.browserName === 'firefox' && !options.HEADLESS);
describe('element screenshot', suite => {
suite.skip(ffheadful);
}, () => { }, () => {
it('should work', async ({page, server, golden}) => { it('should work', async ({page, server, golden}) => {
await page.setViewportSize({width: 500, height: 500}); await page.setViewportSize({width: 500, height: 500});
@ -214,8 +211,8 @@ describe('element screenshot', suite => {
expect(screenshot).toMatchImage(golden('screenshot-element-fractional.png')); expect(screenshot).toMatchImage(golden('screenshot-element-fractional.png'));
}); });
it('should work with a mobile viewport', test => { it('should work with a mobile viewport', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browser, server, golden}) => { }, async ({browser, server, golden}) => {
const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true}); const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true});
const page = await context.newPage(); const page = await context.newPage();
@ -227,8 +224,8 @@ describe('element screenshot', suite => {
await context.close(); await context.close();
}); });
it('should work with device scale factor', test => { it('should work with device scale factor', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browser, server, golden}) => { }, async ({browser, server, golden}) => {
const context = await browser.newContext({ viewport: { width: 320, height: 480 }, deviceScaleFactor: 2 }); const context = await browser.newContext({ viewport: { width: 320, height: 480 }, deviceScaleFactor: 2 });
const page = await context.newPage(); const page = await context.newPage();
@ -292,7 +289,7 @@ describe('element screenshot', suite => {
await context.close(); await context.close();
}); });
it('should restore viewport after page screenshot and exception', test => { it('should restore viewport after page screenshot and exception', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({ browser, server }) => { }, async ({ browser, server }) => {
const context = await browser.newContext({ viewport: { width: 350, height: 360 } }); const context = await browser.newContext({ viewport: { width: 350, height: 360 } });
@ -305,7 +302,7 @@ describe('element screenshot', suite => {
await context.close(); await context.close();
}); });
it('should restore viewport after page screenshot and timeout', test => { it('should restore viewport after page screenshot and timeout', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({ browser, server }) => { }, async ({ browser, server }) => {
const context = await browser.newContext({ viewport: { width: 350, height: 360 } }); const context = await browser.newContext({ viewport: { width: 350, height: 360 } });
@ -351,9 +348,9 @@ describe('element screenshot', suite => {
await context.close(); await context.close();
}); });
it('should restore viewport after element screenshot and exception', test => { it('should restore viewport after element screenshot and exception', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({server, browser}) => { }, async ({browser}) => {
const context = await browser.newContext({ viewport: { width: 350, height: 360 } }); const context = await browser.newContext({ viewport: { width: 350, height: 360 } });
const page = await context.newPage(); const page = await context.newPage();
await page.setContent(`<div style="width:600px;height:600px;"></div>`); await page.setContent(`<div style="width:600px;height:600px;"></div>`);
@ -365,8 +362,8 @@ describe('element screenshot', suite => {
await context.close(); await context.close();
}); });
it('should wait for element to stop moving', test => { it('should wait for element to stop moving', (test, parameters) => {
test.flaky(options.WEBKIT && !options.HEADLESS && LINUX); test.flaky(options.WEBKIT(parameters) && !options.HEADLESS && LINUX);
}, async ({ page, server, golden }) => { }, async ({ page, server, golden }) => {
await page.setViewportSize({ width: 500, height: 500 }); await page.setViewportSize({ width: 500, height: 500 });
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');

View file

@ -15,14 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('should select textarea', async ({ page, server }) => { it('should select textarea', async ({ page, server, isFirefox }) => {
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
const textarea = await page.$('textarea'); const textarea = await page.$('textarea');
await textarea.evaluate(textarea => textarea.value = 'some value'); await textarea.evaluate(textarea => textarea.value = 'some value');
await textarea.selectText(); await textarea.selectText();
if (options.FIREFOX) { if (isFirefox) {
expect(await textarea.evaluate(el => el.selectionStart)).toBe(0); expect(await textarea.evaluate(el => el.selectionStart)).toBe(0);
expect(await textarea.evaluate(el => el.selectionEnd)).toBe(10); expect(await textarea.evaluate(el => el.selectionEnd)).toBe(10);
} else { } else {
@ -30,12 +30,12 @@ it('should select textarea', async ({ page, server }) => {
} }
}); });
it('should select input', async ({ page, server }) => { it('should select input', async ({ page, server, isFirefox }) => {
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
const input = await page.$('input'); const input = await page.$('input');
await input.evaluate(input => input.value = 'some value'); await input.evaluate(input => input.value = 'some value');
await input.selectText(); await input.selectText();
if (options.FIREFOX) { if (isFirefox) {
expect(await input.evaluate(el => el.selectionStart)).toBe(0); expect(await input.evaluate(el => el.selectionStart)).toBe(0);
expect(await input.evaluate(el => el.selectionEnd)).toBe(10); expect(await input.evaluate(el => el.selectionEnd)).toBe(10);
} else { } else {

View file

@ -114,8 +114,8 @@ it('should wait for disabled button', async ({page}) => {
await promise; await promise;
}); });
it('should wait for stable position', test => { it('should wait for stable position', (test, parameters) => {
test.fixme(options.FIREFOX && LINUX); test.fixme(options.FIREFOX(parameters) && LINUX);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button'); const button = await page.$('button');

View file

@ -101,8 +101,8 @@ it('should change document.activeElement', async ({page, server}) => {
expect(active).toEqual(['INPUT', 'TEXTAREA']); expect(active).toEqual(['INPUT', 'TEXTAREA']);
}); });
it('should not affect screenshots', test => { it('should not affect screenshots', (test, parameters) => {
test.skip(options.FIREFOX && !options.HEADLESS); test.skip(options.FIREFOX(parameters) && !options.HEADLESS);
}, async ({page, server, golden}) => { }, async ({page, server, golden}) => {
// Firefox headful produces a different image. // Firefox headful produces a different image.
const page2 = await page.context().newPage(); const page2 = await page.context().newPage();

View file

@ -15,8 +15,8 @@
*/ */
import { it, expect, options } from '../playwright.fixtures'; import { it, expect, options } from '../playwright.fixtures';
it('should pass firefox user preferences', test => { it('should pass firefox user preferences', (test, parameters) => {
test.skip(!options.FIREFOX); test.skip(!options.FIREFOX(parameters));
}, async ({browserType, defaultBrowserOptions}) => { }, async ({browserType, defaultBrowserOptions}) => {
const browser = await browserType.launch({ const browser = await browserType.launch({
...defaultBrowserOptions, ...defaultBrowserOptions,

View file

@ -26,10 +26,10 @@ export type FixturesFixtures = {
stallingConnectedRemoteServer: RemoteServer; stallingConnectedRemoteServer: RemoteServer;
}; };
const fixturesFixtures = serverFixtures.extend<{}, FixturesFixtures>(); const fixturesFixtures = serverFixtures.declareTestFixtures<FixturesFixtures>();
const { it, describe, expect, registerFixture } = fixturesFixtures; const { it, describe, expect, defineTestFixture } = fixturesFixtures;
registerFixture('connectedRemoteServer', async ({browserType, remoteServer, server}, test) => { defineTestFixture('connectedRemoteServer', async ({browserType, remoteServer, server}, test) => {
const browser = await browserType.connect({ wsEndpoint: remoteServer.wsEndpoint() }); const browser = await browserType.connect({ wsEndpoint: remoteServer.wsEndpoint() });
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -37,7 +37,7 @@ registerFixture('connectedRemoteServer', async ({browserType, remoteServer, serv
await browser.close(); await browser.close();
}); });
registerFixture('stallingConnectedRemoteServer', async ({browserType, stallingRemoteServer, server}, test) => { defineTestFixture('stallingConnectedRemoteServer', async ({browserType, stallingRemoteServer, server}, test) => {
const browser = await browserType.connect({ wsEndpoint: stallingRemoteServer.wsEndpoint() }); const browser = await browserType.connect({ wsEndpoint: stallingRemoteServer.wsEndpoint() });
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -45,7 +45,7 @@ registerFixture('stallingConnectedRemoteServer', async ({browserType, stallingRe
await browser.close(); await browser.close();
}); });
it('should close the browser when the node process closes', test => { it('should close the browser when the node process closes', (test, parameters) => {
test.slow(); test.slow();
}, async ({connectedRemoteServer}) => { }, async ({connectedRemoteServer}) => {
if (WIN) if (WIN)

View file

@ -16,8 +16,8 @@
import { it, expect, options } from './playwright.fixtures'; import { it, expect, options } from './playwright.fixtures';
it('should work', test => { it('should work', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async function({page}) { }, async function({page}) {
await page.setContent(`<div id=d1 tabIndex=0></div>`); await page.setContent(`<div id=d1 tabIndex=0></div>`);
expect(await page.evaluate(() => document.activeElement.nodeName)).toBe('BODY'); expect(await page.evaluate(() => document.activeElement.nodeName)).toBe('BODY');
@ -78,8 +78,8 @@ it('should traverse focus in all directions', async function({page}) {
expect(await page.evaluate(() => (document.activeElement as HTMLInputElement).value)).toBe('1'); expect(await page.evaluate(() => (document.activeElement as HTMLInputElement).value)).toBe('1');
}); });
it('should traverse only form elements', test => { it('should traverse only form elements', (test, parameters) => {
test.skip(!MAC || !options.WEBKIT, test.skip(!MAC || !options.WEBKIT(parameters),
'Chromium and WebKit both have settings for tab traversing all links, but it is only on by default in WebKit.'); 'Chromium and WebKit both have settings for tab traversing all links, but it is only on by default in WebKit.');
}, async function({page}) { }, async function({page}) {
await page.setContent(` await page.setContent(`

View file

@ -36,8 +36,8 @@ it('should have correct execution contexts', async ({ page, server }) => {
expect(await page.frames()[1].evaluate(() => document.body.textContent.trim())).toBe(`Hi, I'm frame`); expect(await page.frames()[1].evaluate(() => document.body.textContent.trim())).toBe(`Hi, I'm frame`);
}); });
function expectContexts(pageImpl, count) { function expectContexts(pageImpl, count, isChromium) {
if (options.CHROMIUM) if (isChromium)
expect(pageImpl._delegate._mainFrameSession._contextIdToContext.size).toBe(count); expect(pageImpl._delegate._mainFrameSession._contextIdToContext.size).toBe(count);
else else
expect(pageImpl._delegate._contextIdToContext.size).toBe(count); expect(pageImpl._delegate._contextIdToContext.size).toBe(count);
@ -45,22 +45,22 @@ function expectContexts(pageImpl, count) {
it('should dispose context on navigation', test => { it('should dispose context on navigation', test => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({ page, server, toImpl }) => { }, async ({ page, server, toImpl, isChromium }) => {
await page.goto(server.PREFIX + '/frames/one-frame.html'); await page.goto(server.PREFIX + '/frames/one-frame.html');
expect(page.frames().length).toBe(2); expect(page.frames().length).toBe(2);
expectContexts(toImpl(page), 4); expectContexts(toImpl(page), 4, isChromium);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
expectContexts(toImpl(page), 2); expectContexts(toImpl(page), 2, isChromium);
}); });
it('should dispose context on cross-origin navigation', test => { it('should dispose context on cross-origin navigation', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({ page, server, toImpl }) => { }, async ({ page, server, toImpl, isChromium }) => {
await page.goto(server.PREFIX + '/frames/one-frame.html'); await page.goto(server.PREFIX + '/frames/one-frame.html');
expect(page.frames().length).toBe(2); expect(page.frames().length).toBe(2);
expectContexts(toImpl(page), 4); expectContexts(toImpl(page), 4, isChromium);
await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
expectContexts(toImpl(page), 2); expectContexts(toImpl(page), 2, isChromium);
}); });
it('should execute after cross-site navigation', async ({ page, server }) => { it('should execute after cross-site navigation', async ({ page, server }) => {
@ -131,9 +131,9 @@ it('should be isolated between frames', async ({page, server}) => {
expect(a2).toBe(2); expect(a2).toBe(2);
}); });
it('should work in iframes that failed initial navigation', test => { it('should work in iframes that failed initial navigation', (test, parameters) => {
test.fail(options.CHROMIUM); test.fail(options.CHROMIUM(parameters));
test.fixme(options.FIREFOX); test.fixme(options.FIREFOX(parameters));
}, async ({page}) => { }, async ({page}) => {
// - Firefox does not report domcontentloaded for the iframe. // - Firefox does not report domcontentloaded for the iframe.
// - Chromium and Firefox report empty url. // - Chromium and Firefox report empty url.
@ -155,8 +155,8 @@ it('should work in iframes that failed initial navigation', test => {
expect(await page.frames()[1].$('div')).toBeTruthy(); expect(await page.frames()[1].$('div')).toBeTruthy();
}); });
it('should work in iframes that interrupted initial javascript url navigation', test => { it('should work in iframes that interrupted initial javascript url navigation', (test, parameters) => {
test.fixme(options.CHROMIUM); test.fixme(options.CHROMIUM(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
// Chromium does not report isolated world for the iframe. // Chromium does not report isolated world for the iframe.
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);

View file

@ -172,8 +172,8 @@ it('should report different frame instance when frame re-attaches', async ({page
expect(frame1).not.toBe(frame2); expect(frame1).not.toBe(frame2);
}); });
it('should refuse to display x-frame-options:deny iframe', test => { it('should refuse to display x-frame-options:deny iframe', (test, parameters) => {
test.fixme(options.FIREFOX); test.fixme(options.FIREFOX(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
server.setRoute('/x-frame-options-deny.html', async (req, res) => { server.setRoute('/x-frame-options-deny.html', async (req, res) => {
res.setHeader('Content-Type', 'text/html'); res.setHeader('Content-Type', 'text/html');

View file

@ -26,9 +26,9 @@ it('should have default url when launching browser', async ({browserType, defaul
await browserContext.close(); await browserContext.close();
}); });
it('headless should be able to read cookies written by headful', test => { it('headless should be able to read cookies written by headful', (test, parameters) => {
test.fail(WIN && options.CHROMIUM); test.fail(WIN && options.CHROMIUM(parameters));
test.flaky(options.FIREFOX); test.flaky(options.FIREFOX(parameters));
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions, server}) => { }, async ({browserType, defaultBrowserOptions, server}) => {
// see https://github.com/microsoft/playwright/issues/717 // see https://github.com/microsoft/playwright/issues/717
@ -50,7 +50,7 @@ it('headless should be able to read cookies written by headful', test => {
expect(cookie).toBe('foo=true'); expect(cookie).toBe('foo=true');
}); });
it('should close browser with beforeunload page', test => { it('should close browser with beforeunload page', (test, parameters) => {
test.slow(); test.slow();
}, async ({browserType, defaultBrowserOptions, server, tmpDir}) => { }, async ({browserType, defaultBrowserOptions, server, tmpDir}) => {
const browserContext = await browserType.launchPersistentContext(tmpDir, {...defaultBrowserOptions, headless: false}); const browserContext = await browserType.launchPersistentContext(tmpDir, {...defaultBrowserOptions, headless: false});
@ -94,7 +94,7 @@ it('should close browser after context menu was triggered', async ({browserType,
await browser.close(); await browser.close();
}); });
it('should(not) block third party cookies', async ({browserType, defaultBrowserOptions, server}) => { it('should(not) block third party cookies', async ({browserType, defaultBrowserOptions, server, isChromium, isFirefox}) => {
const browser = await browserType.launch({...defaultBrowserOptions, headless: false }); const browser = await browserType.launch({...defaultBrowserOptions, headless: false });
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
@ -112,7 +112,7 @@ it('should(not) block third party cookies', async ({browserType, defaultBrowserO
return document.cookie; return document.cookie;
}); });
await page.waitForTimeout(2000); await page.waitForTimeout(2000);
const allowsThirdParty = options.CHROMIUM || options.FIREFOX; const allowsThirdParty = isChromium || isFirefox;
expect(documentCookie).toBe(allowsThirdParty ? 'username=John Doe' : ''); expect(documentCookie).toBe(allowsThirdParty ? 'username=John Doe' : '');
const cookies = await page.context().cookies(server.CROSS_PROCESS_PREFIX + '/grid.html'); const cookies = await page.context().cookies(server.CROSS_PROCESS_PREFIX + '/grid.html');
if (allowsThirdParty) { if (allowsThirdParty) {
@ -134,8 +134,8 @@ it('should(not) block third party cookies', async ({browserType, defaultBrowserO
await browser.close(); await browser.close();
}); });
it('should not override viewport size when passed null', test => { it('should not override viewport size when passed null', (test, parameters) => {
test.fixme(options.WEBKIT); test.fixme(options.WEBKIT(parameters));
}, async function({browserType, defaultBrowserOptions, server}) { }, async function({browserType, defaultBrowserOptions, 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({...defaultBrowserOptions, headless: false });

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('should work for primitives', async ({page}) => { it('should work for primitives', async ({page}) => {
const numberHandle = await page.evaluateHandle(() => 2); const numberHandle = await page.evaluateHandle(() => 2);
@ -36,7 +36,7 @@ it('should work for promises', async ({page}) => {
expect(bHandle.toString()).toBe('JSHandle@promise'); expect(bHandle.toString()).toBe('JSHandle@promise');
}); });
it('should work with different subtypes', async ({page}) => { it('should work with different subtypes', async ({page, isWebKit}) => {
expect((await page.evaluateHandle('(function(){})')).toString()).toBe('JSHandle@function'); expect((await page.evaluateHandle('(function(){})')).toString()).toBe('JSHandle@function');
expect((await page.evaluateHandle('12')).toString()).toBe('JSHandle@12'); expect((await page.evaluateHandle('12')).toString()).toBe('JSHandle@12');
expect((await page.evaluateHandle('true')).toString()).toBe('JSHandle@true'); expect((await page.evaluateHandle('true')).toString()).toBe('JSHandle@true');
@ -54,6 +54,6 @@ it('should work with different subtypes', async ({page}) => {
expect((await page.evaluateHandle('new WeakSet()')).toString()).toBe('JSHandle@weakset'); expect((await page.evaluateHandle('new WeakSet()')).toString()).toBe('JSHandle@weakset');
expect((await page.evaluateHandle('new Error()')).toString()).toBe('JSHandle@error'); expect((await page.evaluateHandle('new Error()')).toString()).toBe('JSHandle@error');
// TODO(yurys): change subtype from array to typedarray in WebKit. // TODO(yurys): change subtype from array to typedarray in WebKit.
expect((await page.evaluateHandle('new Int32Array()')).toString()).toBe(options.WEBKIT ? 'JSHandle@array' : 'JSHandle@typedarray'); expect((await page.evaluateHandle('new Int32Array()')).toString()).toBe(isWebKit ? 'JSHandle@array' : 'JSHandle@typedarray');
expect((await page.evaluateHandle('new Proxy({}, {})')).toString()).toBe('JSHandle@proxy'); expect((await page.evaluateHandle('new Proxy({}, {})')).toString()).toBe('JSHandle@proxy');
}); });

View file

@ -83,8 +83,8 @@ it('insertText should only emit input event', async ({page, server}) => {
expect(await events.jsonValue()).toEqual(['input']); expect(await events.jsonValue()).toEqual(['input']);
}); });
it('should report shiftKey', test => { it('should report shiftKey', (test, parameters) => {
test.fail(options.FIREFOX && MAC); test.fail(options.FIREFOX(parameters) && MAC);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/input/keyboard.html'); await page.goto(server.PREFIX + '/input/keyboard.html');
const keyboard = page.keyboard; const keyboard = page.keyboard;
@ -342,7 +342,7 @@ it('should be able to prevent selectAll', async ({page, server}) => {
expect(await page.$eval('textarea', textarea => textarea.value)).toBe('some tex'); expect(await page.$eval('textarea', textarea => textarea.value)).toBe('some tex');
}); });
it('should support MacOS shortcuts', test => { it('should support MacOS shortcuts', (test, parameters) => {
test.skip(!MAC); test.skip(!MAC);
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/input/textarea.html'); await page.goto(server.PREFIX + '/input/textarea.html');
@ -354,21 +354,21 @@ it('should support MacOS shortcuts', test => {
expect(await page.$eval('textarea', textarea => textarea.value)).toBe('some '); expect(await page.$eval('textarea', textarea => textarea.value)).toBe('some ');
}); });
it('should press the meta key', async ({page}) => { it('should press the meta key', async ({page, isFirefox}) => {
const lastEvent = await captureLastKeydown(page); const lastEvent = await captureLastKeydown(page);
await page.keyboard.press('Meta'); await page.keyboard.press('Meta');
const {key, code, metaKey} = await lastEvent.jsonValue(); const {key, code, metaKey} = await lastEvent.jsonValue();
if (options.FIREFOX && !MAC) if (isFirefox && !MAC)
expect(key).toBe('OS'); expect(key).toBe('OS');
else else
expect(key).toBe('Meta'); expect(key).toBe('Meta');
if (options.FIREFOX) if (isFirefox)
expect(code).toBe('OSLeft'); expect(code).toBe('OSLeft');
else else
expect(code).toBe('MetaLeft'); expect(code).toBe('MetaLeft');
if (options.FIREFOX && !MAC) if (isFirefox && !MAC)
expect(metaKey).toBe(false); expect(metaKey).toBe(false);
else else
expect(metaKey).toBe(true); expect(metaKey).toBe(true);
@ -384,9 +384,9 @@ it('should work after a cross origin navigation', async ({page, server}) => {
}); });
// event.keyIdentifier has been removed from all browsers except WebKit // event.keyIdentifier has been removed from all browsers except WebKit
it('should expose keyIdentifier in webkit', test => { it('should expose keyIdentifier in webkit', (test, parameters) => {
test.skip(!options.WEBKIT); test.skip(!options.WEBKIT(parameters));
}, async ({page, server}) => { }, async ({page}) => {
const lastEvent = await captureLastKeydown(page); const lastEvent = await captureLastKeydown(page);
const keyMap = { const keyMap = {
'ArrowUp': 'Up', 'ArrowUp': 'Up',

View file

@ -27,10 +27,9 @@ function dimensions() {
}; };
} }
it('should click the document', test => { it('should click the document', (test, parameters) => {
test.flaky(options.FIREFOX && WIN); test.flaky(options.FIREFOX(parameters) && WIN, 'Occasionally times out on options.FIREFOX on Windows: https://github.com/microsoft/playwright/pull/1911/checks?check_run_id=607149016');
}, async ({page, server}) => { }, async ({page, server}) => {
// Occasionally times out on options.FIREFOX on Windows: https://github.com/microsoft/playwright/pull/1911/checks?check_run_id=607149016
await page.evaluate(() => { await page.evaluate(() => {
window['clickPromise'] = new Promise(resolve => { window['clickPromise'] = new Promise(resolve => {
document.addEventListener('click', event => { document.addEventListener('click', event => {
@ -124,12 +123,12 @@ it('should trigger hover state with removed window.Node', async ({page, server})
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-6'); expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-6');
}); });
it('should set modifier keys on click', async ({page, server}) => { it('should set modifier keys on click', async ({page, server, isFirefox}) => {
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
await page.evaluate(() => document.querySelector('#button-3').addEventListener('mousedown', e => window['lastEvent'] = e, true)); await page.evaluate(() => document.querySelector('#button-3').addEventListener('mousedown', e => window['lastEvent'] = e, true));
const modifiers = {'Shift': 'shiftKey', 'Control': 'ctrlKey', 'Alt': 'altKey', 'Meta': 'metaKey'}; const modifiers = {'Shift': 'shiftKey', 'Control': 'ctrlKey', 'Alt': 'altKey', 'Meta': 'metaKey'};
// In Firefox, the Meta modifier only exists on Mac // In Firefox, the Meta modifier only exists on Mac
if (options.FIREFOX && !MAC) if (isFirefox && !MAC)
delete modifiers['Meta']; delete modifiers['Meta'];
for (const modifier in modifiers) { for (const modifier in modifiers) {
await page.keyboard.down(modifier); await page.keyboard.down(modifier);
@ -145,9 +144,9 @@ it('should set modifier keys on click', async ({page, server}) => {
} }
}); });
it('should tween mouse movement', async ({page}) => { it('should tween mouse movement', async ({page, isWebKit}) => {
// The test becomes flaky on WebKit without next line. // The test becomes flaky on WebKit without next line.
if (options.WEBKIT) if (isWebKit)
await page.evaluate(() => new Promise(requestAnimationFrame)); await page.evaluate(() => new Promise(requestAnimationFrame));
await page.mouse.move(100, 100); await page.mouse.move(100, 100);
await page.evaluate(() => { await page.evaluate(() => {
@ -166,8 +165,8 @@ it('should tween mouse movement', async ({page}) => {
]); ]);
}); });
it('should work with mobile viewports and cross process navigations', test => { it('should work with mobile viewports and cross process navigations', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browser, server}) => { }, async ({browser, server}) => {
// @see https://crbug.com/929806 // @see https://crbug.com/929806
const context = await browser.newContext({ viewport: {width: 360, height: 640}, isMobile: true }); const context = await browser.newContext({ viewport: {width: 360, height: 640}, isMobile: true });

View file

@ -45,18 +45,18 @@ it('should work for fetch requests', async ({page, server}) => {
expect(requests[0].frame()).toBe(page.mainFrame()); expect(requests[0].frame()).toBe(page.mainFrame());
}); });
it('should return headers', async ({page, server}) => { it('should return headers', async ({page, server, isChromium, isFirefox, isWebKit}) => {
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
if (options.CHROMIUM) if (isChromium)
expect(response.request().headers()['user-agent']).toContain('Chrome'); expect(response.request().headers()['user-agent']).toContain('Chrome');
else if (options.FIREFOX) else if (isFirefox)
expect(response.request().headers()['user-agent']).toContain('Firefox'); expect(response.request().headers()['user-agent']).toContain('Firefox');
else if (options.WEBKIT) else if (isWebKit)
expect(response.request().headers()['user-agent']).toContain('WebKit'); expect(response.request().headers()['user-agent']).toContain('WebKit');
}); });
it('should get the same headers as the server', test => { it('should get the same headers as the server', (test, parameters) => {
test.fail(options.CHROMIUM || options.WEBKIT); test.fail(options.CHROMIUM(parameters) || options.WEBKIT(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.PREFIX + '/empty.html'); await page.goto(server.PREFIX + '/empty.html');
let serverRequest; let serverRequest;

View file

@ -74,8 +74,8 @@ it('should work with a path', async ({page, server}) => {
expect(await page.evaluate(() => window['__injected'])).toBe(42); expect(await page.evaluate(() => window['__injected'])).toBe(42);
}); });
it('should include sourceURL when path is provided', test => { it('should include sourceURL when path is provided', (test, parameters) => {
test.skip(options.WEBKIT); test.skip(options.WEBKIT(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.addScriptTag({ path: path.join(__dirname, 'assets/injectedfile.js') }); await page.addScriptTag({ path: path.join(__dirname, 'assets/injectedfile.js') });

View file

@ -34,7 +34,7 @@ it('should not be visible in context.pages', async ({context}) => {
expect(context.pages()).not.toContain(newPage); expect(context.pages()).not.toContain(newPage);
}); });
it('should run beforeunload if asked for', async ({context, server}) => { it('should run beforeunload if asked for', async ({context, server, isChromium, isWebKit}) => {
const newPage = await context.newPage(); const newPage = await context.newPage();
await newPage.goto(server.PREFIX + '/beforeunload.html'); await newPage.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
@ -44,9 +44,9 @@ it('should run beforeunload if asked for', async ({context, server}) => {
const dialog = await newPage.waitForEvent('dialog'); const dialog = await newPage.waitForEvent('dialog');
expect(dialog.type()).toBe('beforeunload'); expect(dialog.type()).toBe('beforeunload');
expect(dialog.defaultValue()).toBe(''); expect(dialog.defaultValue()).toBe('');
if (options.CHROMIUM) if (isChromium)
expect(dialog.message()).toBe(''); expect(dialog.message()).toBe('');
else if (options.WEBKIT) else if (isWebKit)
expect(dialog.message()).toBe('Leave?'); expect(dialog.message()).toBe('Leave?');
else else
expect(dialog.message()).toBe('This page is asking you to confirm that you want to leave - data you have entered may not be saved.'); expect(dialog.message()).toBe('This page is asking you to confirm that you want to leave - data you have entered may not be saved.');
@ -197,7 +197,7 @@ it('page.frame should respect url', async function({page, server}) {
expect(page.frame({ url: /empty/ }).url()).toBe(server.EMPTY_PAGE); expect(page.frame({ url: /empty/ }).url()).toBe(server.EMPTY_PAGE);
}); });
it('should have sane user agent', async ({page}) => { it('should have sane user agent', async ({page, isChromium, isFirefox}) => {
const userAgent = await page.evaluate(() => navigator.userAgent); const userAgent = await page.evaluate(() => navigator.userAgent);
const [ const [
part1, part1,
@ -211,7 +211,7 @@ it('should have sane user agent', async ({page}) => {
// Second part in parenthesis is platform - ignore it. // Second part in parenthesis is platform - ignore it.
// Third part for Firefox is the last one and encodes engine and browser versions. // Third part for Firefox is the last one and encodes engine and browser versions.
if (options.FIREFOX) { if (isFirefox) {
const [engine, browser] = part3.split(' '); const [engine, browser] = part3.split(' ');
expect(engine.startsWith('Gecko')).toBe(true); expect(engine.startsWith('Gecko')).toBe(true);
expect(browser.startsWith('Firefox')).toBe(true); expect(browser.startsWith('Firefox')).toBe(true);
@ -225,7 +225,7 @@ it('should have sane user agent', async ({page}) => {
// 5th part encodes real browser name and engine version. // 5th part encodes real browser name and engine version.
const [engine, browser] = part5.split(' '); const [engine, browser] = part5.split(' ');
expect(browser.startsWith('Safari/')).toBe(true); expect(browser.startsWith('Safari/')).toBe(true);
if (options.CHROMIUM) if (isChromium)
expect(engine.includes('Chrome/')).toBe(true); expect(engine.includes('Chrome/')).toBe(true);
else else
expect(engine.startsWith('Version/')).toBe(true); expect(engine.startsWith('Version/')).toBe(true);
@ -252,8 +252,8 @@ it('frame.press should work', async ({page, server}) => {
expect(await frame.evaluate(() => document.querySelector('textarea').value)).toBe('a'); expect(await frame.evaluate(() => document.querySelector('textarea').value)).toBe('a');
}); });
it('frame.focus should work multiple times', test => { it('frame.focus should work multiple times', (test, parameters) => {
test.fail(options.FIREFOX); test.fail(options.FIREFOX(parameters));
}, async ({ context, server }) => { }, async ({ context, server }) => {
const page1 = await context.newPage(); const page1 = await context.newPage();
const page2 = await context.newPage(); const page2 = await context.newPage();

View file

@ -415,8 +415,8 @@ it('should not throw an error when evaluation does a navigation', async ({ page,
expect(result).toEqual([42]); expect(result).toEqual([42]);
}); });
it('should not throw an error when evaluation does a synchronous navigation and returns an object', test => { it('should not throw an error when evaluation does a synchronous navigation and returns an object', (test, parameters) => {
test.fixme(options.WEBKIT); test.fixme(options.WEBKIT(parameters));
}, async ({ page, server }) => { }, async ({ page, server }) => {
// It is imporant to be on about:blank for sync reload. // It is imporant to be on about:blank for sync reload.
const result = await page.evaluate(() => { const result = await page.evaluate(() => {
@ -435,7 +435,7 @@ it('should not throw an error when evaluation does a synchronous navigation and
expect(result).toBe(undefined); expect(result).toBe(undefined);
}); });
it('should transfer 100Mb of data from page to node.js', test => { it('should transfer 100Mb of data from page to node.js', (test, parameters) => {
test.skip(options.WIRE); test.skip(options.WIRE);
}, async ({ page }) => { }, async ({ page }) => {
// This is too slow with wire. // This is too slow with wire.

View file

@ -26,9 +26,9 @@ function crash(pageImpl, browserName) {
pageImpl._delegate._session.send('Page.crash', {}).catch(e => {}); pageImpl._delegate._session.send('Page.crash', {}).catch(e => {});
} }
describe('', suite => { describe('', (suite, parameters) => {
suite.fixme(options.WIRE); suite.fixme(options.WIRE);
suite.flaky(options.FIREFOX && WIN); suite.flaky(options.FIREFOX(parameters) && WIN);
}, () => { }, () => {
it('should emit crash event when page crashes', async ({page, browserName, toImpl}) => { it('should emit crash event when page crashes', async ({page, browserName, toImpl}) => {
await page.setContent(`<div>This page should crash</div>`); await page.setContent(`<div>This page should crash</div>`);
@ -63,9 +63,9 @@ describe('', suite => {
expect(error.message).toContain('Navigation failed because page crashed'); expect(error.message).toContain('Navigation failed because page crashed');
}); });
it('should be able to close context when page crashes', test => { it('should be able to close context when page crashes', (test, parameters) => {
test.fixme(options.WIRE); test.fixme(options.WIRE);
test.flaky(options.FIREFOX && WIN); test.flaky(options.FIREFOX(parameters) && WIN);
}, async ({page, browserName, toImpl}) => { }, async ({page, browserName, toImpl}) => {
await page.setContent(`<div>This page should crash</div>`); await page.setContent(`<div>This page should crash</div>`);
crash(toImpl(page), browserName); crash(toImpl(page), browserName);

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('Page.Events.Request', async ({page, server}) => { it('Page.Events.Request', async ({page, server}) => {
const requests = []; const requests = [];
@ -41,7 +41,7 @@ it('Page.Events.Response', async ({page, server}) => {
expect(responses[0].request()).toBeTruthy(); expect(responses[0].request()).toBeTruthy();
}); });
it('Page.Events.RequestFailed', async ({page, server}) => { it('Page.Events.RequestFailed', async ({page, server, isChromium, isWebKit}) => {
server.setRoute('/one-style.css', (req, res) => { server.setRoute('/one-style.css', (req, res) => {
res.setHeader('Content-Type', 'text/css'); res.setHeader('Content-Type', 'text/css');
res.connection.destroy(); res.connection.destroy();
@ -53,9 +53,9 @@ it('Page.Events.RequestFailed', async ({page, server}) => {
expect(failedRequests[0].url()).toContain('one-style.css'); expect(failedRequests[0].url()).toContain('one-style.css');
expect(await failedRequests[0].response()).toBe(null); expect(await failedRequests[0].response()).toBe(null);
expect(failedRequests[0].resourceType()).toBe('stylesheet'); expect(failedRequests[0].resourceType()).toBe('stylesheet');
if (options.CHROMIUM) { if (isChromium) {
expect(failedRequests[0].failure().errorText).toBe('net::ERR_EMPTY_RESPONSE'); expect(failedRequests[0].failure().errorText).toBe('net::ERR_EMPTY_RESPONSE');
} else if (options.WEBKIT) { } else if (isWebKit) {
if (MAC) if (MAC)
expect(failedRequests[0].failure().errorText).toBe('The network connection was lost.'); expect(failedRequests[0].failure().errorText).toBe('The network connection was lost.');
else if (WIN) else if (WIN)

View file

@ -17,7 +17,7 @@
import { it, expect, options } from './playwright.fixtures'; import { it, expect, options } from './playwright.fixtures';
it('should fire', async ({page, server}) => { it('should fire', async ({page, server, isWebKit}) => {
const [error] = await Promise.all([ const [error] = await Promise.all([
page.waitForEvent('pageerror'), page.waitForEvent('pageerror'),
page.goto(server.PREFIX + '/error.html'), page.goto(server.PREFIX + '/error.html'),
@ -26,13 +26,13 @@ it('should fire', async ({page, server}) => {
expect(error.message).toBe('Fancy error!'); expect(error.message).toBe('Fancy error!');
let stack = await page.evaluate(() => window['e'].stack); let stack = await page.evaluate(() => window['e'].stack);
// Note that WebKit reports the stack of the 'throw' statement instead of the Error constructor call. // Note that WebKit reports the stack of the 'throw' statement instead of the Error constructor call.
if (options.WEBKIT) if (isWebKit)
stack = stack.replace('14:25', '15:19'); stack = stack.replace('14:25', '15:19');
expect(error.stack).toBe(stack); expect(error.stack).toBe(stack);
}); });
it('should contain sourceURL', test => { it('should contain sourceURL', (test, parameters) => {
test.fail(options.WEBKIT); test.fail(options.WEBKIT(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
const [error] = await Promise.all([ const [error] = await Promise.all([
page.waitForEvent('pageerror'), page.waitForEvent('pageerror'),
@ -41,7 +41,7 @@ it('should contain sourceURL', test => {
expect(error.stack).toContain('myscript.js'); expect(error.stack).toContain('myscript.js');
}); });
it('should handle odd values', async ({page}) => { it('should handle odd values', async ({page, isFirefox}) => {
const cases = [ const cases = [
[null, 'null'], [null, 'null'],
[undefined, 'undefined'], [undefined, 'undefined'],
@ -53,28 +53,28 @@ it('should handle odd values', async ({page}) => {
page.waitForEvent('pageerror'), page.waitForEvent('pageerror'),
page.evaluate(value => setTimeout(() => { throw value; }, 0), value), page.evaluate(value => setTimeout(() => { throw value; }, 0), value),
]); ]);
expect(error.message).toBe(options.FIREFOX ? 'uncaught exception: ' + message : message); expect(error.message).toBe(isFirefox ? 'uncaught exception: ' + message : message);
} }
}); });
it('should handle object', test => { it('should handle object', (test, parameters) => {
test.fixme(options.FIREFOX); test.fixme(options.FIREFOX(parameters));
}, async ({page}) => { }, async ({page, isChromium}) => {
// Firefox just does not report this error. // Firefox just does not report this error.
const [error] = await Promise.all([ const [error] = await Promise.all([
page.waitForEvent('pageerror'), page.waitForEvent('pageerror'),
page.evaluate(() => setTimeout(() => { throw {}; }, 0)), page.evaluate(() => setTimeout(() => { throw {}; }, 0)),
]); ]);
expect(error.message).toBe(options.CHROMIUM ? 'Object' : '[object Object]'); expect(error.message).toBe(isChromium ? 'Object' : '[object Object]');
}); });
it('should handle window', test => { it('should handle window', (test, parameters) => {
test.fixme(options.FIREFOX); test.fixme(options.FIREFOX(parameters));
}, async ({page}) => { }, async ({page, isChromium}) => {
// Firefox just does not report this error. // Firefox just does not report this error.
const [error] = await Promise.all([ const [error] = await Promise.all([
page.waitForEvent('pageerror'), page.waitForEvent('pageerror'),
page.evaluate(() => setTimeout(() => { throw window; }, 0)), page.evaluate(() => setTimeout(() => { throw window; }, 0)),
]); ]);
expect(error.message).toBe(options.CHROMIUM ? 'Window' : '[object Window]'); expect(error.message).toBe(isChromium ? 'Window' : '[object Window]');
}); });

View file

@ -60,8 +60,8 @@ it('should fill date input after clicking', async ({page, server}) => {
expect(await page.$eval('input', input => input.value)).toBe('2020-03-02'); expect(await page.$eval('input', input => input.value)).toBe('2020-03-02');
}); });
it('should throw on incorrect date', test => { it('should throw on incorrect date', (test, parameters) => {
test.skip(options.WEBKIT); test.skip(options.WEBKIT(parameters));
}, async ({page}) => { }, async ({page}) => {
await page.setContent('<input type=date>'); await page.setContent('<input type=date>');
const error = await page.fill('input', '2020-13-05').catch(e => e); const error = await page.fill('input', '2020-13-05').catch(e => e);
@ -74,8 +74,8 @@ it('should fill time input', async ({page, server}) => {
expect(await page.$eval('input', input => input.value)).toBe('13:15'); expect(await page.$eval('input', input => input.value)).toBe('13:15');
}); });
it('should throw on incorrect time', test => { it('should throw on incorrect time', (test, parameters) => {
test.skip(options.WEBKIT); test.skip(options.WEBKIT(parameters));
}, async ({page}) => { }, async ({page}) => {
await page.setContent('<input type=time>'); await page.setContent('<input type=time>');
const error = await page.fill('input', '25:05').catch(e => e); const error = await page.fill('input', '25:05').catch(e => e);
@ -88,8 +88,8 @@ it('should fill datetime-local input', async ({page, server}) => {
expect(await page.$eval('input', input => input.value)).toBe('2020-03-02T05:15'); expect(await page.$eval('input', input => input.value)).toBe('2020-03-02T05:15');
}); });
it('should throw on incorrect datetime-local', test => { it('should throw on incorrect datetime-local', (test, parameters) => {
test.skip(options.WEBKIT || options.FIREFOX); test.skip(options.WEBKIT(parameters) || options.FIREFOX(parameters));
}, async ({page, server}) => { }, async ({page, server}) => {
await page.setContent('<input type=datetime-local>'); await page.setContent('<input type=datetime-local>');
const error = await page.fill('input', 'abc').catch(e => e); const error = await page.fill('input', 'abc').catch(e => e);

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
import utils from './utils'; import utils from './utils';
import path from 'path'; import path from 'path';
@ -134,7 +134,7 @@ it('should work with subframes return 204 with domcontentloaded', async ({page,
await page.goto(server.PREFIX + '/frames/one-frame.html', { waitUntil: 'domcontentloaded' }); await page.goto(server.PREFIX + '/frames/one-frame.html', { waitUntil: 'domcontentloaded' });
}); });
it('should fail when server returns 204', async ({page, server}) => { it('should fail when server returns 204', async ({page, server, isChromium, isWebKit}) => {
// Webkit just loads an empty page. // Webkit just loads an empty page.
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.statusCode = 204; res.statusCode = 204;
@ -143,9 +143,9 @@ it('should fail when server returns 204', async ({page, server}) => {
let error = null; let error = null;
await page.goto(server.EMPTY_PAGE).catch(e => error = e); await page.goto(server.EMPTY_PAGE).catch(e => error = e);
expect(error).not.toBe(null); expect(error).not.toBe(null);
if (options.CHROMIUM) if (isChromium)
expect(error.message).toContain('net::ERR_ABORTED'); expect(error.message).toContain('net::ERR_ABORTED');
else if (options.WEBKIT) else if (isWebKit)
expect(error.message).toContain('Aborted: 204 No Content'); expect(error.message).toContain('Aborted: 204 No Content');
else else
expect(error.message).toContain('NS_BINDING_ABORTED'); expect(error.message).toContain('NS_BINDING_ABORTED');
@ -165,10 +165,10 @@ it('should work when page calls history API in beforeunload', async ({page, serv
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
}); });
it('should fail when navigating to bad url', async ({page}) => { it('should fail when navigating to bad url', async ({page, isChromium, isWebKit}) => {
let error = null; let error = null;
await page.goto('asdfasdf').catch(e => error = e); await page.goto('asdfasdf').catch(e => error = e);
if (options.CHROMIUM || options.WEBKIT) if (isChromium || isWebKit)
expect(error.message).toContain('Cannot navigate to invalid URL'); expect(error.message).toContain('Cannot navigate to invalid URL');
else else
expect(error.message).toContain('Invalid url'); expect(error.message).toContain('Invalid url');
@ -210,14 +210,14 @@ it('should throw if networkidle2 is passed as an option', async ({page, server})
expect(error.message).toContain(`waitUntil: expected one of (load|domcontentloaded|networkidle)`); expect(error.message).toContain(`waitUntil: expected one of (load|domcontentloaded|networkidle)`);
}); });
it('should fail when main resources failed to load', async ({page}) => { it('should fail when main resources failed to load', async ({page, isChromium, isWebKit}) => {
let error = null; let error = null;
await page.goto('http://localhost:44123/non-existing-url').catch(e => error = e); await page.goto('http://localhost:44123/non-existing-url').catch(e => error = e);
if (options.CHROMIUM) if (isChromium)
expect(error.message).toContain('net::ERR_CONNECTION_REFUSED'); expect(error.message).toContain('net::ERR_CONNECTION_REFUSED');
else if (options.WEBKIT && WIN) else if (isWebKit && WIN)
expect(error.message).toContain(`Couldn\'t connect to server`); expect(error.message).toContain(`Couldn\'t connect to server`);
else if (options.WEBKIT) else if (isWebKit)
expect(error.message).toContain('Could not connect'); expect(error.message).toContain('Could not connect');
else else
expect(error.message).toContain('NS_ERROR_CONNECTION_REFUSED'); expect(error.message).toContain('NS_ERROR_CONNECTION_REFUSED');
@ -300,7 +300,7 @@ it('should disable timeout when its set to 0', async ({page, server}) => {
expect(loaded).toBe(true); expect(loaded).toBe(true);
}); });
it('should fail when replaced by another navigation', async ({page, server}) => { it('should fail when replaced by another navigation', async ({page, server, isChromium, isWebKit}) => {
let anotherPromise; let anotherPromise;
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
anotherPromise = page.goto(server.PREFIX + '/one-style.html'); anotherPromise = page.goto(server.PREFIX + '/one-style.html');
@ -308,9 +308,9 @@ it('should fail when replaced by another navigation', async ({page, server}) =>
}); });
const error = await page.goto(server.PREFIX + '/empty.html').catch(e => e); const error = await page.goto(server.PREFIX + '/empty.html').catch(e => e);
await anotherPromise; await anotherPromise;
if (options.CHROMIUM) if (isChromium)
expect(error.message).toContain('net::ERR_ABORTED'); expect(error.message).toContain('net::ERR_ABORTED');
else if (options.WEBKIT) else if (isWebKit)
expect(error.message).toContain('cancelled'); expect(error.message).toContain('cancelled');
else else
expect(error.message).toContain('NS_BINDING_ABORTED'); expect(error.message).toContain('NS_BINDING_ABORTED');
@ -476,7 +476,7 @@ it('should fail when canceled by another navigation', async ({page, server}) =>
expect(error.message).toBeTruthy(); expect(error.message).toBeTruthy();
}); });
it('extraHttpHeaders should be pushed to provisional page', test => { it('extraHttpHeaders should be pushed to provisional page', (test, parameters) => {
test.flaky('This test is flaky, because we cannot await page.setExtraHTTPHeaders.'); test.flaky('This test is flaky, because we cannot await page.setExtraHTTPHeaders.');
// We need a way to test our implementation by more than just public api. // We need a way to test our implementation by more than just public api.
}, async ({page, server}) => { }, async ({page, server}) => {

View file

@ -52,8 +52,8 @@ it('page.goBack should work with HistoryAPI', async ({page, server}) => {
expect(page.url()).toBe(server.PREFIX + '/first.html'); expect(page.url()).toBe(server.PREFIX + '/first.html');
}); });
it('page.goBack should work for file urls', test => { it('page.goBack should work for file urls', (test, parameters) => {
test.fail(options.WEBKIT && MAC); test.fail(options.WEBKIT(parameters) && MAC);
}, async ({page, server, asset}) => { }, async ({page, server, asset}) => {
// WebKit embedder fails to go back/forward to the file url. // WebKit embedder fails to go back/forward to the file url.
const url1 = url.pathToFileURL(asset('empty.html')).href; const url1 = url.pathToFileURL(asset('empty.html')).href;

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('should intercept', async ({page, server}) => { it('should intercept', async ({page, server}) => {
let intercepted = false; let intercepted = false;
@ -183,15 +183,15 @@ it('should be abortable', async ({page, server}) => {
expect(failed).toBe(true); expect(failed).toBe(true);
}); });
it('should be abortable with custom error codes', async ({page, server}) => { it('should be abortable with custom error codes', async ({page, server, isWebKit, isFirefox}) => {
await page.route('**/*', route => route.abort('internetdisconnected')); await page.route('**/*', route => route.abort('internetdisconnected'));
let failedRequest = null; let failedRequest = null;
page.on('requestfailed', request => failedRequest = request); page.on('requestfailed', request => failedRequest = request);
await page.goto(server.EMPTY_PAGE).catch(e => {}); await page.goto(server.EMPTY_PAGE).catch(e => {});
expect(failedRequest).toBeTruthy(); expect(failedRequest).toBeTruthy();
if (options.WEBKIT) if (isWebKit)
expect(failedRequest.failure().errorText).toBe('Request intercepted'); expect(failedRequest.failure().errorText).toBe('Request intercepted');
else if (options.FIREFOX) else if (isFirefox)
expect(failedRequest.failure().errorText).toBe('NS_ERROR_OFFLINE'); expect(failedRequest.failure().errorText).toBe('NS_ERROR_OFFLINE');
else else
expect(failedRequest.failure().errorText).toBe('net::ERR_INTERNET_DISCONNECTED'); expect(failedRequest.failure().errorText).toBe('net::ERR_INTERNET_DISCONNECTED');
@ -209,14 +209,14 @@ it('should send referer', async ({page, server}) => {
expect(request.headers['referer']).toBe('http://google.com/'); expect(request.headers['referer']).toBe('http://google.com/');
}); });
it('should fail navigation when aborting main resource', async ({page, server}) => { it('should fail navigation when aborting main resource', async ({page, server, isWebKit, isFirefox}) => {
await page.route('**/*', route => route.abort()); await page.route('**/*', route => route.abort());
let error = null; let error = null;
await page.goto(server.EMPTY_PAGE).catch(e => error = e); await page.goto(server.EMPTY_PAGE).catch(e => error = e);
expect(error).toBeTruthy(); expect(error).toBeTruthy();
if (options.WEBKIT) if (isWebKit)
expect(error.message).toContain('Request intercepted'); expect(error.message).toContain('Request intercepted');
else if (options.FIREFOX) else if (isFirefox)
expect(error.message).toContain('NS_ERROR_FAILURE'); expect(error.message).toContain('NS_ERROR_FAILURE');
else else
expect(error.message).toContain('net::ERR_FAILED'); expect(error.message).toContain('net::ERR_FAILED');

View file

@ -21,10 +21,9 @@ import path from 'path';
import fs from 'fs'; import fs from 'fs';
// Firefox headful produces a different image. // Firefox headful produces a different image.
const ffheadful = options.FIREFOX && !options.HEADLESS;
describe('page screenshot', suite => { describe('page screenshot', (suite, parameters) => {
suite.skip(ffheadful); suite.skip(options.FIREFOX(parameters) && !options.HEADLESS);
}, () => { }, () => {
it('should work', async ({page, server, golden}) => { it('should work', async ({page, server, golden}) => {
await page.setViewportSize({width: 500, height: 500}); await page.setViewportSize({width: 500, height: 500});
@ -142,8 +141,8 @@ describe('page screenshot', suite => {
await Promise.all(pages.map(page => page.close())); await Promise.all(pages.map(page => page.close()));
}); });
it('should allow transparency', test => { it('should allow transparency', (test, parameters) => {
test.fail(options.FIREFOX); test.fail(options.FIREFOX(parameters));
}, async ({page, golden}) => { }, async ({page, golden}) => {
await page.setViewportSize({ width: 50, height: 150 }); await page.setViewportSize({ width: 50, height: 150 });
await page.setContent(` await page.setContent(`
@ -178,8 +177,8 @@ describe('page screenshot', suite => {
expect(screenshot).toMatchImage(golden('screenshot-clip-odd-size.png')); expect(screenshot).toMatchImage(golden('screenshot-clip-odd-size.png'));
}); });
it('should work with a mobile viewport', test => { it('should work with a mobile viewport', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browser, server, golden}) => { }, async ({browser, server, golden}) => {
const context = await browser.newContext({ viewport: { width: 320, height: 480 }, isMobile: true }); const context = await browser.newContext({ viewport: { width: 320, height: 480 }, isMobile: true });
const page = await context.newPage(); const page = await context.newPage();
@ -189,8 +188,8 @@ describe('page screenshot', suite => {
await context.close(); await context.close();
}); });
it('should work with a mobile viewport and clip', test => { it('should work with a mobile viewport and clip', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browser, server, golden}) => { }, async ({browser, server, golden}) => {
const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true}); const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true});
const page = await context.newPage(); const page = await context.newPage();
@ -200,8 +199,8 @@ describe('page screenshot', suite => {
await context.close(); await context.close();
}); });
it('should work with a mobile viewport and fullPage', test => { it('should work with a mobile viewport and fullPage', (test, parameters) => {
test.skip(options.FIREFOX); test.skip(options.FIREFOX(parameters));
}, async ({browser, server, golden}) => { }, async ({browser, server, golden}) => {
const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true}); const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true});
const page = await context.newPage(); const page = await context.newPage();
@ -218,9 +217,9 @@ describe('page screenshot', suite => {
expect(screenshot).toMatchImage(golden('screenshot-canvas.png'), { threshold: 0.3 }); expect(screenshot).toMatchImage(golden('screenshot-canvas.png'), { threshold: 0.3 });
}); });
it('should work for webgl', test => { it('should work for webgl', (test, parameters) => {
test.fixme(options.FIREFOX); test.fixme(options.FIREFOX(parameters));
test.fixme(options.WEBKIT && LINUX); test.fixme(options.WEBKIT(parameters) && LINUX);
}, async ({page, server, golden}) => { }, async ({page, server, golden}) => {
await page.setViewportSize({width: 640, height: 480}); await page.setViewportSize({width: 640, height: 480});
await page.goto(server.PREFIX + '/screenshots/webgl.html'); await page.goto(server.PREFIX + '/screenshots/webgl.html');

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
import type { Route } from '..'; import type { Route } from '..';
it('should pick up ongoing navigation', async ({page, server}) => { it('should pick up ongoing navigation', async ({page, server}) => {
@ -69,7 +69,7 @@ it('should work with pages that have loaded before being connected to', async ({
expect(popup.url()).toBe(server.EMPTY_PAGE); expect(popup.url()).toBe(server.EMPTY_PAGE);
}); });
it('should wait for load state of empty url popup', async ({browser, page}) => { it('should wait for load state of empty url popup', async ({page, isFirefox}) => {
const [popup, readyState] = await Promise.all([ const [popup, readyState] = await Promise.all([
page.waitForEvent('popup'), page.waitForEvent('popup'),
page.evaluate(() => { page.evaluate(() => {
@ -78,8 +78,8 @@ it('should wait for load state of empty url popup', async ({browser, page}) => {
}), }),
]); ]);
await popup.waitForLoadState(); await popup.waitForLoadState();
expect(readyState).toBe(options.FIREFOX ? 'uninitialized' : 'complete'); expect(readyState).toBe(isFirefox ? 'uninitialized' : 'complete');
expect(await popup.evaluate(() => document.readyState)).toBe(options.FIREFOX ? 'uninitialized' : 'complete'); expect(await popup.evaluate(() => document.readyState)).toBe(isFirefox ? 'uninitialized' : 'complete');
}); });
it('should wait for load state of about:blank popup ', async ({browser, page}) => { it('should wait for load state of about:blank popup ', async ({browser, page}) => {

View file

@ -20,8 +20,8 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
it('should be able to save file', test => { it('should be able to save file', (test, parameters) => {
test.skip(!(options.HEADLESS && options.CHROMIUM), 'Printing to pdf is currently only supported in headless chromium.'); test.skip(!(options.HEADLESS && options.CHROMIUM(parameters)), 'Printing to pdf is currently only supported in headless chromium.');
}, async ({page, tmpDir}) => { }, async ({page, tmpDir}) => {
const outputFile = path.join(tmpDir, 'output.pdf'); const outputFile = path.join(tmpDir, 'output.pdf');
await page.pdf({path: outputFile}); await page.pdf({path: outputFile});
@ -29,8 +29,8 @@ it('should be able to save file', test => {
fs.unlinkSync(outputFile); fs.unlinkSync(outputFile);
}); });
it('should only have pdf in chromium', test => { it('should only have pdf in chromium', (test, parameters) => {
test.skip(options.CHROMIUM); test.skip(options.CHROMIUM(parameters));
}, async ({page}) => { }, async ({page}) => {
expect(page.pdf).toBe(undefined); expect(page.pdf).toBe(undefined);
}); });

View file

@ -21,8 +21,8 @@ function getPermission(page, name) {
return page.evaluate(name => navigator.permissions.query({name}).then(result => result.state), name); return page.evaluate(name => navigator.permissions.query({name}).then(result => result.state), name);
} }
describe('permissions', suite => { describe('permissions', (suite, parameters) => {
suite.skip(options.WEBKIT); suite.skip(options.WEBKIT(parameters));
}, () => { }, () => {
it('should be prompt by default', async ({page, server, context}) => { it('should be prompt by default', async ({page, server, context}) => {
// Permissions API is not implemented in WebKit (see https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API) // Permissions API is not implemented in WebKit (see https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API)
@ -101,10 +101,10 @@ describe('permissions', suite => {
expect(await getPermission(page, 'geolocation')).toBe('prompt'); expect(await getPermission(page, 'geolocation')).toBe('prompt');
}); });
it('should trigger permission onchange', test => { it('should trigger permission onchange', (test, parameters) => {
test.fail(options.WEBKIT); test.fail(options.WEBKIT(parameters));
test.fail(options.CHROMIUM && !options.HEADLESS); test.fail(options.CHROMIUM(parameters) && !options.HEADLESS);
test.flaky(options.FIREFOX && LINUX); test.flaky(options.FIREFOX(parameters) && LINUX);
}, async ({page, server, context}) => { }, async ({page, server, context}) => {
// TODO: flaky // TODO: flaky
// - Linux: https://github.com/microsoft/playwright/pull/1790/checks?check_run_id=587327883 // - Linux: https://github.com/microsoft/playwright/pull/1790/checks?check_run_id=587327883
@ -147,10 +147,10 @@ describe('permissions', suite => {
await otherContext.close(); await otherContext.close();
}); });
it('should support clipboard read', test => { it('should support clipboard read', (test, parameters) => {
test.fail(options.WEBKIT); test.fail(options.WEBKIT(parameters));
test.fail(options.FIREFOX, 'No such permissions (requires flag) in Firefox'); test.fail(options.FIREFOX(parameters), 'No such permissions (requires flag) in Firefox');
test.fixme(options.CHROMIUM && !options.HEADLESS); test.fixme(options.CHROMIUM(parameters) && !options.HEADLESS);
}, async ({page, server, context}) => { }, async ({page, server, context}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
expect(await getPermission(page, 'clipboard-read')).toBe('prompt'); expect(await getPermission(page, 'clipboard-read')).toBe('prompt');

View file

@ -26,19 +26,25 @@ import { installCoverageHooks } from './coverage';
import { mkdtempAsync, removeFolderAsync } from './utils'; import { mkdtempAsync, removeFolderAsync } from './utils';
import { fixtures as baseFixtures } from '@playwright/test-runner'; import { fixtures as baseFixtures } from '@playwright/test-runner';
export type PlaywrightWorkerFixtures = { type PlaywrightParameters = {
browserName: string;
};
type PlaywrightWorkerFixtures = {
asset: (path: string) => string; asset: (path: string) => string;
defaultBrowserOptions: LaunchOptions; defaultBrowserOptions: LaunchOptions;
golden: (path: string) => string; golden: (path: string) => string;
playwright: typeof import('../index'); playwright: typeof import('../index');
browserName: string;
browserType: BrowserType<Browser>; browserType: BrowserType<Browser>;
browser: Browser; browser: Browser;
httpService: {server: TestServer, httpsServer: TestServer} httpService: {server: TestServer, httpsServer: TestServer}
toImpl: (rpcObject: any) => any; toImpl: (rpcObject: any) => any;
isChromium: boolean;
isFirefox: boolean;
isWebKit: boolean;
}; };
export type PlaywrightFixtures = { type PlaywrightFixtures = {
context: BrowserContext; context: BrowserContext;
server: TestServer; server: TestServer;
page: Page; page: Page;
@ -47,8 +53,12 @@ export type PlaywrightFixtures = {
launchPersistent: (options?: Parameters<BrowserType<Browser>['launchPersistentContext']>[1]) => Promise<{context: BrowserContext, page: Page}>; launchPersistent: (options?: Parameters<BrowserType<Browser>['launchPersistentContext']>[1]) => Promise<{context: BrowserContext, page: Page}>;
}; };
const fixtures = baseFixtures.extend<PlaywrightWorkerFixtures, PlaywrightFixtures>(); const fixtures = baseFixtures
const { registerFixture, registerWorkerFixture } = fixtures; .declareParameters<PlaywrightParameters>()
.declareWorkerFixtures<PlaywrightWorkerFixtures>()
.declareTestFixtures<PlaywrightFixtures>();
const { defineTestFixture, defineWorkerFixture, defineParameter } = fixtures;
export const playwrightFixtures = fixtures; export const playwrightFixtures = fixtures;
export const it = fixtures.it; export const it = fixtures.it;
export const fit = fixtures.fit; export const fit = fixtures.fit;
@ -63,9 +73,9 @@ export const afterAll = fixtures.afterAll;
export const expect = fixtures.expect; export const expect = fixtures.expect;
export const options = { export const options = {
CHROMIUM: fixtures.parameters.browserName === 'chromium', CHROMIUM: parameters => parameters.browserName === 'chromium',
FIREFOX: fixtures.parameters.browserName === 'firefox', FIREFOX: parameters => parameters.browserName === 'firefox',
WEBKIT: fixtures.parameters.browserName === 'webkit', WEBKIT: parameters => parameters.browserName === 'webkit',
HEADLESS: !!valueFromEnv('HEADLESS', true), HEADLESS: !!valueFromEnv('HEADLESS', true),
WIRE: !!process.env.PWWIRE, WIRE: !!process.env.PWWIRE,
SLOW_MO: valueFromEnv('SLOW_MO', 0), SLOW_MO: valueFromEnv('SLOW_MO', 0),
@ -83,7 +93,7 @@ global['MAC'] = platform === 'darwin';
global['LINUX'] = platform === 'linux'; global['LINUX'] = platform === 'linux';
global['WIN'] = platform === 'win32'; global['WIN'] = platform === 'win32';
registerWorkerFixture('httpService', async ({parallelIndex}, test) => { defineWorkerFixture('httpService', async ({parallelIndex}, test) => {
const assetsPath = path.join(__dirname, 'assets'); const assetsPath = path.join(__dirname, 'assets');
const cachedPath = path.join(__dirname, 'assets', 'cached'); const cachedPath = path.join(__dirname, 'assets', 'cached');
@ -112,7 +122,7 @@ const getExecutablePath = browserName => {
return process.env.WKPATH; return process.env.WKPATH;
}; };
registerWorkerFixture('defaultBrowserOptions', async ({browserName}, test) => { defineWorkerFixture('defaultBrowserOptions', async ({browserName}, test) => {
const executablePath = getExecutablePath(browserName); const executablePath = getExecutablePath(browserName);
if (executablePath) if (executablePath)
@ -125,7 +135,7 @@ registerWorkerFixture('defaultBrowserOptions', async ({browserName}, test) => {
}); });
}); });
registerWorkerFixture('playwright', async ({browserName}, test) => { defineWorkerFixture('playwright', async ({browserName, parallelIndex}, test) => {
const {coverage, uninstall} = installCoverageHooks(browserName); const {coverage, uninstall} = installCoverageHooks(browserName);
if (options.WIRE) { if (options.WIRE) {
require('../lib/utils/utils').setUnderTest(); require('../lib/utils/utils').setUnderTest();
@ -163,27 +173,37 @@ registerWorkerFixture('playwright', async ({browserName}, test) => {
async function teardownCoverage() { async function teardownCoverage() {
uninstall(); uninstall();
const coveragePath = path.join(__dirname, 'coverage-report', fixtures.parameters.parallelIndex + '.json'); const coveragePath = path.join(__dirname, 'coverage-report', parallelIndex + '.json');
const coverageJSON = [...coverage.keys()].filter(key => coverage.get(key)); const coverageJSON = [...coverage.keys()].filter(key => coverage.get(key));
await fs.promises.mkdir(path.dirname(coveragePath), { recursive: true }); await fs.promises.mkdir(path.dirname(coveragePath), { recursive: true });
await fs.promises.writeFile(coveragePath, JSON.stringify(coverageJSON, undefined, 2), 'utf8'); await fs.promises.writeFile(coveragePath, JSON.stringify(coverageJSON, undefined, 2), 'utf8');
} }
}); });
registerWorkerFixture('toImpl', async ({playwright}, test) => { defineWorkerFixture('toImpl', async ({playwright}, test) => {
await test((playwright as any)._toImpl); await test((playwright as any)._toImpl);
}); });
registerWorkerFixture('browserType', async ({playwright, browserName}, test) => { defineWorkerFixture('browserType', async ({playwright, browserName}, test) => {
const browserType = playwright[browserName]; const browserType = playwright[browserName];
await test(browserType); await test(browserType);
}); });
registerWorkerFixture('browserName', async ({}, test) => { defineParameter('browserName', 'Browser type name', '');
throw new Error(`Parameter 'browserName' is not specified`);
defineWorkerFixture('isChromium', async ({browserName}, test) => {
await test(browserName === 'chromium');
}); });
registerWorkerFixture('browser', async ({browserType, defaultBrowserOptions}, test) => { defineWorkerFixture('isFirefox', async ({browserName}, test) => {
await test(browserName === 'firefox');
});
defineWorkerFixture('isWebKit', async ({browserName}, test) => {
await test(browserName === 'webkit');
});
defineWorkerFixture('browser', async ({browserType, defaultBrowserOptions}, test) => {
const browser = await browserType.launch(defaultBrowserOptions); const browser = await browserType.launch(defaultBrowserOptions);
await test(browser); await test(browser);
if (browser.contexts().length !== 0) { if (browser.contexts().length !== 0) {
@ -193,15 +213,15 @@ registerWorkerFixture('browser', async ({browserType, defaultBrowserOptions}, te
await browser.close(); await browser.close();
}); });
registerWorkerFixture('asset', async ({}, test) => { defineWorkerFixture('asset', async ({}, test) => {
await test(p => path.join(__dirname, `assets`, p)); await test(p => path.join(__dirname, `assets`, p));
}); });
registerWorkerFixture('golden', async ({browserName}, test) => { defineWorkerFixture('golden', async ({browserName}, test) => {
await test(p => path.join(browserName, p)); await test(p => path.join(browserName, p));
}); });
registerFixture('context', async ({browser, playwright, toImpl}, runTest, info) => { defineTestFixture('context', async ({browser, playwright, toImpl}, runTest, info) => {
const context = await browser.newContext(); const context = await browser.newContext();
const { test, config } = info; const { test, config } = info;
if ((playwright as any).__tracer) { if ((playwright as any).__tracer) {
@ -215,7 +235,7 @@ registerFixture('context', async ({browser, playwright, toImpl}, runTest, info)
await context.close(); await context.close();
}); });
registerFixture('page', async ({context, playwright, toImpl}, runTest, info) => { defineTestFixture('page', async ({context, playwright, toImpl}, runTest, info) => {
const page = await context.newPage(); const page = await context.newPage();
await runTest(page); await runTest(page);
const { test, config, result } = info; const { test, config, result } = info;
@ -229,7 +249,7 @@ registerFixture('page', async ({context, playwright, toImpl}, runTest, info) =>
} }
}); });
registerFixture('launchPersistent', async ({tmpDir, defaultBrowserOptions, browserType}, test) => { defineTestFixture('launchPersistent', async ({tmpDir, defaultBrowserOptions, browserType}, test) => {
let context; let context;
async function launchPersistent(options) { async function launchPersistent(options) {
if (context) if (context)
@ -243,17 +263,17 @@ registerFixture('launchPersistent', async ({tmpDir, defaultBrowserOptions, brows
await context.close(); await context.close();
}); });
registerFixture('server', async ({httpService}, test) => { defineTestFixture('server', async ({httpService}, test) => {
httpService.server.reset(); httpService.server.reset();
await test(httpService.server); await test(httpService.server);
}); });
registerFixture('httpsServer', async ({httpService}, test) => { defineTestFixture('httpsServer', async ({httpService}, test) => {
httpService.httpsServer.reset(); httpService.httpsServer.reset();
await test(httpService.httpsServer); await test(httpService.httpsServer);
}); });
registerFixture('tmpDir', async ({}, test) => { defineTestFixture('tmpDir', async ({}, test) => {
const tmpDir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-')); const tmpDir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-'));
await test(tmpDir); await test(tmpDir);
await removeFolderAsync(tmpDir).catch(e => {}); await removeFolderAsync(tmpDir).catch(e => {});

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('should inherit user agent from browser context', async function({browser, server}) { it('should inherit user agent from browser context', async function({browser, server}) {
const context = await browser.newContext({ const context = await browser.newContext({
@ -210,7 +210,7 @@ it('should expose function from browser context', async function({browser, serve
expect(messages.join('|')).toBe('page|binding'); expect(messages.join('|')).toBe('page|binding');
}); });
it('should not dispatch binding on a closed page', async function({browser, server}) { it('should not dispatch binding on a closed page', async function({browser, server, isFirefox}) {
const context = await browser.newContext(); const context = await browser.newContext();
const messages = []; const messages = [];
await context.exposeFunction('add', (a, b) => { await context.exposeFunction('add', (a, b) => {
@ -233,7 +233,7 @@ it('should not dispatch binding on a closed page', async function({browser, serv
}), }),
]); ]);
await context.close(); await context.close();
if (options.FIREFOX) if (isFirefox)
expect(messages.join('|')).toBe('close'); expect(messages.join('|')).toBe('close');
else else
expect(messages.join('|')).toBe('binding|close'); expect(messages.join('|')).toBe('binding|close');

View file

@ -77,8 +77,8 @@ it('should authenticate', async ({browserType, defaultBrowserOptions, server}) =
await browser.close(); await browser.close();
}); });
it('should exclude patterns', test => { it('should exclude patterns', (test, parameters) => {
test.flaky(options.CHROMIUM && !options.HEADLESS, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.'); test.flaky(options.CHROMIUM(parameters) && !options.HEADLESS, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.');
}, async ({browserType, defaultBrowserOptions, server}) => { }, async ({browserType, defaultBrowserOptions, 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>');
@ -119,8 +119,8 @@ it('should exclude patterns', test => {
await browser.close(); await browser.close();
}); });
it('should use socks proxy', test => { it('should use socks proxy', (test, parameters) => {
test.flaky(MAC && options.WEBKIT, 'Intermittent page.goto: The network connection was lost error on bots'); test.flaky(MAC && options.WEBKIT(parameters), 'Intermittent page.goto: The network connection was lost error on bots');
}, async ({ browserType, defaultBrowserOptions, parallelIndex }) => { }, async ({ browserType, defaultBrowserOptions, parallelIndex }) => {
const server = socks.createServer((info, accept, deny) => { const server = socks.createServer((info, accept, deny) => {
let socket; let socket;

View file

@ -24,8 +24,8 @@ type ServerFixtures = {
remoteServer: RemoteServer; remoteServer: RemoteServer;
stallingRemoteServer: RemoteServer; stallingRemoteServer: RemoteServer;
}; };
export const serverFixtures = playwrightFixtures.extend<{}, ServerFixtures>(); export const serverFixtures = playwrightFixtures.declareTestFixtures<ServerFixtures>();
const { registerFixture } = serverFixtures; const { defineTestFixture } = serverFixtures;
const playwrightPath = path.join(__dirname, '..'); const playwrightPath = path.join(__dirname, '..');
@ -116,14 +116,14 @@ export class RemoteServer {
} }
} }
registerFixture('remoteServer', async ({browserType, defaultBrowserOptions}, test) => { defineTestFixture('remoteServer', async ({browserType, defaultBrowserOptions}, test) => {
const remoteServer = new RemoteServer(); const remoteServer = new RemoteServer();
await remoteServer._start(browserType, defaultBrowserOptions); await remoteServer._start(browserType, defaultBrowserOptions);
await test(remoteServer); await test(remoteServer);
await remoteServer.close(); await remoteServer.close();
}); });
registerFixture('stallingRemoteServer', async ({browserType, defaultBrowserOptions}, test) => { defineTestFixture('stallingRemoteServer', async ({browserType, defaultBrowserOptions}, test) => {
const remoteServer = new RemoteServer(); const remoteServer = new RemoteServer();
await remoteServer._start(browserType, defaultBrowserOptions, { stallOnClose: true }); await remoteServer._start(browserType, defaultBrowserOptions, { stallOnClose: true });
await test(remoteServer); await test(remoteServer);

View file

@ -50,8 +50,8 @@ it('should work with status code 422', async ({page, server}) => {
expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!'); expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!');
}); });
it('should allow mocking binary responses', test => { it('should allow mocking binary responses', (test, parameters) => {
test.skip(options.FIREFOX && !options.HEADLESS, '// Firefox headful produces a different image.'); test.skip(options.FIREFOX(parameters) && !options.HEADLESS, '// Firefox headful produces a different image.');
}, async ({page, server, golden}) => { }, async ({page, server, golden}) => {
await page.route('**/*', route => { await page.route('**/*', route => {
const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png')); const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png'));
@ -70,8 +70,8 @@ it('should allow mocking binary responses', test => {
expect(await img.screenshot()).toMatchImage(golden('mock-binary-response.png')); expect(await img.screenshot()).toMatchImage(golden('mock-binary-response.png'));
}); });
it('should allow mocking svg with charset', test => { it('should allow mocking svg with charset', (test, parameters) => {
test.skip(options.FIREFOX && !options.HEADLESS, '// Firefox headful produces a different image.'); test.skip(options.FIREFOX(parameters) && !options.HEADLESS, '// Firefox headful produces a different image.');
}, async ({page, server, golden}) => { }, async ({page, server, golden}) => {
// Firefox headful produces a different image. // Firefox headful produces a different image.
await page.route('**/*', route => { await page.route('**/*', route => {

View file

@ -24,10 +24,10 @@ import { TestServer } from '../utils/testserver';
type TestState = { type TestState = {
videoPlayer: VideoPlayer; videoPlayer: VideoPlayer;
}; };
const fixtures = playwrightFixtures.extend<{}, TestState>(); const fixtures = playwrightFixtures.declareTestFixtures<TestState>();
const { it, expect, describe, registerFixture } = fixtures; const { it, expect, describe, defineTestFixture } = fixtures;
registerFixture('videoPlayer', async ({playwright, context, server}, test) => { defineTestFixture('videoPlayer', async ({playwright, context, server}, test) => {
// WebKit on Mac & Windows cannot replay webm/vp8 video, is unrelyable // WebKit on Mac & Windows cannot replay webm/vp8 video, is unrelyable
// on Linux (times out) and in Firefox, so we always launch chromium for // on Linux (times out) and in Firefox, so we always launch chromium for
// playback. // playback.
@ -181,7 +181,7 @@ describe('screencast', suite => {
expectAll(pixels, almostRed); expectAll(pixels, almostRed);
}); });
it('should capture navigation', test => { it('should capture navigation', (test, parameters) => {
test.flaky(); test.flaky();
}, async ({page, tmpDir, server, videoPlayer, toImpl}) => { }, async ({page, tmpDir, server, videoPlayer, toImpl}) => {
const videoFile = path.join(tmpDir, 'v.webm'); const videoFile = path.join(tmpDir, 'v.webm');
@ -210,8 +210,8 @@ describe('screencast', suite => {
} }
}); });
it('should capture css transformation', test => { it('should capture css transformation', (test, parameters) => {
test.fail(options.WEBKIT && WIN, 'Does not work on WebKit Windows'); test.fail(options.WEBKIT(parameters) && WIN, 'Does not work on WebKit Windows');
}, async ({page, tmpDir, server, videoPlayer, toImpl}) => { }, async ({page, tmpDir, server, videoPlayer, toImpl}) => {
const videoFile = path.join(tmpDir, 'v.webm'); const videoFile = path.join(tmpDir, 'v.webm');
// Set viewport equal to screencast frame size to avoid scaling. // Set viewport equal to screencast frame size to avoid scaling.

View file

@ -15,9 +15,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, expect, options } from './playwright.fixtures'; import { it, expect } from './playwright.fixtures';
it('query', async ({page}) => { it('query', async ({page, isWebKit}) => {
await page.setContent(`<div>yo</div><div>ya</div><div>\nye </div>`); await page.setContent(`<div>yo</div><div>ya</div><div>\nye </div>`);
expect(await page.$eval(`text=ya`, e => e.outerHTML)).toBe('<div>ya</div>'); expect(await page.$eval(`text=ya`, e => e.outerHTML)).toBe('<div>ya</div>');
expect(await page.$eval(`text="ya"`, e => e.outerHTML)).toBe('<div>ya</div>'); expect(await page.$eval(`text="ya"`, e => e.outerHTML)).toBe('<div>ya</div>');
@ -59,9 +59,9 @@ it('query', async ({page}) => {
expect(await page.$eval(`"x"`, e => e.outerHTML)).toBe('<div>x</div>'); expect(await page.$eval(`"x"`, e => e.outerHTML)).toBe('<div>x</div>');
expect(await page.$eval(`'x'`, e => e.outerHTML)).toBe('<div>x</div>'); expect(await page.$eval(`'x'`, e => e.outerHTML)).toBe('<div>x</div>');
let error = await page.$(`"`).catch(e => e); let error = await page.$(`"`).catch(e => e);
expect(error.message).toContain(options.WEBKIT ? 'SyntaxError' : 'querySelector'); expect(error.message).toContain(isWebKit ? 'SyntaxError' : 'querySelector');
error = await page.$(`'`).catch(e => e); error = await page.$(`'`).catch(e => e);
expect(error.message).toContain(options.WEBKIT ? 'SyntaxError' : 'querySelector'); expect(error.message).toContain(isWebKit ? 'SyntaxError' : 'querySelector');
await page.setContent(`<div> ' </div><div> " </div>`); await page.setContent(`<div> ' </div><div> " </div>`);
expect(await page.$eval(`text="`, e => e.outerHTML)).toBe('<div> " </div>'); expect(await page.$eval(`text="`, e => e.outerHTML)).toBe('<div> " </div>');

View file

@ -14,16 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
declare const before: (f: () => Promise<any>) => void; (global as any).setParameterValues(
declare const after: (f: () => Promise<any>) => void; 'browserName',
declare const matrix: (m: any) => void; process.env.BROWSER ? [process.env.BROWSER] : ['chromium', 'webkit', 'firefox']);
matrix({
'browserName': process.env.BROWSER ? [process.env.BROWSER] : ['chromium', 'webkit', 'firefox'],
});
before(async () => {
});
after(async () => {
});

View file

@ -16,7 +16,7 @@
import { it, options } from './playwright.fixtures'; import { it, options } from './playwright.fixtures';
it('should not throw', test => { it('should not throw', (test, parameters) => {
test.skip(!options.TRACING); test.skip(!options.TRACING);
}, async ({page, server, playwright, toImpl}) => { }, async ({page, server, playwright, toImpl}) => {
await page.goto(server.PREFIX + '/snapshot/snapshot-with-css.html'); await page.goto(server.PREFIX + '/snapshot/snapshot-with-css.html');

View file

@ -145,7 +145,7 @@ const utils = module.exports = {
}, },
}); });
testRunner.on('testfinished', test => { testRunner.on('testfinished', (test, parameters) => {
// Do not report tests from COVERAGE testsuite. // Do not report tests from COVERAGE testsuite.
// They don't bring much value to us. // They don't bring much value to us.
if (test.fullName.includes('**API COVERAGE**')) if (test.fullName.includes('**API COVERAGE**'))

View file

@ -21,9 +21,9 @@ const Source = require('../../Source');
const mdBuilder = require('../MDBuilder'); const mdBuilder = require('../MDBuilder');
const jsBuilder = require('../JSBuilder'); const jsBuilder = require('../JSBuilder');
const { fixtures } = require('@playwright/test-runner'); const { fixtures } = require('@playwright/test-runner');
const { registerWorkerFixture, describe, it, expect } = fixtures; const { defineWorkerFixture, describe, it, expect } = fixtures;
registerWorkerFixture('page', async({}, test) => { defineWorkerFixture('page', async({}, test) => {
const browser = await playwright.chromium.launch(); const browser = await playwright.chromium.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await test(page); await test(page);