test: migrate most non-page tests to new folio (#6059)

This commit is contained in:
Dmitry Gozman 2021-04-02 21:07:45 -07:00 коммит произвёл GitHub
Родитель 5a1974ccad
Коммит f5781f90ba
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
67 изменённых файлов: 345 добавлений и 298 удалений

Просмотреть файл

@ -14,11 +14,10 @@
* limitations under the License.
*/
import { expect } from 'folio';
import { Page } from '..';
import { folio } from './fixtures';
import { recorderPageGetter } from './utils';
const { afterEach, it, describe } = folio;
const { afterEach, it, describe, expect } = folio;
describe('pause', (suite, { mode }) => {
suite.skip(mode !== 'default');

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 5.4 KiB

После

Ширина:  |  Высота:  |  Размер: 5.4 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 5.4 KiB

После

Ширина:  |  Высота:  |  Размер: 5.4 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 5.4 KiB

После

Ширина:  |  Высота:  |  Размер: 5.4 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 5.3 KiB

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 5.5 KiB

После

Ширина:  |  Высота:  |  Размер: 5.5 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 5.3 KiB

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 19 KiB

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 5.7 KiB

После

Ширина:  |  Высота:  |  Размер: 5.7 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 4.6 KiB

После

Ширина:  |  Высота:  |  Размер: 4.6 KiB

Просмотреть файл

@ -15,10 +15,9 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should close browser with beforeunload page', (test, {browserName}) => {
}, async ({server, browserType, browserOptions }) => {
it('should close browser with beforeunload page', async ({server, browserType, browserOptions }) => {
const browser = await browserType.launch(browserOptions);
const page = await browser.newPage();
await page.goto(server.PREFIX + '/beforeunload.html');
@ -28,8 +27,7 @@ it('should close browser with beforeunload page', (test, {browserName}) => {
await browser.close();
});
it('should close browsercontext with beforeunload page', (test, {browserName}) => {
}, async ({server, contextFactory }) => {
it('should close browsercontext with beforeunload page', async ({server, contextFactory }) => {
const browserContext = await contextFactory();
const page = await browserContext.newPage();
await page.goto(server.PREFIX + '/beforeunload.html');
@ -39,7 +37,8 @@ it('should close browsercontext with beforeunload page', (test, {browserName}) =
await browserContext.close();
});
it('should close page with beforeunload listener', async ({context, server}) => {
it('should close page with beforeunload listener', async ({contextFactory, server}) => {
const context = await contextFactory();
const newPage = await context.newPage();
await newPage.goto(server.PREFIX + '/beforeunload.html');
// We have to interact with a page so that 'beforeunload' handlers
@ -48,7 +47,8 @@ it('should close page with beforeunload listener', async ({context, server}) =>
await newPage.close();
});
it('should run beforeunload if asked for', async ({context, server, isChromium, isWebKit}) => {
it('should run beforeunload if asked for', async ({contextFactory, server, isChromium, isWebKit}) => {
const context = await contextFactory();
const newPage = await context.newPage();
await newPage.goto(server.PREFIX + '/beforeunload.html');
// We have to interact with a page so that 'beforeunload' handlers

Просмотреть файл

@ -15,7 +15,8 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { contextTest as it, expect } from './config/browserTest';
import { slowTest as playwrightTest } from './config/playwrightTest';
it('should work', async ({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
@ -157,9 +158,7 @@ it('should isolate send cookie header', async ({server, context, browser}) => {
}
});
it('should isolate cookies between launches', test => {
test.slow();
}, async ({browserType, server, browserOptions}) => {
playwrightTest('should isolate cookies between launches', async ({browserType, server, browserOptions}) => {
const browser1 = await browserType.launch(browserOptions);
const context1 = await browser1.newContext();
await context1.addCookies([{url: server.EMPTY_PAGE, name: 'cookie-in-context-1', value: 'value', expires: Date.now() / 1000 + 10000}]);

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { contextTest as it, expect } from './config/browserTest';
import path from 'path';
it('should work with browser context scripts', async ({ context, server }) => {
@ -54,7 +54,7 @@ it('should work without navigation in popup', async ({ context }) => {
});
it('should work with browser context scripts with a path', async ({ context, server }) => {
await context.addInitScript({ path: path.join(__dirname, 'assets/injectedfile.js') });
await context.addInitScript({ path: path.join(__dirname, '../test/assets/injectedfile.js') });
const page = await context.newPage();
await page.goto(server.PREFIX + '/tamperable.html');
expect(await page.evaluate(() => window['result'])).toBe(123);

Просмотреть файл

@ -15,8 +15,8 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { verifyViewport } from './utils';
import { test as it, expect } from './config/browserTest';
import { verifyViewport } from '../test/utils';
it('should create new context', async function({browser}) {
expect(browser.contexts().length).toBe(0);

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { contextTest as it, expect } from './config/browserTest';
it('should clear cookies', async ({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { contextTest as it, expect } from './config/browserTest';
it('should return no cookies in pristine browser context', async ({context, page, server}) => {
expect(await context.cookies()).toEqual([]);
@ -73,9 +73,9 @@ it('should properly report httpOnly cookie', async ({context, page, server}) =>
expect(cookies[0].httpOnly).toBe(true);
});
it('should properly report "Strict" sameSite cookie', (test, { browserName, platform }) => {
test.fail(browserName === 'webkit' && platform === 'win32');
}, async ({context, page, server}) => {
it('should properly report "Strict" sameSite cookie', async ({context, page, server, browserName, platform}) => {
it.fail(browserName === 'webkit' && platform === 'win32');
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', 'name=value;SameSite=Strict');
res.end();
@ -86,9 +86,9 @@ it('should properly report "Strict" sameSite cookie', (test, { browserName, plat
expect(cookies[0].sameSite).toBe('Strict');
});
it('should properly report "Lax" sameSite cookie', (test, { browserName, platform }) => {
test.fail(browserName === 'webkit' && platform === 'win32');
}, async ({context, page, server}) => {
it('should properly report "Lax" sameSite cookie', async ({context, page, server, browserName, platform}) => {
it.fail(browserName === 'webkit' && platform === 'win32');
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', 'name=value;SameSite=Lax');
res.end();

Просмотреть файл

@ -15,11 +15,11 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should fail without credentials', async ({browser, server, browserName, headful}) => {
it.fail(browserName === 'chromium' && headful);
it('should fail without credentials', (test, { browserName, headful}) => {
test.fail(browserName === 'chromium' && headful);
}, async ({browser, server}) => {
server.setAuth('/empty.html', 'user', 'pass');
const context = await browser.newContext();
const page = await context.newPage();
@ -28,9 +28,9 @@ it('should fail without credentials', (test, { browserName, headful}) => {
await context.close();
});
it('should work with setHTTPCredentials', (test, { browserName, headful }) => {
test.fail(browserName === 'chromium' && headful);
}, async ({browser, server}) => {
it('should work with setHTTPCredentials', async ({browser, server, browserName, headful}) => {
it.fail(browserName === 'chromium' && headful);
server.setAuth('/empty.html', 'user', 'pass');
const context = await browser.newContext();
const page = await context.newPage();

Просмотреть файл

@ -14,8 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { attachFrame } from './utils';
import { test as it, expect } from './config/browserTest';
import { attachFrame } from '../test/utils';
it('should bypass CSP meta tag', async ({browser, server}) => {
// Make sure CSP prohibits addScriptTag.

Просмотреть файл

@ -15,11 +15,13 @@
* limitations under the License.
*/
import { it, expect, describe } from './fixtures';
import { test as it, expect } from './config/browserTest';
it.describe('device', () => {
it.beforeEach(async ({browserName}) => {
it.skip(browserName === 'firefox');
});
describe('device', (suite, { browserName }) => {
suite.skip(browserName === 'firefox');
}, () => {
it('should work', async ({playwright, browser, server}) => {
const iPhone = playwright.devices['iPhone 6'];
const context = await browser.newContext({ ...iPhone });
@ -81,9 +83,9 @@ describe('device', (suite, { browserName }) => {
await context.close();
});
it('should reset scroll top after a navigation', (test, {browserName}) => {
test.skip(browserName === 'webkit');
}, async ({server, contextFactory, playwright, contextOptions}) => {
it('should reset scroll top after a navigation', async ({server, contextFactory, playwright, contextOptions, browserName}) => {
it.skip(browserName === 'webkit');
const device = playwright.devices['iPhone 6'];
const context = await contextFactory({
...contextOptions,
@ -98,9 +100,9 @@ describe('device', (suite, { browserName }) => {
await context.close();
});
it('should scroll to a precise position with mobile scale', (test, {browserName}) => {
test.skip(browserName === 'webkit');
}, async ({server, contextFactory, playwright, contextOptions}) => {
it('should scroll to a precise position with mobile scale', async ({server, contextFactory, playwright, contextOptions, browserName}) => {
it.skip(browserName === 'webkit');
const device = playwright.devices['iPhone 6'];
const context = await contextFactory({
...contextOptions,

Просмотреть файл

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should fetch lodpi assets', async ({ contextFactory, server}) => {
const context = await contextFactory({

Просмотреть файл

@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { contextTest as it, expect } from './config/browserTest';
it('expose binding should work', async ({context}) => {
let bindingSource;

Просмотреть файл

@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should affect accept-language header', async ({browser, server}) => {
const context = await browser.newContext({ locale: 'fr-CH' });

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should have url', async ({browser, server}) => {
const context = await browser.newContext();
@ -157,9 +157,9 @@ it('should fire page lifecycle events', async function({browser, server}) {
await context.close();
});
it('should work with Shift-clicking', (test, { browserName }) => {
test.fixme(browserName === 'webkit', 'WebKit: Shift+Click does not open a new window.');
}, async ({browser, server}) => {
it('should work with Shift-clicking', async ({browser, server, browserName}) => {
it.fixme(browserName === 'webkit', 'WebKit: Shift+Click does not open a new window.');
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);
@ -172,10 +172,10 @@ it('should work with Shift-clicking', (test, { browserName }) => {
await context.close();
});
it('should work with Ctrl-clicking', (test, { browserName }) => {
test.fixme(browserName === 'webkit', 'Ctrl+Click does not open a new tab.');
test.fixme(browserName === 'firefox', 'Reports an opener in this case.');
}, async ({browser, server, isMac}) => {
it('should work with Ctrl-clicking', async ({browser, server, isMac, browserName}) => {
it.fixme(browserName === 'webkit', 'Ctrl+Click does not open a new tab.');
it.fixme(browserName === 'firefox', 'Reports an opener in this case.');
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);

Просмотреть файл

@ -14,14 +14,7 @@
* limitations under the License.
*/
import { folio as baseFolio } from './fixtures';
const fixtures = baseFolio.extend();
fixtures.browserOptions.override(async ({ browserOptions }, run) => {
await run({ ...browserOptions, proxy: { server: 'per-context' } });
});
const { it, expect } = fixtures.build();
import { proxyTest as it, expect } from './config/browserTest';
it('should throw for missing global proxy', async ({ browserType, browserOptions, server }) => {
delete browserOptions.proxy;
@ -164,9 +157,9 @@ it('should authenticate with empty password', async ({contextFactory, contextOpt
});
it('should isolate proxy credentials between contexts', (test, { browserName }) => {
test.fixme(browserName === 'firefox', 'Credentials from the first context stick around');
}, async ({contextFactory, contextOptions, server}) => {
it('should isolate proxy credentials between contexts', async ({contextFactory, contextOptions, server, browserName}) => {
it.fixme(browserName === 'firefox', 'Credentials from the first context stick around');
server.setRoute('/target.html', async (req, res) => {
const auth = req.headers['proxy-authorization'];
if (!auth) {
@ -200,9 +193,9 @@ it('should isolate proxy credentials between contexts', (test, { browserName })
}
});
it('should exclude patterns', (test, { browserName, headful }) => {
test.fixme(browserName === 'chromium' && headful, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.');
}, async ({contextFactory, contextOptions, server}) => {
it('should exclude patterns', async ({contextFactory, contextOptions, server, browserName, headful}) => {
it.fixme(browserName === 'chromium' && headful, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.');
server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>');
});

Просмотреть файл

@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should intercept', async ({browser, server}) => {
const context = await browser.newContext();

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should override extra headers from browser context', async ({browser, server}) => {
const context = await browser.newContext({

Просмотреть файл

@ -15,10 +15,11 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
import fs from 'fs';
it('should capture local storage', async ({ context }) => {
it('should capture local storage', async ({ contextFactory }) => {
const context = await contextFactory();
const page1 = await context.newPage();
await page1.route('**/*', route => {
route.fulfill({ body: '<html></html>' }).catch(() => {});
@ -71,7 +72,8 @@ it('should set local storage', async ({ browser }) => {
await context.close();
});
it('should round-trip through the file', async ({ browser, context, testInfo }) => {
it('should round-trip through the file', async ({ contextFactory }, testInfo) => {
const context = await contextFactory();
const page1 = await context.newPage();
await page1.route('**/*', route => {
route.fulfill({ body: '<html></html>' }).catch(() => {});
@ -88,7 +90,7 @@ it('should round-trip through the file', async ({ browser, context, testInfo })
const written = await fs.promises.readFile(path, 'utf8');
expect(JSON.stringify(state, undefined, 2)).toBe(written);
const context2 = await browser.newContext({ storageState: path });
const context2 = await contextFactory({ storageState: path });
const page2 = await context2.newPage();
await page2.route('**/*', route => {
route.fulfill({ body: '<html></html>' }).catch(() => {});

Просмотреть файл

@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should work', async ({ browser }) => {
const func = () => new Date(1479579154987).toString();

Просмотреть файл

@ -14,8 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { attachFrame } from './utils';
import { test as it, expect } from './config/browserTest';
import { attachFrame } from '../test/utils';
it('should work', async ({browser, server}) => {
{

Просмотреть файл

@ -15,11 +15,13 @@
* limitations under the License.
*/
import { it, expect, describe } from './fixtures';
import { test as it, expect } from './config/browserTest';
it.describe('mobile viewport', () => {
it.beforeEach(async ({ browserName }) => {
it.skip(browserName === 'firefox');
});
describe('mobile viewport', (suite, { browserName }) => {
suite.skip(browserName === 'firefox');
}, () => {
it('should support mobile emulation', async ({playwright, browser, server}) => {
const iPhone = playwright.devices['iPhone 6'];
const context = await browser.newContext({ ...iPhone });

Просмотреть файл

@ -14,8 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { verifyViewport } from './utils';
import { test as it, expect } from './config/pageTest';
import { test as browserTest } from './config/browserTest';
import { verifyViewport } from '../test/utils';
it.beforeEach(async () => {
it.skip(!!process.env.PW_ANDROID_TESTS);
});
it('should get the proper default viewport size', async ({page, server}) => {
await verifyViewport(page, 1280, 720);
@ -95,7 +101,7 @@ it('should not have touch by default', async ({page, server}) => {
expect(await page.evaluate(() => document.body.textContent.trim())).toBe('NO');
});
it('should support touch with null viewport', async ({browser, server}) => {
browserTest('should support touch with null viewport', async ({browser, server}) => {
const context = await browser.newContext({ viewport: null, hasTouch: true });
const page = await context.newPage();
await page.goto(server.PREFIX + '/mobile.html');
@ -103,7 +109,7 @@ it('should support touch with null viewport', async ({browser, server}) => {
await context.close();
});
it('should report null viewportSize when given null viewport', async ({browser, server}) => {
browserTest('should report null viewportSize when given null viewport', async ({browser, server}) => {
const context = await browser.newContext({ viewport: null });
const page = await context.newPage();
expect(page.viewportSize()).toBe(null);

Просмотреть файл

@ -15,21 +15,23 @@
* limitations under the License.
*/
import { folio } from './fixtures';
const { it, expect, describe } = folio;
import { test as it, expect } from './config/playwrightTest';
it.describe('launch server', () => {
it.beforeEach(async ({ mode}) => {
it.skip(mode !== 'default');
});
describe('launch server', (suite, { mode }) => {
suite.skip(mode !== 'default');
}, () => {
it('should work', async ({browserType, browserOptions}) => {
const browserServer = await browserType.launchServer(browserOptions);
expect(browserServer.wsEndpoint()).not.toBe(null);
await browserServer.close();
});
it('should work with port', async ({browserType, browserOptions, testWorkerIndex}) => {
const browserServer = await browserType.launchServer({ ...browserOptions, port: 8800 + testWorkerIndex });
expect(browserServer.wsEndpoint()).toContain(String(8800 + testWorkerIndex));
it('should work with port', async ({browserType, browserOptions}, testInfo) => {
const port = 8800 + testInfo.workerIndex;
const browserServer = await browserType.launchServer({ ...browserOptions, port });
expect(browserServer.wsEndpoint()).toContain(String(port));
await browserServer.close();
});
@ -60,9 +62,9 @@ describe('launch server', (suite, { mode }) => {
await browserServer.close();
});
it('should fire close event', (test, { browserChannel }) => {
test.fixme(!!browserChannel, 'Uncomment on roll');
}, async ({browserType, browserOptions}) => {
it('should fire close event', async ({browserType, browserOptions, browserChannel}) => {
it.fixme(!!browserChannel, 'Uncomment on roll');
const browserServer = await browserType.launchServer(browserOptions);
const [result] = await Promise.all([
// @ts-expect-error The signal parameter is not documented.

Просмотреть файл

@ -16,7 +16,7 @@
*/
import path from 'path';
import { it, expect } from './fixtures';
import { test as it, slowTest, expect } from './config/playwrightTest';
it('should reject all promises when browser is closed', async ({browserType, browserOptions}) => {
const browser = await browserType.launch(browserOptions);
@ -55,9 +55,9 @@ it('should throw if port option is passed for persistent context', async ({brows
expect(error.message).toContain('Cannot specify a port without launching as a server.');
});
it('should throw if page argument is passed', (test, { browserName }) => {
test.skip(browserName === 'firefox');
}, async ({browserType, browserOptions}) => {
it('should throw if page argument is passed', async ({browserType, browserOptions, browserName}) => {
it.skip(browserName === 'firefox');
let waitError = null;
const options = Object.assign({}, browserOptions, { args: ['http://example.com'] });
await browserType.launch(options).catch(e => waitError = e);
@ -65,7 +65,7 @@ it('should throw if page argument is passed', (test, { browserName }) => {
});
it('should reject if launched browser fails immediately', async ({browserType, browserOptions}) => {
const options = Object.assign({}, browserOptions, {executablePath: path.join(__dirname, 'assets', 'dummy_bad_browser_executable.js')});
const options = Object.assign({}, browserOptions, {executablePath: path.join(__dirname, '..', 'test', 'assets', 'dummy_bad_browser_executable.js')});
let waitError = null;
await browserType.launch(options).catch(e => waitError = e);
expect(waitError.message).toContain('== logs ==');
@ -78,9 +78,9 @@ it('should reject if executable path is invalid', async ({browserType, browserOp
expect(waitError.message).toContain('Failed to launch');
});
it('should handle timeout', (test, { mode }) => {
test.skip(mode !== 'default');
}, async ({browserType, browserOptions}) => {
it('should handle timeout', async ({browserType, browserOptions, mode}) => {
it.skip(mode !== 'default');
const options = { ...browserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
const error = await browserType.launch(options).catch(e => e);
expect(error.message).toContain(`browserType.launch: Timeout 5000ms exceeded.`);
@ -88,27 +88,25 @@ it('should handle timeout', (test, { mode }) => {
expect(error.message).toContain(`<launched> pid=`);
});
it('should handle exception', (test, { mode }) => {
test.skip(mode !== 'default');
}, async ({browserType, browserOptions}) => {
it('should handle exception', async ({browserType, browserOptions, mode}) => {
it.skip(mode !== 'default');
const e = new Error('Dummy');
const options = { ...browserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
const error = await browserType.launch(options).catch(e => e);
expect(error.message).toContain('Dummy');
});
it('should report launch log', (test, { mode }) => {
test.skip(mode !== 'default');
}, async ({browserType, browserOptions}) => {
it('should report launch log', async ({browserType, browserOptions, mode}) => {
it.skip(mode !== 'default');
const e = new Error('Dummy');
const options = { ...browserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
const error = await browserType.launch(options).catch(e => e);
expect(error.message).toContain('<launching>');
});
it('should accept objects as options', (test, parameters) => {
test.slow();
}, async ({browserType, browserOptions}) => {
slowTest('should accept objects as options', async ({browserType, browserOptions}) => {
// @ts-expect-error process is not a real option.
const browser = await browserType.launch({ ...browserOptions, process });
await browser.close();

Просмотреть файл

@ -16,16 +16,20 @@
import os from 'os';
import url from 'url';
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('Web Assembly should work', (test, { browserName, platform }) => {
test.fail(browserName === 'webkit' && platform === 'win32');
}, async function({page, server}) {
it('Web Assembly should work', async function({contextFactory, server, browserName, platform}) {
it.fail(browserName === 'webkit' && platform === 'win32');
const context = await contextFactory();
const page = await context.newPage();
await page.goto(server.PREFIX + '/wasm/table2.html');
expect(await page.evaluate('loadTable()')).toBe('42, 83');
});
it('WebSocket should work', async ({page, server}) => {
it('WebSocket should work', async ({contextFactory, server}) => {
const context = await contextFactory();
const page = await context.newPage();
const value = await page.evaluate(port => {
let cb;
const result = new Promise(f => cb = f);
@ -37,7 +41,7 @@ it('WebSocket should work', async ({page, server}) => {
expect(value).toBe('incoming');
});
it('should respect CSP', async ({page, server}) => {
it('should respect CSP', async ({contextFactory, server}) => {
server.setRoute('/empty.html', async (req, res) => {
res.setHeader('Content-Security-Policy', `script-src 'unsafe-inline';`);
res.end(`
@ -47,19 +51,22 @@ it('should respect CSP', async ({page, server}) => {
</script>`);
});
const context = await contextFactory();
const page = await context.newPage();
await page.goto(server.EMPTY_PAGE);
expect(await page.evaluate(() => window['testStatus'])).toBe('SUCCESS');
});
it('should play video', (test, { browserName, platform }) => {
test.fixme(browserName === 'webkit' && platform !== 'darwin');
// Doesnt' work on BigSur
test.fixme(browserName === 'webkit' && platform === 'darwin' && parseInt(os.release(), 10) >= 20);
}, async ({page, asset, isWebKit}) => {
it('should play video', async ({contextFactory, asset, isWebKit, browserName, platform}) => {
// TODO: the test passes on Windows locally but fails on GitHub Action bot,
// apparently due to a Media Pack issue in the Windows Server.
// Also the test is very flaky on Linux WebKit.
//
it.fixme(browserName === 'webkit' && platform !== 'darwin');
it.fixme(browserName === 'webkit' && platform === 'darwin' && parseInt(os.release(), 10) >= 20, 'Does not work on BigSur');
const context = await contextFactory();
const page = await context.newPage();
// Safari only plays mp4 so we test WebKit with an .mp4 clip.
const fileName = isWebKit ? 'video_mp4.html' : 'video.html';
const absolutePath = asset(fileName);
@ -70,9 +77,11 @@ it('should play video', (test, { browserName, platform }) => {
await page.$eval('video', v => v.pause());
});
it('should support webgl', (test, {browserName, headful}) => {
test.fixme(browserName === 'firefox' && !headful);
}, async ({page}) => {
it('should support webgl', async ({contextFactory, browserName, headful}) => {
it.fixme(browserName === 'firefox' && !headful);
const context = await contextFactory();
const page = await context.newPage();
const hasWebGL = await page.evaluate(() => {
const canvas = document.createElement('canvas');
return !!canvas.getContext('webgl');
@ -80,11 +89,13 @@ it('should support webgl', (test, {browserName, headful}) => {
expect(hasWebGL).toBe(true);
});
it('should support webgl 2', (test, {browserName, headful}) => {
test.skip(browserName === 'webkit', 'WebKit doesn\'t have webgl2 enabled yet upstream.');
test.fixme(browserName === 'firefox' && !headful);
test.fixme(browserName === 'chromium' && headful, 'chromium doesn\'t like webgl2 when running under xvfb');
}, async ({page}) => {
it('should support webgl 2', async ({contextFactory, browserName, headful}) => {
it.skip(browserName === 'webkit', 'WebKit doesn\'t have webgl2 enabled yet upstream.');
it.fixme(browserName === 'firefox' && !headful);
it.fixme(browserName === 'chromium' && headful, 'chromium doesn\'t like webgl2 when running under xvfb');
const context = await contextFactory();
const page = await context.newPage();
const hasWebGL2 = await page.evaluate(() => {
const canvas = document.createElement('canvas');
return !!canvas.getContext('webgl2');

Просмотреть файл

@ -16,14 +16,10 @@
*/
import domain from 'domain';
import { folio } from './fixtures';
const { it, expect } = folio;
import { test as it, expect } from './config/playwrightTest';
it('should work', async ({browser}) => {
expect(!!browser['_connection']).toBeTruthy();
});
it('should scope context handles', async ({browser, server}) => {
it('should scope context handles', async ({browserType, browserOptions, server}) => {
const browser = await browserType.launch(browserOptions);
const GOLDEN_PRECONDITION = {
_guid: '',
objects: [
@ -68,11 +64,13 @@ it('should scope context handles', async ({browser, server}) => {
await context.close();
await expectScopeState(browser, GOLDEN_PRECONDITION);
await browser.close();
});
it('should scope CDPSession handles', (test, { browserName }) => {
test.skip(browserName !== 'chromium');
}, async ({browserType, browser}) => {
it('should scope CDPSession handles', async ({browserType, browserOptions, browserName}) => {
it.skip(browserName !== 'chromium');
const browser = await browserType.launch(browserOptions);
const GOLDEN_PRECONDITION = {
_guid: '',
objects: [
@ -109,6 +107,8 @@ it('should scope CDPSession handles', (test, { browserName }) => {
await session.detach();
await expectScopeState(browserType, GOLDEN_PRECONDITION);
await browser.close();
});
it('should scope browser handles', async ({browserType, browserOptions}) => {
@ -117,10 +117,7 @@ it('should scope browser handles', async ({browserType, browserOptions}) => {
objects: [
{ _guid: 'Android', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [] },
]
},
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'Electron', objects: [] },
{ _guid: 'Playwright', objects: [] },
@ -138,7 +135,6 @@ it('should scope browser handles', async ({browserType, browserOptions}) => {
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [] },
{
_guid: 'Browser', objects: [
{ _guid: 'BrowserContext', objects: [] }

Просмотреть файл

@ -18,7 +18,7 @@ import { newTestType } from '../folio/out';
import type { AndroidDevice } from '../../index';
import type { CommonTestArgs } from './pageTest';
import type { ServerTestArgs } from './serverTest';
export { expect } from 'folio';
export { expect } from '../folio/out';
export type AndroidTestArgs = CommonTestArgs & {
androidDevice: AndroidDevice;

Просмотреть файл

@ -187,8 +187,6 @@ export class PlaywrightEnv implements Env<PlaywrightTestArgs> {
}
async afterEach(testInfo: TestInfo) {
await removeFolders(this._userDataDirs);
this._userDataDirs = [];
if (this._persistentContext) {
await this._persistentContext.close();
this._persistentContext = undefined;
@ -197,6 +195,8 @@ export class PlaywrightEnv implements Env<PlaywrightTestArgs> {
await this._remoteServer.close();
this._remoteServer = undefined;
}
await removeFolders(this._userDataDirs);
this._userDataDirs = [];
}
async afterAll(workerInfo: WorkerInfo) {
@ -204,7 +204,7 @@ export class PlaywrightEnv implements Env<PlaywrightTestArgs> {
const { coverage, uninstall } = this._coverage!;
uninstall();
const coveragePath = path.join(__dirname, '..', '..', 'test', 'coverage-report', workerInfo.workerIndex + '.json');
const coverageJSON = [...coverage.keys()].filter(key => coverage.get(key));
const coverageJSON = Array.from(coverage.keys()).filter(key => coverage.get(key));
await fs.promises.mkdir(path.dirname(coveragePath), { recursive: true });
await fs.promises.writeFile(coveragePath, JSON.stringify(coverageJSON, undefined, 2), 'utf8');
}

Просмотреть файл

@ -15,9 +15,10 @@
*/
import { newTestType } from '../folio/out';
import type { Browser, BrowserContextOptions, BrowserContext } from '../../index';
import type { Browser, BrowserContextOptions, BrowserContext, Page } from '../../index';
import type { PlaywrightTestArgs } from './playwrightTest';
export { expect } from 'folio';
import type { ServerTestArgs } from './serverTest';
export { expect } from '../folio/out';
export type BrowserTestArgs = PlaywrightTestArgs & {
browser: Browser;
@ -25,4 +26,12 @@ export type BrowserTestArgs = PlaywrightTestArgs & {
contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
};
export const test = newTestType<BrowserTestArgs>();
export const test = newTestType<BrowserTestArgs & ServerTestArgs>();
export const proxyTest = newTestType<BrowserTestArgs & ServerTestArgs>();
// Context test guarantees an isolated context.
export type ContextTestArgs = BrowserTestArgs & {
context: BrowserContext;
page: Page;
};
export const contextTest = newTestType<ContextTestArgs & ServerTestArgs>();

Просмотреть файл

@ -22,7 +22,7 @@ import * as http from 'http';
import * as path from 'path';
import type { Source } from '../../src/server/supplements/recorder/recorderTypes';
import { ChildProcess, spawn } from 'child_process';
export { expect } from 'folio';
export { expect } from '../folio/out';
interface CLIHTTPServer {
setHandler: (handler: http.RequestListener) => void

Просмотреть файл

@ -17,7 +17,7 @@
import { setConfig, Config } from '../folio/out';
import * as path from 'path';
import { test as playwrightTest, slowTest as playwrightSlowTest } from './playwrightTest';
import { test as browserTest } from './browserTest';
import { test as browserTest, contextTest, proxyTest } from './browserTest';
import { test as pageTest } from './pageTest';
import { test as electronTest } from './electronTest';
import { test as cliTest } from './cliTest';
@ -64,7 +64,11 @@ for (const browserName of browsers) {
playwrightTest.runWith(browserName, serverEnv, new PlaywrightEnv(browserName, options), {});
playwrightSlowTest.runWith(browserName, serverEnv, new PlaywrightEnv(browserName, options), { timeout: config.timeout * 3 });
browserTest.runWith(browserName, serverEnv, new BrowserEnv(browserName, options), {});
// TODO: perhaps export proxyTest from the test file?
proxyTest.runWith(browserName, serverEnv, new BrowserEnv(browserName, { ...options, proxy: { server: 'per-context' } }), {});
pageTest.runWith(browserName, serverEnv, new PageEnv(browserName, options), {});
// TODO: get rid of contextTest if there isn't too many of them.
contextTest.runWith(browserName, serverEnv, new PageEnv(browserName, options), {});
cliTest.runWith(browserName, serverEnv, new CLIEnv(browserName, options), {});
if (browserName === 'chromium')
electronTest.runWith(browserName, serverEnv, new ElectronEnv({ mode }));

Просмотреть файл

@ -18,7 +18,7 @@ import { newTestType } from '../folio/out';
import { ElectronApplication, Page } from '../../index';
import type { CommonTestArgs } from './pageTest';
import type { ServerTestArgs } from './serverTest';
export { expect } from 'folio';
export { expect } from '../folio/out';
export type ElectronTestArgs = CommonTestArgs & {
electronApp: ElectronApplication;

Просмотреть файл

@ -17,7 +17,7 @@
import { newTestType } from '../folio/out';
import type { Page } from '../../index';
import type { ServerTestArgs } from './serverTest';
export { expect } from 'folio';
export { expect } from '../folio/out';
export type CommonTestArgs = {
mode: 'default' | 'driver' | 'service';
@ -37,6 +37,7 @@ export type CommonTestArgs = {
isLinux: boolean;
};
// Page test does not guarantee an isolated context, just a new page (because Android).
export type PageTestArgs = CommonTestArgs & {
page: Page;
};

Просмотреть файл

@ -19,7 +19,7 @@ import type { Browser, BrowserType, LaunchOptions, BrowserContext, Page } from '
import { CommonTestArgs } from './pageTest';
import type { ServerTestArgs } from './serverTest';
import { RemoteServer, RemoteServerOptions } from './remoteServer';
export { expect } from 'folio';
export { expect } from '../folio/out';
export type PlaywrightTestArgs = CommonTestArgs & {
browserType: BrowserType<Browser>;

Просмотреть файл

@ -14,15 +14,17 @@
* limitations under the License.
*/
import type { WorkerInfo, TestInfo } from '../folio/out';
import type { WorkerInfo, TestInfo, Env } from '../folio/out';
import { TestServer } from '../../utils/testserver';
import * as path from 'path';
import socks from 'socksv5';
import { ServerTestArgs } from './serverTest';
export class ServerEnv {
export class ServerEnv implements Env<ServerTestArgs> {
private _server: TestServer;
private _httpsServer: TestServer;
private _socksServer: any;
private _socksPort: number;
async beforeAll(workerInfo: WorkerInfo) {
const assetsPath = path.join(__dirname, '..', '..', 'test', 'assets');
@ -52,8 +54,8 @@ export class ServerEnv {
].join('\r\n'));
}
});
const socksPort = 9107 + workerInfo.workerIndex * 2;
this._socksServer.listen(socksPort, 'localhost');
this._socksPort = 9107 + workerInfo.workerIndex * 2;
this._socksServer.listen(this._socksPort, 'localhost');
this._socksServer.useAuth(socks.auth.None());
}
@ -61,9 +63,10 @@ export class ServerEnv {
this._server.reset();
this._httpsServer.reset();
return {
asset: (p: string) => path.join(__dirname, '..', 'assets', p),
asset: (p: string) => path.join(__dirname, '..', '..', 'test', 'assets', p),
server: this._server,
httpsServer: this._httpsServer,
socksPort: this._socksPort,
};
}

Просмотреть файл

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/playwrightTest';
import { parseCSS, serializeSelector as serialize } from '../src/server/common/cssParser';
const parse = (selector: string) => {

Просмотреть файл

@ -15,8 +15,8 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { verifyViewport } from './utils';
import { test as it, expect } from './config/playwrightTest';
import { verifyViewport } from '../test/utils';
import fs from 'fs';
it('context.cookies() should work', async ({server, launchPersistent}) => {
@ -170,9 +170,9 @@ it('should support offline option', async ({server, launchPersistent}) => {
expect(error).toBeTruthy();
});
it('should support acceptDownloads option', (test, parameters) => {
test.skip('Unskip once we support downloads in persistent context.');
}, async ({server, launchPersistent}) => {
it('should support acceptDownloads option', async ({server, launchPersistent}) => {
it.skip('Unskip once we support downloads in persistent context.');
const {page} = await launchPersistent({acceptDownloads: true});
server.setRoute('/download', (req, res) => {
res.setHeader('Content-Type', 'application/octet-stream');

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, slowTest, expect } from './config/playwrightTest';
import fs from 'fs';
it('should support hasTouch option', async ({server, launchPersistent}) => {
@ -24,10 +24,9 @@ it('should support hasTouch option', async ({server, launchPersistent}) => {
expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(true);
});
it('should work in persistent context', (test, { browserName }) => {
test.skip(browserName === 'firefox');
}, async ({server, launchPersistent}) => {
// Firefox does not support mobile.
it('should work in persistent context', async ({server, launchPersistent, browserName}) => {
it.skip(browserName === 'firefox', 'Firefox does not support mobile');
const {page} = await launchPersistent({viewport: {width: 320, height: 480}, isMobile: true});
await page.goto(server.PREFIX + '/empty.html');
expect(await page.evaluate(() => window.innerWidth)).toBe(980);
@ -83,9 +82,7 @@ it('should accept userDataDir', async ({createUserDataDir, browserType, browserO
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
});
it('should restore state from userDataDir', (test, { browserName }) => {
test.slow();
}, async ({browserType, browserOptions, server, createUserDataDir}) => {
slowTest('should restore state from userDataDir', async ({browserType, browserOptions, server, createUserDataDir}) => {
const userDataDir = await createUserDataDir();
const browserContext = await browserType.launchPersistentContext(userDataDir, browserOptions);
const page = await browserContext.newPage();
@ -107,10 +104,9 @@ it('should restore state from userDataDir', (test, { browserName }) => {
await browserContext3.close();
});
it('should restore cookies from userDataDir', (test, { platform, browserChannel }) => {
test.slow();
test.fixme(platform === 'win32' && browserChannel === 'chrome');
}, async ({browserType, browserOptions, server, createUserDataDir}) => {
slowTest('should restore cookies from userDataDir', async ({browserType, browserOptions, server, createUserDataDir, platform, browserChannel}) => {
slowTest.fixme(platform === 'win32' && browserChannel === 'chrome');
const userDataDir = await createUserDataDir();
const browserContext = await browserType.launchPersistentContext(userDataDir, browserOptions);
const page = await browserContext.newPage();
@ -142,17 +138,17 @@ it('should have default URL when launching browser', async ({launchPersistent})
expect(urls).toEqual(['about:blank']);
});
it('should throw if page argument is passed', (test, { browserName }) => {
test.skip(browserName === 'firefox');
}, async ({browserType, browserOptions, server, createUserDataDir}) => {
it('should throw if page argument is passed', async ({browserType, browserOptions, server, createUserDataDir, browserName}) => {
it.skip(browserName === 'firefox');
const options = {...browserOptions, args: [server.EMPTY_PAGE] };
const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e);
expect(error.message).toContain('can not specify page');
});
it('should have passed URL when launching with ignoreDefaultArgs: true', (test, { mode }) => {
test.skip(mode !== 'default');
}, async ({browserType, browserOptions, server, createUserDataDir, toImpl}) => {
it('should have passed URL when launching with ignoreDefaultArgs: true', async ({browserType, browserOptions, server, createUserDataDir, toImpl, mode}) => {
it.skip(mode !== 'default');
const userDataDir = await createUserDataDir();
const args = toImpl(browserType)._defaultArgs(browserOptions, 'persistent', userDataDir, 0).filter(a => a !== 'about:blank');
const options = {
@ -169,17 +165,17 @@ it('should have passed URL when launching with ignoreDefaultArgs: true', (test,
await browserContext.close();
});
it('should handle timeout', (test, { mode }) => {
test.skip(mode !== 'default');
}, async ({browserType, browserOptions, createUserDataDir}) => {
it('should handle timeout', async ({browserType, browserOptions, createUserDataDir, mode}) => {
it.skip(mode !== 'default');
const options = { ...browserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e);
expect(error.message).toContain(`browserType.launchPersistentContext: Timeout 5000ms exceeded.`);
});
it('should handle exception', (test, { mode }) => {
test.skip(mode !== 'default');
}, async ({browserType, browserOptions, createUserDataDir}) => {
it('should handle exception', async ({browserType, browserOptions, createUserDataDir, mode}) => {
it.skip(mode !== 'default');
const e = new Error('Dummy');
const options = { ...browserOptions, __testHookBeforeCreateBrowser: () => { throw e; } };
const error = await browserType.launchPersistentContext(await createUserDataDir(), options).catch(e => e);
@ -194,9 +190,9 @@ it('should fire close event for a persistent context', async ({launchPersistent}
expect(closed).toBe(true);
});
it('coverage should work', (test, { browserName }) => {
test.skip(browserName !== 'chromium');
}, async ({server, launchPersistent}) => {
it('coverage should work', async ({server, launchPersistent, browserName}) => {
it.skip(browserName !== 'chromium');
const {page} = await launchPersistent();
await page.coverage.startJSCoverage();
await page.goto(server.PREFIX + '/jscoverage/simple.html', { waitUntil: 'load' });
@ -224,9 +220,9 @@ it('should respect selectors', async ({playwright, launchPersistent}) => {
expect(await page.innerHTML('defaultContextCSS=div')).toBe('hello');
});
it('should connect to a browser with the default page', (test, { mode }) => {
test.skip(mode !== 'default');
}, async ({browserType, browserOptions, createUserDataDir}) => {
it('should connect to a browser with the default page', async ({browserType, browserOptions, createUserDataDir, mode}) => {
it.skip(mode !== 'default');
const options = { ...browserOptions, __testHookOnConnectToBrowser: () => new Promise(f => setTimeout(f, 3000)) };
const context = await browserType.launchPersistentContext(await createUserDataDir(), options);
expect(context.pages().length).toBe(1);

Просмотреть файл

@ -14,12 +14,11 @@
* limitations under the License.
*/
import { folio } from './fixtures';
import { test as it, expect } from './config/playwrightTest';
import fs from 'fs';
const { it, expect, describe, beforeEach } = folio;
describe('downloads path', () => {
beforeEach(async ({server}) => {
it.describe('downloads path', () => {
it.beforeEach(async ({server}) => {
server.setRoute('/download', (req, res) => {
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', 'attachment; filename=file.txt');
@ -27,7 +26,7 @@ describe('downloads path', () => {
});
});
it('should keep downloadsPath folder', async ({browserType, browserOptions, testInfo, server}) => {
it('should keep downloadsPath folder', async ({browserType, browserOptions, server}, testInfo) => {
const downloadsBrowser = await browserType.launch({ ...browserOptions, downloadsPath: testInfo.outputPath('') });
const page = await downloadsBrowser.newPage();
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
@ -43,7 +42,7 @@ describe('downloads path', () => {
expect(fs.existsSync(testInfo.outputPath(''))).toBeTruthy();
});
it('should delete downloads when context closes', async ({browserType, browserOptions, server, testInfo}) => {
it('should delete downloads when context closes', async ({browserType, browserOptions, server}, testInfo) => {
const downloadsBrowser = await browserType.launch({ ...browserOptions, downloadsPath: testInfo.outputPath('') });
const page = await downloadsBrowser.newPage({ acceptDownloads: true });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
@ -58,7 +57,7 @@ describe('downloads path', () => {
await downloadsBrowser.close();
});
it('should report downloads in downloadsPath folder', async ({browserType, browserOptions, testInfo, server}) => {
it('should report downloads in downloadsPath folder', async ({browserType, browserOptions, server}, testInfo) => {
const downloadsBrowser = await browserType.launch({ ...browserOptions, downloadsPath: testInfo.outputPath('') });
const page = await downloadsBrowser.newPage({ acceptDownloads: true });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
@ -72,7 +71,7 @@ describe('downloads path', () => {
await downloadsBrowser.close();
});
it('should accept downloads in persistent context', async ({launchPersistent, testInfo, server}) => {
it('should accept downloads in persistent context', async ({launchPersistent, server}, testInfo) => {
const { context, page } = await launchPersistent({ acceptDownloads: true, downloadsPath: testInfo.outputPath('') });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
const [ download ] = await Promise.all([
@ -86,7 +85,7 @@ describe('downloads path', () => {
await context.close();
});
it('should delete downloads when persistent context closes', async ({launchPersistent, server, testInfo}) => {
it('should delete downloads when persistent context closes', async ({launchPersistent, server}, testInfo) => {
const { context, page } = await launchPersistent({ acceptDownloads: true, downloadsPath: testInfo.outputPath('') });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
const [ download ] = await Promise.all([

Просмотреть файл

@ -18,7 +18,7 @@
import { test as it, expect } from './config/pageTest';
it('should work', async ({ page, server }) => {
it.fixme(process.env.PW_ANDROID_TESTS);
it.fixme(!!process.env.PW_ANDROID_TESTS);
await page.goto(server.PREFIX + '/offscreenbuttons.html');
for (let i = 0; i < 11; ++i) {

Просмотреть файл

@ -51,3 +51,8 @@ function toMatchSnapshot(received: Buffer | string, nameOrOptions?: string | { n
}
expectLibrary.extend({ toMatchSnapshot });
// TEMPORARY HACK: two folios currently fight for their own toMatchSnapshot.
export function extendAgain() {
expectLibrary.extend({ toMatchSnapshot });
}

Просмотреть файл

@ -24,6 +24,7 @@ import { Loader } from './loader';
import { Spec, Suite, Test } from './test';
import { TestInfo, WorkerInfo } from './types';
import { RunListDescription } from './spec';
import { extendAgain } from './expect';
export class WorkerRunner extends EventEmitter {
private _params: WorkerInitParams;
@ -128,6 +129,7 @@ export class WorkerRunner extends EventEmitter {
return;
this._loader.loadTestFile(this._file);
extendAgain();
const fileSuite = this._runList.fileSuites.get(this._file);
if (fileSuite) {
fileSuite._renumber();

Просмотреть файл

@ -15,9 +15,11 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should work', async ({page, server, context}) => {
it('should work', async ({server, contextFactory}) => {
const context = await contextFactory();
const page = await context.newPage();
await context.grantPermissions(['geolocation']);
await page.goto(server.EMPTY_PAGE);
await context.setGeolocation({longitude: 10, latitude: 10});
@ -30,7 +32,8 @@ it('should work', async ({page, server, context}) => {
});
});
it('should throw when invalid longitude', async ({context}) => {
it('should throw when invalid longitude', async ({contextFactory}) => {
const context = await contextFactory();
let error = null;
try {
await context.setGeolocation({longitude: 200, latitude: 10});
@ -40,7 +43,9 @@ it('should throw when invalid longitude', async ({context}) => {
expect(error.message).toContain('geolocation.longitude: precondition -180 <= LONGITUDE <= 180 failed.');
});
it('should isolate contexts', async ({page, server, context, browser}) => {
it('should isolate contexts', async ({server, contextFactory, browser}) => {
const context = await contextFactory();
const page = await context.newPage();
await context.grantPermissions(['geolocation']);
await context.setGeolocation({longitude: 10, latitude: 10});
await page.goto(server.EMPTY_PAGE);
@ -71,7 +76,8 @@ it('should isolate contexts', async ({page, server, context, browser}) => {
await context2.close();
});
it('should throw with missing latitude', async ({context}) => {
it('should throw with missing latitude', async ({contextFactory}) => {
const context = await contextFactory();
let error = null;
try {
// @ts-expect-error setGeolocation must have latitude
@ -119,7 +125,9 @@ it('should use context options', async ({browser, server}) => {
await context.close();
});
it('watchPosition should be notified', async ({page, server, context}) => {
it('watchPosition should be notified', async ({server, contextFactory}) => {
const context = await contextFactory();
const page = await context.newPage();
await context.grantPermissions(['geolocation']);
await page.goto(server.EMPTY_PAGE);
const messages = [];
@ -145,7 +153,9 @@ it('watchPosition should be notified', async ({page, server, context}) => {
expect(allMessages).toContain('lat=40 lng=50');
});
it('should use context options for popup', async ({page, context, server}) => {
it('should use context options for popup', async ({contextFactory, server}) => {
const context = await contextFactory();
const page = await context.newPage();
await context.grantPermissions(['geolocation']);
await context.setGeolocation({ longitude: 10, latitude: 10 });
const [popup] = await Promise.all([

Просмотреть файл

@ -15,13 +15,11 @@
* limitations under the License.
*/
import { folio } from './fixtures';
import { test as it, expect } from './config/browserTest';
import fs from 'fs';
import type { BrowserContext, BrowserContextOptions } from '../index';
import { TestInfo } from 'folio';
const { expect, it } = folio;
async function pageWithHar(contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>, testInfo: TestInfo) {
async function pageWithHar(contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>, testInfo: any) {
const harPath = testInfo.outputPath('test.har');
const context = await contextFactory({ recordHar: { path: harPath }, ignoreHTTPSErrors: true });
const page = await context.newPage();
@ -39,7 +37,7 @@ it('should throw without path', async ({ browser }) => {
expect(error.message).toContain('recordHar.path: expected string, got undefined');
});
it('should have version and creator', async ({ contextFactory, testInfo, server }) => {
it('should have version and creator', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE);
const log = await getLog();
@ -48,7 +46,7 @@ it('should have version and creator', async ({ contextFactory, testInfo, server
expect(log.creator.version).toBe(require('../package.json')['version']);
});
it('should have browser', async ({ browserName, browser, contextFactory, testInfo, server }) => {
it('should have browser', async ({ browserName, browser, contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE);
const log = await getLog();
@ -56,7 +54,7 @@ it('should have browser', async ({ browserName, browser, contextFactory, testInf
expect(log.browser.version).toBe(browser.version());
});
it('should have pages', async ({ contextFactory, testInfo, server }) => {
it('should have pages', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto('data:text/html,<title>Hello</title>');
// For data: load comes before domcontentloaded...
@ -71,7 +69,7 @@ it('should have pages', async ({ contextFactory, testInfo, server }) => {
expect(pageEntry.pageTimings.onLoad).toBeGreaterThan(0);
});
it('should have pages in persistent context', async ({ launchPersistent, testInfo }) => {
it('should have pages in persistent context', async ({ launchPersistent }, testInfo) => {
const harPath = testInfo.outputPath('test.har');
const { context, page } = await launchPersistent({ recordHar: { path: harPath } });
await page.goto('data:text/html,<title>Hello</title>');
@ -85,7 +83,7 @@ it('should have pages in persistent context', async ({ launchPersistent, testInf
expect(pageEntry.title).toBe('Hello');
});
it('should include request', async ({ contextFactory, testInfo, server }) => {
it('should include request', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE);
const log = await getLog();
@ -99,7 +97,7 @@ it('should include request', async ({ contextFactory, testInfo, server }) => {
expect(entry.request.headers.find(h => h.name.toLowerCase() === 'user-agent')).toBeTruthy();
});
it('should include response', async ({ contextFactory, testInfo, server }) => {
it('should include response', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE);
const log = await getLog();
@ -111,7 +109,7 @@ it('should include response', async ({ contextFactory, testInfo, server }) => {
expect(entry.response.headers.find(h => h.name.toLowerCase() === 'content-type').value).toContain('text/html');
});
it('should include redirectURL', async ({ contextFactory, testInfo, server }) => {
it('should include redirectURL', async ({ contextFactory, server }, testInfo) => {
server.setRedirect('/foo.html', '/empty.html');
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/foo.html');
@ -122,14 +120,14 @@ it('should include redirectURL', async ({ contextFactory, testInfo, server }) =>
expect(entry.response.redirectURL).toBe(server.EMPTY_PAGE);
});
it('should include query params', async ({ contextFactory, testInfo, server }) => {
it('should include query params', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/har.html?name=value');
const log = await getLog();
expect(log.entries[0].request.queryString).toEqual([{ name: 'name', value: 'value' }]);
});
it('should include postData', async ({ contextFactory, testInfo, server }) => {
it('should include postData', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => fetch('./post', { method: 'POST', body: 'Hello' }));
@ -141,7 +139,7 @@ it('should include postData', async ({ contextFactory, testInfo, server }) => {
});
});
it('should include binary postData', async ({ contextFactory, testInfo, server }) => {
it('should include binary postData', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE);
await page.evaluate(async () => {
@ -155,7 +153,7 @@ it('should include binary postData', async ({ contextFactory, testInfo, server }
});
});
it('should include form params', async ({ contextFactory, testInfo, server }) => {
it('should include form params', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE);
await page.setContent(`<form method='POST' action='/post'><input type='text' name='foo' value='bar'><input type='number' name='baz' value='123'><input type='submit'></form>`);
@ -171,7 +169,7 @@ it('should include form params', async ({ contextFactory, testInfo, server }) =>
});
});
it('should include cookies', async ({ contextFactory, testInfo, server }) => {
it('should include cookies', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
const context = page.context();
await context.addCookies([
@ -190,9 +188,9 @@ it('should include cookies', async ({ contextFactory, testInfo, server }) => {
]);
});
it('should include set-cookies', (test, { browserName, platform }) => {
test.fail(browserName === 'webkit' && platform === 'darwin', 'Does not work yet');
}, async ({ contextFactory, testInfo, server }) => {
it('should include set-cookies', async ({ contextFactory, server, browserName, platform }, testInfo) => {
it.fail(browserName === 'webkit' && platform === 'darwin', 'Does not work yet');
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', [
@ -210,7 +208,7 @@ it('should include set-cookies', (test, { browserName, platform }) => {
expect(new Date(cookies[2].expires).valueOf()).toBeGreaterThan(Date.now());
});
it('should include set-cookies with comma', async ({ contextFactory, testInfo, server }) => {
it('should include set-cookies with comma', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', [
@ -224,7 +222,7 @@ it('should include set-cookies with comma', async ({ contextFactory, testInfo, s
expect(cookies[0]).toEqual({ name: 'name1', value: 'val,ue1' });
});
it('should include secure set-cookies', async ({ contextFactory, testInfo, httpsServer }) => {
it('should include secure set-cookies', async ({ contextFactory, httpsServer }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
httpsServer.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', [
@ -238,7 +236,7 @@ it('should include secure set-cookies', async ({ contextFactory, testInfo, https
expect(cookies[0]).toEqual({ name: 'name1', value: 'value1', secure: true });
});
it('should include content', async ({ contextFactory, testInfo, server }) => {
it('should include content', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/har.html');
const log = await getLog();

Просмотреть файл

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { it, expect, folio } from './fixtures';
import { test as it, slowTest, expect } from './config/playwrightTest';
it('should have default url when launching browser', async ({browserType, browserOptions, createUserDataDir}) => {
const browserContext = await browserType.launchPersistentContext(await createUserDataDir(), {...browserOptions, headless: false });
@ -23,9 +23,7 @@ it('should have default url when launching browser', async ({browserType, browse
await browserContext.close();
});
it('headless should be able to read cookies written by headful', (test, { browserName, platform }) => {
test.slow();
}, async ({browserType, browserOptions, server, createUserDataDir}) => {
slowTest('headless should be able to read cookies written by headful', async ({browserType, browserOptions, server, createUserDataDir}) => {
// see https://github.com/microsoft/playwright/issues/717
const userDataDir = await createUserDataDir();
// Write a cookie in headful chrome
@ -43,9 +41,7 @@ it('headless should be able to read cookies written by headful', (test, { browse
expect(cookie).toBe('foo=true');
});
it('should close browser with beforeunload page', (test, parameters) => {
test.slow();
}, async ({browserType, browserOptions, server, createUserDataDir}) => {
slowTest('should close browser with beforeunload page', async ({browserType, browserOptions, server, createUserDataDir}) => {
const browserContext = await browserType.launchPersistentContext(await createUserDataDir(), {...browserOptions, headless: false});
const page = await browserContext.newPage();
await page.goto(server.PREFIX + '/beforeunload.html');
@ -127,9 +123,9 @@ it('should(not) block third party cookies', async ({browserType, browserOptions,
await browser.close();
});
it('should not override viewport size when passed null', (test, { browserName }) => {
test.fixme(browserName === 'webkit');
}, async function({browserType, browserOptions, server}) {
it('should not override viewport size when passed null', async function({browserType, browserOptions, server, browserName}) {
it.fixme(browserName === 'webkit');
// Our WebKit embedder does not respect window features.
const browser = await browserType.launch({...browserOptions, headless: false });
const context = await browser.newContext({ viewport: null });
@ -167,16 +163,15 @@ it('Page.bringToFront should work', async ({browserType, browserOptions}) => {
await browser.close();
});
const fixtures = folio.extend();
fixtures.testParametersPathSegment.override(async ({ browserName, platform }, run) => {
await run(browserName + '-' + platform);
});
fixtures.build().it('focused input should produce the same screenshot', (test, { browserName, platform }) => {
test.fail(browserName === 'firefox' && platform === 'darwin', 'headless has thinner outline');
test.fail(browserName === 'firefox' && platform === 'linux', 'headless has no outline');
test.skip(browserName === 'webkit' && platform === 'linux', 'gtk vs wpe');
test.skip(process.env.CRPATH);
}, async ({browserType, browserOptions}) => {
it('focused input should produce the same screenshot', async ({browserType, browserOptions, browserName, platform, browserChannel}, testInfo) => {
it.fail(browserName === 'firefox' && platform === 'darwin', 'headless has thinner outline');
it.fail(browserName === 'firefox' && platform === 'linux', 'headless has no outline');
it.skip(browserName === 'webkit' && platform === 'linux', 'gtk vs wpe');
it.skip(!!process.env.CRPATH);
it.skip(!!browserChannel, 'Uncomment on roll');
testInfo.snapshotPathSegment = browserName + '-' + platform;
const headful = await browserType.launch({...browserOptions, headless: false });
const headfulPage = await headful.newPage();
await headfulPage.setContent('<input>');

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should work', async ({browser, httpsServer}) => {
let error = null;

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/playwrightTest';
it('should require top-level Errors', async ({}) => {
const Errors = require('../lib/utils/errors.js');
@ -28,9 +28,9 @@ it('should require top-level DeviceDescriptors', async ({playwright}) => {
expect(Devices['iPhone 6']).toEqual(playwright.devices['iPhone 6']);
});
it('should kill browser process on timeout after close', (test, { mode }) => {
test.skip(mode !== 'default', 'Test passes server hooks via options');
}, async ({browserType, browserOptions}) => {
it('should kill browser process on timeout after close', async ({browserType, browserOptions, mode}) => {
it.skip(mode !== 'default', 'Test passes server hooks via options');
const launchOptions = { ...browserOptions };
let stalled = false;
(launchOptions as any).__testHookGracefullyClose = () => {

Просмотреть файл

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/playwrightTest';
it('should log', async ({browserType, browserOptions}) => {
const log = [];

Просмотреть файл

@ -99,7 +99,7 @@ it('should throw when added with content to the CSP page', async ({page, server}
});
it('should throw when added with URL to the CSP page', async ({page, server}) => {
it.skip(process.env.PW_ANDROID_TESTS);
it.skip(!!process.env.PW_ANDROID_TESTS);
await page.goto(server.PREFIX + '/csp.html');
let error = null;

Просмотреть файл

@ -77,7 +77,7 @@ it('should throw when added with content to the CSP page', async ({page, server}
});
it('should throw when added with URL to the CSP page', async ({page, server}) => {
it.skip(process.env.PW_ANDROID_TESTS);
it.skip(!!process.env.PW_ANDROID_TESTS);
await page.goto(server.PREFIX + '/csp.html');
let error = null;

Просмотреть файл

@ -18,7 +18,7 @@ import { test as it } from './config/pageTest';
it('should not hit scroll bar', async ({page, server, isWebKit, platform}) => {
it.fixme(isWebKit && platform === 'darwin');
it.skip(process.env.PW_ANDROID_TESTS);
it.skip(!!process.env.PW_ANDROID_TESTS);
await page.setContent(`
<style>

Просмотреть файл

@ -42,7 +42,7 @@ it('should fire for fetches', async ({page, server}) => {
});
it('should report requests and responses handled by service worker', async ({page, server}) => {
it.fixme(process.env.PW_ANDROID_TESTS);
it.fixme(!!process.env.PW_ANDROID_TESTS);
await page.goto(server.PREFIX + '/serviceworkers/fetchdummy/sw.html');
await page.evaluate(() => window['activationPromise']);

Просмотреть файл

@ -124,7 +124,7 @@ it('should contain referer header', async ({page, server}) => {
});
it('should properly return navigation response when URL has cookies', async ({page, server}) => {
it.skip(process.env.PW_ANDROID_TESTS);
it.skip(!!process.env.PW_ANDROID_TESTS);
// Setup cookie.
await page.goto(server.EMPTY_PAGE);

Просмотреть файл

@ -14,14 +14,14 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
import fs from 'fs';
it('should be able to save file', async ({contextFactory, headful, browserName}, testInfo) => {
it.skip(headful || browserName !== 'chromium', 'Printing to pdf is currently only supported in headless chromium.');
it('should be able to save file', (test, { browserName, headful }) => {
test.skip(headful || browserName !== 'chromium', 'Printing to pdf is currently only supported in headless chromium.');
}, async ({page, testInfo}) => {
const context = await contextFactory();
const page = await context.newPage();
const outputFile = testInfo.outputPath('output.pdf');
await page.pdf({path: outputFile});
expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0);

Просмотреть файл

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/browserTest';
it('should inherit user agent from browser context', async function({browser, server}) {
const context = await browser.newContext({

Просмотреть файл

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { it, expect } from './fixtures';
import { test as it, expect } from './config/playwrightTest';
import net from 'net';
it('should throw for bad server value', async ({browserType, browserOptions}) => {
@ -96,9 +96,9 @@ it('should authenticate', async ({browserType, browserOptions, server}) => {
await browser.close();
});
it('should exclude patterns', (test, { browserName, headful }) => {
test.fixme(browserName === 'chromium' && headful, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.');
}, async ({browserType, browserOptions, server}) => {
it('should exclude patterns', async ({browserType, browserOptions, server, browserName, headful}) => {
it.fixme(browserName === 'chromium' && headful, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.');
server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>');
});
@ -174,9 +174,9 @@ it('does launch without a port', async ({ browserType, browserOptions }) => {
await browser.close();
});
it('should use proxy', test => {
test.fixme('Non-emulated user agent is used in proxy CONNECT');
}, async ({ browserType, browserOptions }) => {
it('should use proxy', async ({ browserType, browserOptions }) => {
it.fixme('Non-emulated user agent is used in proxy CONNECT');
let requestText = '';
// This is our proxy server
const server = net.createServer(socket => {

Просмотреть файл

@ -14,23 +14,19 @@
* limitations under the License.
*/
import { folio } from './fixtures';
import type { Page, Frame } from '..';
const fixtures = folio.extend();
fixtures.context.override(async ({ context }, run) => {
await (context as any)._enableRecorder({ language: 'javascript' });
await run(context);
});
const { describe, it, expect } = fixtures.build();
import { contextTest as it, expect } from './config/browserTest';
import type { Page, Frame } from '../index';
async function generate(pageOrFrame: Page | Frame, target: string): Promise<string> {
return pageOrFrame.$eval(target, e => (window as any).playwright.selector(e));
}
describe('selector generator', (suite, { mode }) => {
suite.skip(mode !== 'default');
}, () => {
it.describe('selector generator', () => {
it.beforeEach(async ({ mode, context }) => {
await (context as any)._enableRecorder({ language: 'javascript' });
it.skip(mode !== 'default');
});
it('should prefer button over inner span', async ({ page }) => {
await page.setContent(`<button id=clickme><span></span></button>`);
expect(await generate(page, 'button')).toBe('#clickme');
@ -201,7 +197,7 @@ describe('selector generator', (suite, { mode }) => {
expect(await generate(page, 'input[mark="1"]')).toBe(':nth-match(input, 2)');
});
describe('should prioritise input element attributes correctly', () => {
it.describe('should prioritise input element attributes correctly', () => {
it('name', async ({ page }) => {
await page.setContent(`<input name="foobar" type="text"/>`);
expect(await generate(page, 'input')).toBe('input[name="foobar"]');

13
tests/tsconfig.json Normal file
Просмотреть файл

@ -0,0 +1,13 @@
{
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"noEmit": true,
"moduleResolution": "node",
"target": "ESNext",
"strictNullChecks": false,
"strictBindCallApply": true,
"allowSyntheticDefaultImports": true,
},
"include": ["**/*.spec.js", "**/*.ts"]
}