test(har): add more har tests (#14997)

This commit is contained in:
Pavel Feldman 2022-06-20 17:22:32 -07:00 committed by GitHub
parent aaafb77036
commit 883e4d449a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 30 deletions

View File

@ -194,44 +194,34 @@ class HarBackend {
const harLog = this._harFile.log;
const visited = new Set<HAREntry>();
while (true) {
const entries = harLog.entries.filter(entry => entry.request.url === url && entry.request.method === method);
const entries: HAREntry[] = [];
for (const candidate of harLog.entries) {
if (candidate.request.url !== url || candidate.request.method !== method)
continue;
if (method === 'POST' && postData && candidate.request.postData) {
const buffer = await this._loadContent(candidate.request.postData);
if (!buffer.equals(postData))
continue;
}
entries.push(candidate);
}
if (!entries.length)
return;
let entry: HAREntry | undefined;
let entry = entries[0];
// Disambiguate using headers - then one with most matching headers wins.
if (entries.length > 1) {
// Disambiguating requests
// 1. Disambiguate using postData - this covers GraphQL
if (!entry && postData) {
for (const candidate of entries) {
if (!candidate.request.postData)
continue;
const buffer = await this._loadContent(candidate.request.postData);
if (buffer.equals(postData)) {
entry = candidate;
break;
}
}
const list: { candidate: HAREntry, matchingHeaders: number }[] = [];
for (const candidate of entries) {
const matchingHeaders = countMatchingHeaders(candidate.request.headers, headers);
list.push({ candidate, matchingHeaders });
}
// Last. Disambiguate using headers - then one with most matching headers wins.
if (!entry) {
const list: { candidate: HAREntry, matchingHeaders: number }[] = [];
for (const candidate of entries) {
const matchingHeaders = countMatchingHeaders(candidate.request.headers, headers);
list.push({ candidate, matchingHeaders });
}
list.sort((a, b) => b.matchingHeaders - a.matchingHeaders);
entry = list[0].candidate;
}
} else {
entry = entries[0];
list.sort((a, b) => b.matchingHeaders - a.matchingHeaders);
entry = list[0].candidate;
}
if (visited.has(entry))
throw new Error(`Found redirect cycle for ${url}`);

View File

@ -16,6 +16,8 @@
import { browserTest as it, expect } from '../config/browserTest';
import fs from 'fs';
import path from 'path';
import extractZip from '../../packages/playwright-core/bundles/zip/node_modules/extract-zip';
it('should fulfill from har, matching the method and following redirects', async ({ contextFactory, isAndroid, asset }) => {
it.fixme(isAndroid);
@ -192,3 +194,91 @@ it('should round-trip har.zip', async ({ contextFactory, isAndroid, server }, te
expect(await page2.content()).toContain('hello, world!');
await expect(page2.locator('body')).toHaveCSS('background-color', 'rgb(255, 192, 203)');
});
it('should round-trip extracted 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 harDir = testInfo.outputPath('hardir');
await extractZip(harPath, { dir: harDir });
const context2 = await contextFactory({ har: { path: path.join(harDir, 'har.har') } });
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)');
});
it('should round-trip har with postData', async ({ contextFactory, isAndroid, server }, testInfo) => {
it.fixme(isAndroid);
server.setRoute('/echo', async (req, res) => {
const body = await req.postBody;
res.end(body.toString());
});
const harPath = testInfo.outputPath('har.zip');
const context1 = await contextFactory({ recordHar: { path: harPath } });
const page1 = await context1.newPage();
await page1.goto(server.EMPTY_PAGE);
const fetchFunction = async (body: string) => {
const response = await fetch('/echo', { method: 'POST', body });
return await response.text();
};
expect(await page1.evaluate(fetchFunction, '1')).toBe('1');
expect(await page1.evaluate(fetchFunction, '2')).toBe('2');
expect(await page1.evaluate(fetchFunction, '3')).toBe('3');
await context1.close();
const context2 = await contextFactory({ har: { path: harPath } });
const page2 = await context2.newPage();
await page2.goto(server.EMPTY_PAGE);
expect(await page2.evaluate(fetchFunction, '1')).toBe('1');
expect(await page2.evaluate(fetchFunction, '2')).toBe('2');
expect(await page2.evaluate(fetchFunction, '3')).toBe('3');
expect(await page2.evaluate(fetchFunction, '4').catch(e => e)).toBeTruthy();
});
it('should disambiguate by header', async ({ contextFactory, isAndroid, server }, testInfo) => {
it.fixme(isAndroid);
server.setRoute('/echo', async (req, res) => {
res.end(req.headers['baz']);
});
const harPath = testInfo.outputPath('har.zip');
const context1 = await contextFactory({ recordHar: { path: harPath } });
const page1 = await context1.newPage();
await page1.goto(server.EMPTY_PAGE);
const fetchFunction = async (bazValue: string) => {
const response = await fetch('/echo', {
method: 'POST',
body: '',
headers: {
foo: 'foo-value',
bar: 'bar-value',
baz: bazValue,
}
});
return await response.text();
};
expect(await page1.evaluate(fetchFunction, 'baz1')).toBe('baz1');
expect(await page1.evaluate(fetchFunction, 'baz2')).toBe('baz2');
expect(await page1.evaluate(fetchFunction, 'baz3')).toBe('baz3');
await context1.close();
const context2 = await contextFactory({ har: { path: harPath } });
const page2 = await context2.newPage();
await page2.goto(server.EMPTY_PAGE);
expect(await page2.evaluate(fetchFunction, 'baz1')).toBe('baz1');
expect(await page2.evaluate(fetchFunction, 'baz2')).toBe('baz2');
expect(await page2.evaluate(fetchFunction, 'baz3')).toBe('baz3');
expect(await page2.evaluate(fetchFunction, 'baz4')).toBe('baz1');
});