feature(har): add testOptions.har (#14991)

Can now be used with `test.use({ har })`.
Also added more tests for latest har features.
This commit is contained in:
Dmitry Gozman 2022-06-20 13:37:31 -07:00 committed by GitHub
parent c3bbf8963d
commit 5397394653
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 157 additions and 2 deletions

View File

@ -129,6 +129,8 @@ Options used to create the context, as passed to [`method: Browser.newContext`].
## property: TestOptions.geolocation = %%-context-option-geolocation-%%
## property: TestOptions.har = %%-js-context-option-har-%%
## property: TestOptions.hasTouch = %%-context-option-hastouch-%%
## property: TestOptions.headless = %%-browser-option-headless-%%

View File

@ -141,6 +141,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
deviceScaleFactor: [ undefined, { option: true } ],
extraHTTPHeaders: [ undefined, { option: true } ],
geolocation: [ undefined, { option: true } ],
har: [undefined, { option: true }],
hasTouch: [ undefined, { option: true } ],
httpCredentials: [ undefined, { option: true } ],
ignoreHTTPSErrors: [ undefined, { option: true } ],
@ -168,6 +169,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
colorScheme,
deviceScaleFactor,
extraHTTPHeaders,
har,
hasTouch,
geolocation,
httpCredentials,
@ -199,6 +201,8 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
options.extraHTTPHeaders = extraHTTPHeaders;
if (geolocation !== undefined)
options.geolocation = geolocation;
if (har !== undefined)
options.har = har;
if (hasTouch !== undefined)
options.hasTouch = hasTouch;
if (httpCredentials !== undefined)

View File

@ -2492,6 +2492,7 @@ type BrowserName = 'chromium' | 'firefox' | 'webkit';
type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>;
type ColorScheme = Exclude<BrowserContextOptions['colorScheme'], undefined>;
type ExtraHTTPHeaders = Exclude<BrowserContextOptions['extraHTTPHeaders'], undefined>;
type HAROptions = Exclude<BrowserContextOptions['har'], undefined>;
type Proxy = Exclude<BrowserContextOptions['proxy'], undefined>;
type StorageState = Exclude<BrowserContextOptions['storageState'], undefined>;
type ServiceWorkerPolicy = Exclude<BrowserContextOptions['serviceWorkers'], undefined>;
@ -2699,6 +2700,14 @@ export interface PlaywrightTestOptions {
*/
extraHTTPHeaders: ExtraHTTPHeaders | undefined;
geolocation: Geolocation | undefined;
/**
* If specified the network requests that are made in the context will be served from the HAR file.
*
* > NOTE: Playwright will not serve requests intercepted by Service Worker from the HAR file. See
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
* request interception. Via `await context.addInitScript(() => delete window.navigator.serviceWorker);`
*/
har: HAROptions | undefined;
/**
* Specifies if viewport supports touch events. Defaults to false.
*/

View File

@ -0,0 +1 @@
Hello, world

96
tests/assets/har-sha1.har Normal file
View File

@ -0,0 +1,96 @@
{
"log": {
"version": "1.2",
"creator": {
"name": "Playwright",
"version": "1.23.0-next"
},
"browser": {
"name": "chromium",
"version": "103.0.5060.33"
},
"pages": [
{
"startedDateTime": "2022-06-10T04:27:32.125Z",
"id": "page@b17b177f1c2e66459db3dcbe44636ffd",
"title": "Hey",
"pageTimings": {
"onContentLoad": 70,
"onLoad": 70
}
}
],
"entries": [
{
"_requestref": "request@ee2a0dc164935fcd4d9432d37b245f3c",
"_frameref": "frame@c7467fc0f1f86f09fc3b0d727a3862ea",
"_monotonicTime": 270572145.898,
"startedDateTime": "2022-06-10T04:27:32.146Z",
"time": 8.286,
"request": {
"method": "GET",
"url": "http://no.playwright/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{
"name": "Accept",
"value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
},
{
"name": "Upgrade-Insecure-Requests",
"value": "1"
},
{
"name": "User-Agent",
"value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.33 Safari/537.36"
}
],
"queryString": [],
"headersSize": 326,
"bodySize": 0
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{
"name": "content-length",
"value": "12"
},
{
"name": "content-type",
"value": "text/html"
}
],
"content": {
"size": 12,
"mimeType": "text/html",
"compression": 0,
"_sha1": "har-sha1-main-response.txt"
},
"headersSize": 64,
"bodySize": 71,
"redirectURL": "",
"_transferSize": 71
},
"cache": {
"beforeRequest": null,
"afterRequest": null
},
"timings": {
"dns": -1,
"connect": -1,
"ssl": -1,
"send": 0,
"wait": 8.286,
"receive": -1
},
"pageref": "page@b17b177f1c2e66459db3dcbe44636ffd",
"_securityDetails": {}
}
]
}
}

View File

@ -166,3 +166,29 @@ it('should reload redirected navigation', async ({ contextFactory, isAndroid, as
expect(response.request().url()).toBe('https://www.theverge.com/');
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
});
it('should fulfill from har with content in a file', async ({ contextFactory, isAndroid, asset }) => {
it.fixme(isAndroid);
const path = asset('har-sha1.har');
const context = await contextFactory({ har: { path } });
const page = await context.newPage();
await page.goto('http://no.playwright/');
expect(await page.content()).toBe('<html><head></head><body>Hello, world</body></html>');
});
it('should round-trip har.zip', async ({ contextFactory, isAndroid, server }, testInfo) => {
it.fixme(isAndroid);
const harPath = testInfo.outputPath('har.zip');
const context1 = await contextFactory({ recordHar: { path: harPath } });
const page1 = await context1.newPage();
await page1.goto(server.PREFIX + '/one-style.html');
await context1.close();
const context2 = await contextFactory({ har: { path: harPath, fallback: 'abort' } });
const page2 = await context2.newPage();
await page2.goto(server.PREFIX + '/one-style.html');
expect(await page2.content()).toContain('hello, world!');
await expect(page2.locator('body')).toHaveCSS('background-color', 'rgb(255, 192, 203)');
});

View File

@ -30,7 +30,7 @@ export class VideoPlayer {
const output = spawnSync(ffmpeg, ['-i', fileName, '-r', '25', `${fileName}-%03d.png`]).stderr.toString();
const lines = output.split('\n');
const streamLine = lines.find(l => l.trim().startsWith('Stream #0:0'));
const resolutionMatch = streamLine.match(/, (\d+)x(\d+),/);
const resolutionMatch = streamLine!.match(/, (\d+)x(\d+),/);
this.videoWidth = parseInt(resolutionMatch![1], 10);
this.videoHeight = parseInt(resolutionMatch![2], 10);
}
@ -526,7 +526,7 @@ test('should work with video: on-first-retry', async ({ runInlineTest }, testInf
expect(result.report.suites[0].specs[1].tests[0].results[1].attachments).toEqual([{
name: 'video',
contentType: 'video/webm',
path: path.join(dirRetry, videoFailRetry),
path: path.join(dirRetry, videoFailRetry!),
}]);
});
@ -602,3 +602,18 @@ test('should pass fixture defaults to tests', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
});
test('should support har option', async ({ runInlineTest, asset }) => {
const result = await runInlineTest({
'a.test.ts': `
const { test } = pwt;
test.use({ har: { path: ${JSON.stringify(asset('har-fulfill.har'))} }});
test('pass', async ({ page }) => {
await page.goto('http://no.playwright/');
expect(await page.evaluate('window.value')).toBe('foo');
});
`,
}, { workers: 1 });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
});

View File

@ -173,6 +173,7 @@ type BrowserName = 'chromium' | 'firefox' | 'webkit';
type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>;
type ColorScheme = Exclude<BrowserContextOptions['colorScheme'], undefined>;
type ExtraHTTPHeaders = Exclude<BrowserContextOptions['extraHTTPHeaders'], undefined>;
type HAROptions = Exclude<BrowserContextOptions['har'], undefined>;
type Proxy = Exclude<BrowserContextOptions['proxy'], undefined>;
type StorageState = Exclude<BrowserContextOptions['storageState'], undefined>;
type ServiceWorkerPolicy = Exclude<BrowserContextOptions['serviceWorkers'], undefined>;
@ -215,6 +216,7 @@ export interface PlaywrightTestOptions {
deviceScaleFactor: number | undefined;
extraHTTPHeaders: ExtraHTTPHeaders | undefined;
geolocation: Geolocation | undefined;
har: HAROptions | undefined;
hasTouch: boolean | undefined;
httpCredentials: HTTPCredentials | undefined;
ignoreHTTPSErrors: boolean | undefined;