test: remove unnecessary folio.extend calls before test migration (#6030)

This commit is contained in:
Dmitry Gozman 2021-04-01 13:18:04 -07:00 committed by GitHub
parent 8f71f5971b
commit 2290d8f81f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 225 additions and 295 deletions

View file

@ -18,18 +18,7 @@
import domain from 'domain'; import domain from 'domain';
import { folio } from './fixtures'; import { folio } from './fixtures';
import type { ChromiumBrowser } from '..'; import type { ChromiumBrowser } from '..';
const { it, expect } = folio;
const fixtures = folio.extend<{}, { domain: any }>();
fixtures.domain.init(async ({ }, run) => {
const local = domain.create();
local.run(() => { });
let err;
local.on('error', e => err = e);
await run(null);
if (err)
throw err;
}, { scope: 'worker' });
const { it, expect } = fixtures.build();
it('should work', async ({browser}) => { it('should work', async ({browser}) => {
expect(!!browser['_connection']).toBeTruthy(); expect(!!browser['_connection']).toBeTruthy();
@ -168,7 +157,12 @@ it('should scope browser handles', async ({browserType, browserOptions}) => {
await expectScopeState(browserType, GOLDEN_PRECONDITION); await expectScopeState(browserType, GOLDEN_PRECONDITION);
}); });
it('should work with the domain module', async ({ domain, browserType, browserOptions, server, isFirefox }) => { it('should work with the domain module', async ({ browserType, browserOptions, server, isFirefox }) => {
const local = domain.create();
local.run(() => { });
let err;
local.on('error', e => err = e);
const browser = await browserType.launch(browserOptions); const browser = await browserType.launch(browserOptions);
const page = await browser.newPage(); const page = await browser.newPage();
@ -189,6 +183,9 @@ it('should work with the domain module', async ({ domain, browserType, browserOp
expect(message).toContain(': 400'); expect(message).toContain(': 400');
await browser.close(); await browser.close();
if (err)
throw err;
}); });
async function expectScopeState(object, golden) { async function expectScopeState(object, golden) {

View file

@ -18,20 +18,13 @@ import { folio } from '../fixtures';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import type { ChromiumBrowser } from '../..'; import type { ChromiumBrowser } from '../..';
const { it, expect, describe } = folio;
type TestState = {
outputTraceFile: string;
};
const fixtures = folio.extend<TestState>();
fixtures.outputTraceFile.init(async ({ testInfo }, run) => {
await run(testInfo.outputPath(path.join(`trace.json`)));
});
const { it, expect, describe } = fixtures.build();
describe('tracing', (suite, { browserName }) => { describe('tracing', (suite, { browserName }) => {
suite.skip(browserName !== 'chromium'); suite.skip(browserName !== 'chromium');
}, () => { }, () => {
it('should output a trace', async ({browser, page, server, outputTraceFile}) => { it('should output a trace', async ({browser, page, server, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile}); await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile});
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
await (browser as ChromiumBrowser).stopTracing(); await (browser as ChromiumBrowser).stopTracing();
@ -46,7 +39,8 @@ describe('tracing', (suite, { browserName }) => {
expect(fs.existsSync(filePath)).toBe(true); expect(fs.existsSync(filePath)).toBe(true);
}); });
it('should run with custom categories if provided', async ({browser, page, outputTraceFile}) => { it('should run with custom categories if provided', async ({browser, page, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {path: outputTraceFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']}); await (browser as ChromiumBrowser).startTracing(page, {path: outputTraceFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']});
await (browser as ChromiumBrowser).stopTracing(); await (browser as ChromiumBrowser).stopTracing();
@ -54,7 +48,8 @@ describe('tracing', (suite, { browserName }) => {
expect(traceJson.metadata['trace-config']).toContain('disabled-by-default-v8.cpu_profiler.hires'); expect(traceJson.metadata['trace-config']).toContain('disabled-by-default-v8.cpu_profiler.hires');
}); });
it('should throw if tracing on two pages', async ({browser, page, outputTraceFile}) => { it('should throw if tracing on two pages', async ({browser, page, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {path: outputTraceFile}); await (browser as ChromiumBrowser).startTracing(page, {path: outputTraceFile});
const newPage = await browser.newPage(); const newPage = await browser.newPage();
let error = null; let error = null;
@ -64,7 +59,8 @@ describe('tracing', (suite, { browserName }) => {
await (browser as ChromiumBrowser).stopTracing(); await (browser as ChromiumBrowser).stopTracing();
}); });
it('should return a buffer', async ({browser, page, server, outputTraceFile}) => { it('should return a buffer', async ({browser, page, server, testInfo}) => {
const outputTraceFile = testInfo.outputPath(path.join(`trace.json`));
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile}); await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: outputTraceFile});
await page.goto(server.PREFIX + '/grid.html'); await page.goto(server.PREFIX + '/grid.html');
const trace = await (browser as ChromiumBrowser).stopTracing(); const trace = await (browser as ChromiumBrowser).stopTracing();

View file

@ -17,10 +17,11 @@
import * as http from 'http'; import * as http from 'http';
import path from 'path'; import path from 'path';
import { ChildProcess, spawn } from 'child_process'; import { ChildProcess, spawn } from 'child_process';
import { folio as baseFolio } from '../recorder.fixtures'; import { folio as baseFolio } from '../fixtures';
import type { BrowserType, Browser, Page } from '../..'; import type { BrowserType, Browser, Page } from '../..';
export { config } from 'folio'; export { config } from 'folio';
import type { Source } from '../../src/server/supplements/recorder/recorderTypes'; import type { Source } from '../../src/server/supplements/recorder/recorderTypes';
import { recorderPageGetter } from '../utils';
type WorkerFixtures = { type WorkerFixtures = {
browserType: BrowserType<Browser>; browserType: BrowserType<Browser>;
@ -35,9 +36,9 @@ type TestFixtures = {
export const fixtures = baseFolio.extend<TestFixtures, WorkerFixtures>(); export const fixtures = baseFolio.extend<TestFixtures, WorkerFixtures>();
fixtures.recorder.init(async ({ page, recorderPageGetter }, runTest) => { fixtures.recorder.init(async ({ page, context, toImpl }, runTest) => {
await (page.context() as any)._enableRecorder({ language: 'javascript', startRecording: true }); await (page.context() as any)._enableRecorder({ language: 'javascript', startRecording: true });
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await runTest(new Recorder(page, recorderPage)); await runTest(new Recorder(page, recorderPage));
}); });

View file

@ -15,109 +15,87 @@
*/ */
import { folio } from './fixtures'; import { folio } from './fixtures';
import fs from 'fs'; import fs from 'fs';
import type { Browser, BrowserContext } from '..'; const { it, expect, describe, beforeEach } = folio;
type TestState = { describe('downloads path', () => {
downloadsBrowser: Browser; beforeEach(async ({server}) => {
persistentDownloadsContext: BrowserContext; server.setRoute('/download', (req, res) => {
}; res.setHeader('Content-Type', 'application/octet-stream');
const fixtures = folio.extend<TestState>(); res.setHeader('Content-Disposition', 'attachment; filename=file.txt');
res.end(`Hello world`);
fixtures.downloadsBrowser.init(async ({ server, browserType, browserOptions, testInfo }, test) => { });
server.setRoute('/download', (req, res) => {
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', 'attachment; filename=file.txt');
res.end(`Hello world`);
}); });
const browser = await browserType.launch({
...browserOptions, it('should keep downloadsPath folder', async ({browserType, browserOptions, testInfo, server}) => {
downloadsPath: testInfo.outputPath(''), const downloadsBrowser = await browserType.launch({ ...browserOptions, downloadsPath: testInfo.outputPath('') });
const page = await downloadsBrowser.newPage();
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
const [ download ] = await Promise.all([
page.waitForEvent('download'),
page.click('a')
]);
expect(download.url()).toBe(`${server.PREFIX}/download`);
expect(download.suggestedFilename()).toBe(`file.txt`);
await download.path().catch(e => void 0);
await page.close();
await downloadsBrowser.close();
expect(fs.existsSync(testInfo.outputPath(''))).toBeTruthy();
}); });
await test(browser);
await browser.close();
});
fixtures.persistentDownloadsContext.init(async ({ server, launchPersistent, testInfo, browserChannel }, test) => { it('should delete downloads when context closes', async ({browserType, browserOptions, server, testInfo}) => {
server.setRoute('/download', (req, res) => { const downloadsBrowser = await browserType.launch({ ...browserOptions, downloadsPath: testInfo.outputPath('') });
res.setHeader('Content-Type', 'application/octet-stream'); const page = await downloadsBrowser.newPage({ acceptDownloads: true });
res.setHeader('Content-Disposition', 'attachment; filename=file.txt'); await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
res.end(`Hello world`); const [ download ] = await Promise.all([
page.waitForEvent('download'),
page.click('a')
]);
const path = await download.path();
expect(fs.existsSync(path)).toBeTruthy();
await page.close();
expect(fs.existsSync(path)).toBeFalsy();
await downloadsBrowser.close();
}); });
const { context, page } = await launchPersistent(
{
downloadsPath: testInfo.outputPath(''),
acceptDownloads: true,
}
);
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
await test(context);
await context.close();
});
const { it, expect } = fixtures.build(); it('should report downloads in downloadsPath folder', async ({browserType, browserOptions, testInfo, server}) => {
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>`);
const [ download ] = await Promise.all([
page.waitForEvent('download'),
page.click('a')
]);
const path = await download.path();
expect(path.startsWith(testInfo.outputPath(''))).toBeTruthy();
await page.close();
await downloadsBrowser.close();
});
it('should keep downloadsPath folder', async ({downloadsBrowser, testInfo, server}) => { it('should accept downloads in persistent context', async ({launchPersistent, testInfo, server}) => {
const page = await downloadsBrowser.newPage(); const { context, page } = await launchPersistent({ acceptDownloads: true, downloadsPath: testInfo.outputPath('') });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`); await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
const [ download ] = await Promise.all([ const [ download ] = await Promise.all([
page.waitForEvent('download'), page.waitForEvent('download'),
page.click('a') page.click('a'),
]); ]);
expect(download.url()).toBe(`${server.PREFIX}/download`); expect(download.url()).toBe(`${server.PREFIX}/download`);
expect(download.suggestedFilename()).toBe(`file.txt`); expect(download.suggestedFilename()).toBe(`file.txt`);
await download.path().catch(e => void 0); const path = await download.path();
await page.close(); expect(path.startsWith(testInfo.outputPath(''))).toBeTruthy();
await downloadsBrowser.close(); await context.close();
expect(fs.existsSync(testInfo.outputPath(''))).toBeTruthy(); });
});
it('should delete downloads when context closes', async ({downloadsBrowser, server}) => { it('should delete downloads when persistent context closes', async ({launchPersistent, server, testInfo}) => {
const page = await downloadsBrowser.newPage({ acceptDownloads: true }); const { context, page } = await launchPersistent({ acceptDownloads: true, downloadsPath: testInfo.outputPath('') });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`); await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
const [ download ] = await Promise.all([ const [ download ] = await Promise.all([
page.waitForEvent('download'), page.waitForEvent('download'),
page.click('a') page.click('a'),
]); ]);
const path = await download.path(); const path = await download.path();
expect(fs.existsSync(path)).toBeTruthy(); expect(fs.existsSync(path)).toBeTruthy();
await page.close(); await context.close();
expect(fs.existsSync(path)).toBeFalsy(); expect(fs.existsSync(path)).toBeFalsy();
}); });
it('should report downloads in downloadsPath folder', async ({downloadsBrowser, testInfo, server}) => {
const page = await downloadsBrowser.newPage({ acceptDownloads: true });
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
const [ download ] = await Promise.all([
page.waitForEvent('download'),
page.click('a')
]);
const path = await download.path();
expect(path.startsWith(testInfo.outputPath(''))).toBeTruthy();
await page.close();
});
it('should accept downloads in persistent context', async ({persistentDownloadsContext, testInfo, server}) => {
const page = persistentDownloadsContext.pages()[0];
const [ download ] = await Promise.all([
page.waitForEvent('download'),
page.click('a'),
]);
expect(download.url()).toBe(`${server.PREFIX}/download`);
expect(download.suggestedFilename()).toBe(`file.txt`);
const path = await download.path();
expect(path.startsWith(testInfo.outputPath(''))).toBeTruthy();
});
it('should delete downloads when persistent context closes', async ({persistentDownloadsContext}) => {
const page = persistentDownloadsContext.pages()[0];
const [ download ] = await Promise.all([
page.waitForEvent('download'),
page.click('a'),
]);
const path = await download.path();
expect(fs.existsSync(path)).toBeTruthy();
await persistentDownloadsContext.close();
expect(fs.existsSync(path)).toBeFalsy();
}); });

View file

@ -15,65 +15,53 @@
* limitations under the License. * limitations under the License.
*/ */
import { folio as baseFolio } from './fixtures'; import { folio } from './fixtures';
import fs from 'fs'; import fs from 'fs';
import type * as har from '../src/server/supplements/har/har'; import type { BrowserContext, BrowserContextOptions } from '../index';
import type { BrowserContext, Page } from '../index'; import { TestInfo } from 'folio';
const { expect, it } = folio;
const builder = baseFolio.extend<{ async function pageWithHar(contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>, testInfo: TestInfo) {
pageWithHar: {
page: Page,
context: BrowserContext,
path: string,
log: () => Promise<har.Log>
}
}>();
builder.pageWithHar.init(async ({ contextFactory, testInfo }, run) => {
const harPath = testInfo.outputPath('test.har'); const harPath = testInfo.outputPath('test.har');
const context = await contextFactory({ recordHar: { path: harPath }, ignoreHTTPSErrors: true }); const context = await contextFactory({ recordHar: { path: harPath }, ignoreHTTPSErrors: true });
const page = await context.newPage(); const page = await context.newPage();
await run({ return {
path: harPath,
page, page,
context, getLog: async () => {
log: async () => {
await context.close(); await context.close();
return JSON.parse(fs.readFileSync(harPath).toString())['log']; return JSON.parse(fs.readFileSync(harPath).toString())['log'];
} }
}); };
}); }
const { expect, it } = builder.build();
it('should throw without path', async ({ browser }) => { it('should throw without path', async ({ browser }) => {
const error = await browser.newContext({ recordHar: {} as any }).catch(e => e); const error = await browser.newContext({ recordHar: {} as any }).catch(e => e);
expect(error.message).toContain('recordHar.path: expected string, got undefined'); expect(error.message).toContain('recordHar.path: expected string, got undefined');
}); });
it('should have version and creator', async ({ pageWithHar, server }) => { it('should have version and creator', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
expect(log.version).toBe('1.2'); expect(log.version).toBe('1.2');
expect(log.creator.name).toBe('Playwright'); expect(log.creator.name).toBe('Playwright');
expect(log.creator.version).toBe(require('../package.json')['version']); expect(log.creator.version).toBe(require('../package.json')['version']);
}); });
it('should have browser', async ({ browserName, browser, pageWithHar, server }) => { it('should have browser', async ({ browserName, browser, contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
expect(log.browser.name.toLowerCase()).toBe(browserName); expect(log.browser.name.toLowerCase()).toBe(browserName);
expect(log.browser.version).toBe(browser.version()); expect(log.browser.version).toBe(browser.version());
}); });
it('should have pages', async ({ pageWithHar, server }) => { it('should have pages', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto('data:text/html,<title>Hello</title>'); await page.goto('data:text/html,<title>Hello</title>');
// For data: load comes before domcontentloaded... // For data: load comes before domcontentloaded...
await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('domcontentloaded');
const log = await pageWithHar.log(); const log = await getLog();
expect(log.pages.length).toBe(1); expect(log.pages.length).toBe(1);
const pageEntry = log.pages[0]; const pageEntry = log.pages[0];
expect(pageEntry.id).toBe('page_0'); expect(pageEntry.id).toBe('page_0');
@ -97,10 +85,10 @@ it('should have pages in persistent context', async ({ launchPersistent, testInf
expect(pageEntry.title).toBe('Hello'); expect(pageEntry.title).toBe('Hello');
}); });
it('should include request', async ({ pageWithHar, server }) => { it('should include request', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
expect(log.entries.length).toBe(1); expect(log.entries.length).toBe(1);
const entry = log.entries[0]; const entry = log.entries[0];
expect(entry.pageref).toBe('page_0'); expect(entry.pageref).toBe('page_0');
@ -111,10 +99,10 @@ it('should include request', async ({ pageWithHar, server }) => {
expect(entry.request.headers.find(h => h.name.toLowerCase() === 'user-agent')).toBeTruthy(); expect(entry.request.headers.find(h => h.name.toLowerCase() === 'user-agent')).toBeTruthy();
}); });
it('should include response', async ({ pageWithHar, server }) => { it('should include response', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
const entry = log.entries[0]; const entry = log.entries[0];
expect(entry.response.status).toBe(200); expect(entry.response.status).toBe(200);
expect(entry.response.statusText).toBe('OK'); expect(entry.response.statusText).toBe('OK');
@ -123,29 +111,29 @@ it('should include response', async ({ pageWithHar, server }) => {
expect(entry.response.headers.find(h => h.name.toLowerCase() === 'content-type').value).toContain('text/html'); expect(entry.response.headers.find(h => h.name.toLowerCase() === 'content-type').value).toContain('text/html');
}); });
it('should include redirectURL', async ({ pageWithHar, server }) => { it('should include redirectURL', async ({ contextFactory, testInfo, server }) => {
server.setRedirect('/foo.html', '/empty.html'); server.setRedirect('/foo.html', '/empty.html');
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/foo.html'); await page.goto(server.PREFIX + '/foo.html');
const log = await pageWithHar.log(); const log = await getLog();
expect(log.entries.length).toBe(2); expect(log.entries.length).toBe(2);
const entry = log.entries[0]; const entry = log.entries[0];
expect(entry.response.status).toBe(302); expect(entry.response.status).toBe(302);
expect(entry.response.redirectURL).toBe(server.EMPTY_PAGE); expect(entry.response.redirectURL).toBe(server.EMPTY_PAGE);
}); });
it('should include query params', async ({ pageWithHar, server }) => { it('should include query params', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/har.html?name=value'); await page.goto(server.PREFIX + '/har.html?name=value');
const log = await pageWithHar.log(); const log = await getLog();
expect(log.entries[0].request.queryString).toEqual([{ name: 'name', value: 'value' }]); expect(log.entries[0].request.queryString).toEqual([{ name: 'name', value: 'value' }]);
}); });
it('should include postData', async ({ pageWithHar, server }) => { it('should include postData', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => fetch('./post', { method: 'POST', body: 'Hello' })); await page.evaluate(() => fetch('./post', { method: 'POST', body: 'Hello' }));
const log = await pageWithHar.log(); const log = await getLog();
expect(log.entries[1].request.postData).toEqual({ expect(log.entries[1].request.postData).toEqual({
mimeType: 'text/plain;charset=UTF-8', mimeType: 'text/plain;charset=UTF-8',
params: [], params: [],
@ -153,13 +141,13 @@ it('should include postData', async ({ pageWithHar, server }) => {
}); });
}); });
it('should include binary postData', async ({ pageWithHar, server }) => { it('should include binary postData', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(async () => { await page.evaluate(async () => {
await fetch('./post', { method: 'POST', body: new Uint8Array(Array.from(Array(16).keys())) }); await fetch('./post', { method: 'POST', body: new Uint8Array(Array.from(Array(16).keys())) });
}); });
const log = await pageWithHar.log(); const log = await getLog();
expect(log.entries[1].request.postData).toEqual({ expect(log.entries[1].request.postData).toEqual({
mimeType: 'application/octet-stream', mimeType: 'application/octet-stream',
params: [], params: [],
@ -167,12 +155,12 @@ it('should include binary postData', async ({ pageWithHar, server }) => {
}); });
}); });
it('should include form params', async ({ pageWithHar, server }) => { it('should include form params', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); 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>`); 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>`);
await page.click('input[type=submit]'); await page.click('input[type=submit]');
const log = await pageWithHar.log(); const log = await getLog();
expect(log.entries[1].request.postData).toEqual({ expect(log.entries[1].request.postData).toEqual({
mimeType: 'application/x-www-form-urlencoded', mimeType: 'application/x-www-form-urlencoded',
params: [ params: [
@ -183,8 +171,9 @@ it('should include form params', async ({ pageWithHar, server }) => {
}); });
}); });
it('should include cookies', async ({ pageWithHar, server }) => { it('should include cookies', async ({ contextFactory, testInfo, server }) => {
const { page, context } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
const context = page.context();
await context.addCookies([ await context.addCookies([
{ name: 'name1', value: '"value1"', domain: 'localhost', path: '/', httpOnly: true }, { name: 'name1', value: '"value1"', domain: 'localhost', path: '/', httpOnly: true },
{ name: 'name2', value: 'val"ue2', domain: 'localhost', path: '/', sameSite: 'Lax' }, { name: 'name2', value: 'val"ue2', domain: 'localhost', path: '/', sameSite: 'Lax' },
@ -192,7 +181,7 @@ it('should include cookies', async ({ pageWithHar, server }) => {
{ name: 'name4', value: 'val,ue4', domain: 'localhost', path: '/' }, { name: 'name4', value: 'val,ue4', domain: 'localhost', path: '/' },
]); ]);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
expect(log.entries[0].request.cookies).toEqual([ expect(log.entries[0].request.cookies).toEqual([
{ name: 'name1', value: '"value1"' }, { name: 'name1', value: '"value1"' },
{ name: 'name2', value: 'val"ue2' }, { name: 'name2', value: 'val"ue2' },
@ -203,8 +192,8 @@ it('should include cookies', async ({ pageWithHar, server }) => {
it('should include set-cookies', (test, { browserName, platform }) => { it('should include set-cookies', (test, { browserName, platform }) => {
test.fail(browserName === 'webkit' && platform === 'darwin', 'Does not work yet'); test.fail(browserName === 'webkit' && platform === 'darwin', 'Does not work yet');
}, async ({ pageWithHar, server }) => { }, async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', [ res.setHeader('Set-Cookie', [
'name1=value1; HttpOnly', 'name1=value1; HttpOnly',
@ -214,15 +203,15 @@ it('should include set-cookies', (test, { browserName, platform }) => {
res.end(); res.end();
}); });
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
const cookies = log.entries[0].response.cookies; const cookies = log.entries[0].response.cookies;
expect(cookies[0]).toEqual({ name: 'name1', value: 'value1', httpOnly: true }); expect(cookies[0]).toEqual({ name: 'name1', value: 'value1', httpOnly: true });
expect(cookies[1]).toEqual({ name: 'name2', value: '"value2"' }); expect(cookies[1]).toEqual({ name: 'name2', value: '"value2"' });
expect(new Date(cookies[2].expires).valueOf()).toBeGreaterThan(Date.now()); expect(new Date(cookies[2].expires).valueOf()).toBeGreaterThan(Date.now());
}); });
it('should include set-cookies with comma', async ({ pageWithHar, server }) => { it('should include set-cookies with comma', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', [ res.setHeader('Set-Cookie', [
'name1=val,ue1', 'name1=val,ue1',
@ -230,13 +219,13 @@ it('should include set-cookies with comma', async ({ pageWithHar, server }) => {
res.end(); res.end();
}); });
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
const cookies = log.entries[0].response.cookies; const cookies = log.entries[0].response.cookies;
expect(cookies[0]).toEqual({ name: 'name1', value: 'val,ue1' }); expect(cookies[0]).toEqual({ name: 'name1', value: 'val,ue1' });
}); });
it('should include secure set-cookies', async ({ pageWithHar, httpsServer }) => { it('should include secure set-cookies', async ({ contextFactory, testInfo, httpsServer }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
httpsServer.setRoute('/empty.html', (req, res) => { httpsServer.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', [ res.setHeader('Set-Cookie', [
'name1=value1; Secure', 'name1=value1; Secure',
@ -244,15 +233,15 @@ it('should include secure set-cookies', async ({ pageWithHar, httpsServer }) =>
res.end(); res.end();
}); });
await page.goto(httpsServer.EMPTY_PAGE); await page.goto(httpsServer.EMPTY_PAGE);
const log = await pageWithHar.log(); const log = await getLog();
const cookies = log.entries[0].response.cookies; const cookies = log.entries[0].response.cookies;
expect(cookies[0]).toEqual({ name: 'name1', value: 'value1', secure: true }); expect(cookies[0]).toEqual({ name: 'name1', value: 'value1', secure: true });
}); });
it('should include content', async ({ pageWithHar, server }) => { it('should include content', async ({ contextFactory, testInfo, server }) => {
const { page } = pageWithHar; const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/har.html'); await page.goto(server.PREFIX + '/har.html');
const log = await pageWithHar.log(); const log = await getLog();
const content1 = log.entries[0].response.content; const content1 = log.entries[0].response.content;
expect(content1.encoding).toBe('base64'); expect(content1.encoding).toBe('base64');

View file

@ -16,26 +16,27 @@
import { expect } from 'folio'; import { expect } from 'folio';
import { Page } from '..'; import { Page } from '..';
import { folio } from './recorder.fixtures'; import { folio } from './fixtures';
import { recorderPageGetter } from './utils';
const { afterEach, it, describe } = folio; const { afterEach, it, describe } = folio;
describe('pause', (suite, { mode }) => { describe('pause', (suite, { mode }) => {
suite.skip(mode !== 'default'); suite.skip(mode !== 'default');
}, () => { }, () => {
afterEach(async ({ recorderPageGetter }) => { afterEach(async ({ context, toImpl }) => {
try { try {
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
recorderPage.click('[title=Resume]').catch(() => {}); recorderPage.click('[title=Resume]').catch(() => {});
} catch (e) { } catch (e) {
// Some tests close context. // Some tests close context.
} }
}); });
it('should pause and resume the script', async ({ page, recorderPageGetter }) => { it('should pause and resume the script', async ({ page, context, toImpl }) => {
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title=Resume]'); await recorderPage.click('[title=Resume]');
await scriptPromise; await scriptPromise;
}); });
@ -52,33 +53,33 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should pause after a navigation', async ({page, server, recorderPageGetter}) => { it('should pause after a navigation', async ({page, server, context, toImpl}) => {
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.pause(); await page.pause();
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title=Resume]'); await recorderPage.click('[title=Resume]');
await scriptPromise; await scriptPromise;
}); });
it('should show source', async ({page, recorderPageGetter}) => { it('should show source', async ({page, context, toImpl}) => {
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
const source = await recorderPage.textContent('.source-line-paused .source-code'); const source = await recorderPage.textContent('.source-line-paused .source-code');
expect(source).toContain('page.pause()'); expect(source).toContain('page.pause()');
await recorderPage.click('[title=Resume]'); await recorderPage.click('[title=Resume]');
await scriptPromise; await scriptPromise;
}); });
it('should pause on next pause', async ({page, recorderPageGetter}) => { it('should pause on next pause', async ({page, context, toImpl}) => {
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); // 1 await page.pause(); // 1
await page.pause(); // 2 await page.pause(); // 2
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
const source = await recorderPage.textContent('.source-line-paused'); const source = await recorderPage.textContent('.source-line-paused');
expect(source).toContain('page.pause(); // 1'); expect(source).toContain('page.pause(); // 1');
await recorderPage.click('[title=Resume]'); await recorderPage.click('[title=Resume]');
@ -87,13 +88,13 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should step', async ({page, recorderPageGetter}) => { it('should step', async ({page, context, toImpl}) => {
await page.setContent('<button>Submit</button>'); await page.setContent('<button>Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
await page.click('button'); await page.click('button');
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
const source = await recorderPage.textContent('.source-line-paused'); const source = await recorderPage.textContent('.source-line-paused');
expect(source).toContain('page.pause();'); expect(source).toContain('page.pause();');
@ -104,13 +105,13 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should highlight pointer', async ({page, recorderPageGetter}) => { it('should highlight pointer', async ({page, context, toImpl}) => {
await page.setContent('<button>Submit</button>'); await page.setContent('<button>Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
await page.click('button'); await page.click('button');
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Step over"]'); await recorderPage.click('[title="Step over"]');
const point = await page.waitForSelector('x-pw-action-point'); const point = await page.waitForSelector('x-pw-action-point');
@ -130,28 +131,28 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should skip input when resuming', async ({page, recorderPageGetter}) => { it('should skip input when resuming', async ({page, context, toImpl}) => {
await page.setContent('<button>Submit</button>'); await page.setContent('<button>Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
await page.click('button'); await page.click('button');
await page.pause(); // 2 await page.pause(); // 2
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Resume"]'); await recorderPage.click('[title="Resume"]');
await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")'); await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")');
await recorderPage.click('[title=Resume]'); await recorderPage.click('[title=Resume]');
await scriptPromise; await scriptPromise;
}); });
it('should populate log', async ({page, recorderPageGetter}) => { it('should populate log', async ({page, context, toImpl}) => {
await page.setContent('<button>Submit</button>'); await page.setContent('<button>Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
await page.click('button'); await page.click('button');
await page.pause(); // 2 await page.pause(); // 2
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Resume"]'); await recorderPage.click('[title="Resume"]');
await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")'); await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")');
expect(await sanitizeLog(recorderPage)).toEqual([ expect(await sanitizeLog(recorderPage)).toEqual([
@ -163,7 +164,7 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should highlight waitForEvent', async ({page, recorderPageGetter}) => { it('should highlight waitForEvent', async ({page, context, toImpl}) => {
await page.setContent('<button onclick="console.log(1)">Submit</button>'); await page.setContent('<button onclick="console.log(1)">Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
@ -172,7 +173,7 @@ describe('pause', (suite, { mode }) => {
page.click('button'), page.click('button'),
]); ]);
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Step over"]'); await recorderPage.click('[title="Step over"]');
await recorderPage.waitForSelector('.source-line-paused:has-text("page.click")'); await recorderPage.waitForSelector('.source-line-paused:has-text("page.click")');
await recorderPage.waitForSelector('.source-line-running:has-text("page.waitForEvent")'); await recorderPage.waitForSelector('.source-line-running:has-text("page.waitForEvent")');
@ -180,7 +181,7 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should populate log with waitForEvent', async ({page, recorderPageGetter}) => { it('should populate log with waitForEvent', async ({page, context, toImpl}) => {
await page.setContent('<button onclick="console.log(1)">Submit</button>'); await page.setContent('<button onclick="console.log(1)">Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
@ -190,7 +191,7 @@ describe('pause', (suite, { mode }) => {
]); ]);
await page.pause(); // 2 await page.pause(); // 2
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Resume"]'); await recorderPage.click('[title="Resume"]');
await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")'); await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")');
expect(await sanitizeLog(recorderPage)).toEqual([ expect(await sanitizeLog(recorderPage)).toEqual([
@ -203,13 +204,13 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should populate log with error', async ({page, recorderPageGetter}) => { it('should populate log with error', async ({page, context, toImpl}) => {
await page.setContent('<button onclick="console.log(1)">Submit</button>'); await page.setContent('<button onclick="console.log(1)">Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
await page.isChecked('button'); await page.isChecked('button');
})().catch(e => e); })().catch(e => e);
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Resume"]'); await recorderPage.click('[title="Resume"]');
await recorderPage.waitForSelector('.source-line-error'); await recorderPage.waitForSelector('.source-line-error');
expect(await sanitizeLog(recorderPage)).toEqual([ expect(await sanitizeLog(recorderPage)).toEqual([
@ -223,7 +224,7 @@ describe('pause', (suite, { mode }) => {
expect(error.message).toContain('Not a checkbox or radio button'); expect(error.message).toContain('Not a checkbox or radio button');
}); });
it('should populate log with error in waitForEvent', async ({page, recorderPageGetter}) => { it('should populate log with error in waitForEvent', async ({page, context, toImpl}) => {
await page.setContent('<button>Submit</button>'); await page.setContent('<button>Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
@ -232,7 +233,7 @@ describe('pause', (suite, { mode }) => {
page.click('button'), page.click('button'),
]); ]);
})().catch(() => {}); })().catch(() => {});
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Step over"]'); await recorderPage.click('[title="Step over"]');
await recorderPage.waitForSelector('.source-line-paused:has-text("page.click")'); await recorderPage.waitForSelector('.source-line-paused:has-text("page.click")');
await recorderPage.waitForSelector('.source-line-error:has-text("page.waitForEvent")'); await recorderPage.waitForSelector('.source-line-error:has-text("page.waitForEvent")');
@ -247,36 +248,36 @@ describe('pause', (suite, { mode }) => {
await scriptPromise; await scriptPromise;
}); });
it('should pause on page close', async ({ page, recorderPageGetter }) => { it('should pause on page close', async ({ page, context, toImpl }) => {
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
await page.close(); await page.close();
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Step over"]'); await recorderPage.click('[title="Step over"]');
await recorderPage.waitForSelector('.source-line-paused:has-text("page.close();")'); await recorderPage.waitForSelector('.source-line-paused:has-text("page.close();")');
await recorderPage.click('[title=Resume]'); await recorderPage.click('[title=Resume]');
await scriptPromise; await scriptPromise;
}); });
it('should pause on context close', async ({ page, recorderPageGetter }) => { it('should pause on context close', async ({ page, context, toImpl }) => {
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
await page.context().close(); await page.context().close();
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
await recorderPage.click('[title="Step over"]'); await recorderPage.click('[title="Step over"]');
await recorderPage.waitForSelector('.source-line-paused:has-text("page.context().close();")'); await recorderPage.waitForSelector('.source-line-paused:has-text("page.context().close();")');
await recorderPage.click('[title=Resume]'); await recorderPage.click('[title=Resume]');
await scriptPromise; await scriptPromise;
}); });
it('should highlight on explore', async ({ page, recorderPageGetter }) => { it('should highlight on explore', async ({ page, context, toImpl }) => {
await page.setContent('<button>Submit</button>'); await page.setContent('<button>Submit</button>');
const scriptPromise = (async () => { const scriptPromise = (async () => {
await page.pause(); await page.pause();
})(); })();
const recorderPage = await recorderPageGetter(); const recorderPage = await recorderPageGetter(context, toImpl);
const [element] = await Promise.all([ const [element] = await Promise.all([
page.waitForSelector('x-pw-highlight:visible'), page.waitForSelector('x-pw-highlight:visible'),
recorderPage.fill('input[placeholder="Playwright Selector"]', 'text=Submit'), recorderPage.fill('input[placeholder="Playwright Selector"]', 'text=Submit'),

View file

@ -1,36 +0,0 @@
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { folio as baseFolio } from './fixtures';
import { Page } from '..';
import { chromium } from '../index';
const fixtures = baseFolio.extend<{
recorderPageGetter: () => Promise<Page>,
}>();
fixtures.recorderPageGetter.init(async ({context, toImpl}, runTest) => {
await runTest(async () => {
while (!toImpl(context).recorderAppForTest)
await new Promise(f => setTimeout(f, 100));
const wsEndpoint = toImpl(context).recorderAppForTest.wsEndpoint;
const browser = await chromium.connectOverCDP({ wsEndpoint });
const c = browser.contexts()[0];
return c.pages()[0] || await c.waitForEvent('page');
});
});
export const folio = fixtures.build();

View file

@ -14,46 +14,40 @@
* limitations under the License. * limitations under the License.
*/ */
import { folio as baseFolio } from './fixtures'; import { folio } from './fixtures';
import { InMemorySnapshotter } from '../lib/server/snapshot/inMemorySnapshotter'; import { InMemorySnapshotter } from '../lib/server/snapshot/inMemorySnapshotter';
import { HttpServer } from '../lib/utils/httpServer'; import { HttpServer } from '../lib/utils/httpServer';
import { SnapshotServer } from '../lib/server/snapshot/snapshotServer'; import { SnapshotServer } from '../lib/server/snapshot/snapshotServer';
const { it, describe, expect, beforeEach, afterEach } = folio;
type TestFixtures = {
snapshotter: any;
snapshotPort: number;
};
export const fixtures = baseFolio.extend<TestFixtures>();
fixtures.snapshotter.init(async ({ context, toImpl }, runTest) => {
const snapshotter = new InMemorySnapshotter(toImpl(context));
await snapshotter.initialize();
await runTest(snapshotter);
await snapshotter.dispose();
});
fixtures.snapshotPort.init(async ({ snapshotter, testWorkerIndex }, runTest) => {
const httpServer = new HttpServer();
new SnapshotServer(httpServer, snapshotter);
const port = 9700 + testWorkerIndex;
httpServer.start(port);
await runTest(port);
httpServer.stop();
});
const { it, describe, expect } = fixtures.build();
describe('snapshots', (suite, { mode }) => { describe('snapshots', (suite, { mode }) => {
suite.skip(mode !== 'default'); suite.skip(mode !== 'default');
}, () => { }, () => {
let snapshotter: any;
let httpServer: any;
let snapshotPort: number;
it('should collect snapshot', async ({ snapshotter, page, toImpl }) => { beforeEach(async ({ context, toImpl, testWorkerIndex }) => {
snapshotter = new InMemorySnapshotter(toImpl(context));
await snapshotter.initialize();
httpServer = new HttpServer();
new SnapshotServer(httpServer, snapshotter);
snapshotPort = 9700 + testWorkerIndex;
httpServer.start(snapshotPort);
});
afterEach(async () => {
await snapshotter.dispose();
httpServer.stop();
});
it('should collect snapshot', async ({ page, toImpl }) => {
await page.setContent('<button>Hello</button>'); await page.setContent('<button>Hello</button>');
const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot'); const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot');
expect(distillSnapshot(snapshot)).toBe('<BUTTON>Hello</BUTTON>'); expect(distillSnapshot(snapshot)).toBe('<BUTTON>Hello</BUTTON>');
}); });
it('should capture resources', async ({ snapshotter, page, toImpl, server }) => { it('should capture resources', async ({ page, toImpl, server }) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.route('**/style.css', route => { await page.route('**/style.css', route => {
route.fulfill({ body: 'button { color: red; }', }).catch(() => {}); route.fulfill({ body: 'button { color: red; }', }).catch(() => {});
@ -65,7 +59,7 @@ describe('snapshots', (suite, { mode }) => {
expect(resources[cssHref]).toBeTruthy(); expect(resources[cssHref]).toBeTruthy();
}); });
it('should collect multiple', async ({ snapshotter, page, toImpl }) => { it('should collect multiple', async ({ page, toImpl }) => {
await page.setContent('<button>Hello</button>'); await page.setContent('<button>Hello</button>');
const snapshots = []; const snapshots = [];
snapshotter.on('snapshot', snapshot => snapshots.push(snapshot)); snapshotter.on('snapshot', snapshot => snapshots.push(snapshot));
@ -74,7 +68,7 @@ describe('snapshots', (suite, { mode }) => {
expect(snapshots.length).toBe(2); expect(snapshots.length).toBe(2);
}); });
it('should only collect on change', async ({ snapshotter, page }) => { it('should only collect on change', async ({ page }) => {
await page.setContent('<button>Hello</button>'); await page.setContent('<button>Hello</button>');
const snapshots = []; const snapshots = [];
snapshotter.on('snapshot', snapshot => snapshots.push(snapshot)); snapshotter.on('snapshot', snapshot => snapshots.push(snapshot));
@ -89,7 +83,7 @@ describe('snapshots', (suite, { mode }) => {
expect(snapshots.length).toBe(2); expect(snapshots.length).toBe(2);
}); });
it('should respect inline CSSOM change', async ({ snapshotter, page }) => { it('should respect inline CSSOM change', async ({ page }) => {
await page.setContent('<style>button { color: red; }</style><button>Hello</button>'); await page.setContent('<style>button { color: red; }</style><button>Hello</button>');
const snapshots = []; const snapshots = [];
snapshotter.on('snapshot', snapshot => snapshots.push(snapshot)); snapshotter.on('snapshot', snapshot => snapshots.push(snapshot));
@ -108,7 +102,7 @@ describe('snapshots', (suite, { mode }) => {
expect(distillSnapshot(snapshots[1])).toBe('<style>button { color: blue; }</style><BUTTON>Hello</BUTTON>'); expect(distillSnapshot(snapshots[1])).toBe('<style>button { color: blue; }</style><BUTTON>Hello</BUTTON>');
}); });
it('should respect subresource CSSOM change', async ({ snapshotter, page, server }) => { it('should respect subresource CSSOM change', async ({ page, server }) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.route('**/style.css', route => { await page.route('**/style.css', route => {
route.fulfill({ body: 'button { color: red; }', }).catch(() => {}); route.fulfill({ body: 'button { color: red; }', }).catch(() => {});
@ -137,7 +131,7 @@ describe('snapshots', (suite, { mode }) => {
it('should capture iframe', (test, { browserName }) => { it('should capture iframe', (test, { browserName }) => {
test.skip(browserName === 'firefox'); test.skip(browserName === 'firefox');
}, async ({ contextFactory, snapshotter, page, server, snapshotPort, toImpl }) => { }, async ({ contextFactory, page, server, toImpl }) => {
await page.route('**/empty.html', route => { await page.route('**/empty.html', route => {
route.fulfill({ route.fulfill({
body: '<iframe src="iframe.html"></iframe>', body: '<iframe src="iframe.html"></iframe>',
@ -176,7 +170,7 @@ describe('snapshots', (suite, { mode }) => {
expect(await button.textContent()).toBe('Hello iframe'); expect(await button.textContent()).toBe('Hello iframe');
}); });
it('should capture snapshot target', async ({ snapshotter, page, toImpl }) => { it('should capture snapshot target', async ({ page, toImpl }) => {
await page.setContent('<button>Hello</button><button>World</button>'); await page.setContent('<button>Hello</button><button>World</button>');
{ {
const handle = await page.$('text=Hello'); const handle = await page.$('text=Hello');
@ -190,7 +184,7 @@ describe('snapshots', (suite, { mode }) => {
} }
}); });
it('should collect on attribute change', async ({ snapshotter, page, toImpl }) => { it('should collect on attribute change', async ({ page, toImpl }) => {
await page.setContent('<button>Hello</button>'); await page.setContent('<button>Hello</button>');
{ {
const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot'); const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot');

View file

@ -15,7 +15,8 @@
*/ */
import { expect } from './fixtures'; import { expect } from './fixtures';
import type { Frame, Page } from '../index'; import type { Frame, Page, BrowserContext } from '../index';
import { chromium } from '../index';
export async function attachFrame(page: Page, frameId: string, url: string): Promise<Frame> { export async function attachFrame(page: Page, frameId: string, url: string): Promise<Frame> {
const handle = await page.evaluateHandle(async ({ frameId, url }) => { const handle = await page.evaluateHandle(async ({ frameId, url }) => {
@ -58,3 +59,12 @@ export function expectedSSLError(browserName: string): string {
} }
return expectedSSLError; return expectedSSLError;
} }
export async function recorderPageGetter(context: BrowserContext, toImpl: (x: any) => any) {
while (!toImpl(context).recorderAppForTest)
await new Promise(f => setTimeout(f, 100));
const wsEndpoint = toImpl(context).recorderAppForTest.wsEndpoint;
const browser = await chromium.connectOverCDP({ wsEndpoint });
const c = browser.contexts()[0];
return c.pages()[0] || await c.waitForEvent('page');
}