Skip to content

Commit

Permalink
fix: postprocess function will work with update: true
Browse files Browse the repository at this point in the history
  • Loading branch information
NoamGaash committed Feb 20, 2024
1 parent 0a1cb02 commit fd74278
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 5 deletions.
17 changes: 15 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test as base } from "@playwright/test";
import * as fs from "fs";
import { AdvancedRouteFromHAR } from "./utils/types";
import { serveFromHar } from "./utils/serveFromHar";
import { AdvancedRouteFromHAR, requestResponseToEntry } from "./utils/types";
import { parseContent, serveFromHar } from "./utils/serveFromHar";
import { defaultMatcher } from "./utils/matchers/defaultMatcher";
export { Matcher, AdvancedRouteFromHAR } from "./utils/types";
export { defaultMatcher } from "./utils/matchers/defaultMatcher";
Expand All @@ -15,6 +15,19 @@ export const test = base.extend<{
const originalRouteFromHAR = page.routeFromHAR.bind(page);
const advancedRouteFromHAR: AdvancedRouteFromHAR = async (filename, options) => {
if (options?.update) {
const {matcher} = options

Check failure on line 18 in src/index.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 18 in src/index.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon
if (matcher && "postProcess" in matcher) {
await page.route(options.url || /.*/, async (route, request) => {
const resp = await route.fetch();
const response = matcher.postProcess?.(await requestResponseToEntry(request, resp, await page.context().cookies())).response;
if(response)
route.fulfill({
status: response.status,
headers: Object.fromEntries(response.headers.map((header) => [header.name, header.value])),
body: await parseContent(response.content, path.dirname(filename)),
});
})

Check failure on line 29 in src/index.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 29 in src/index.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon
}
// on update, we want to record the HAR just like the original playwright method
return originalRouteFromHAR(filename, {
update: true,
Expand Down
2 changes: 1 addition & 1 deletion src/utils/serveFromHar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function findEntry(
return bestEntry?.entry ?? null;
}

async function parseContent(
export async function parseContent(
content: Omit<Content & { _file?: string }, "text"> & { text?: Buffer | string },
dirName: string = ".",
) {
Expand Down
53 changes: 52 additions & 1 deletion src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Request, Route } from "@playwright/test";
import type { APIResponse, Request, Route, Cookie } from "@playwright/test";
import type { Entry } from "har-format";
import type { findEntry } from "./serveFromHar";

Expand Down Expand Up @@ -56,3 +56,54 @@ export type RouteFromHAROptions = {
};

export type AdvancedRouteFromHAR = (filename: string, options?: RouteFromHAROptions) => Promise<void>;

export async function requestResponseToEntry(request: Request, resp: APIResponse, requestCookies: Cookie[]): Promise<Entry> {
const postData = request.postData();
const body = await resp.body();
const respHeaders = resp.headers();
return {
startedDateTime: new Date().toISOString(),
time: 0, // TODO: get the actual time
cache: {},
timings: {
send: 0, // TODO: get the actual time
wait: 0, // TODO: get the actual time
receive: 0, // TODO: get the actual time
},
request: {
httpVersion: "HTTP/2.0", // TODO: is it possible to get this from playwright?
bodySize: postData ? postData.length : 0,
cookies: requestCookies.map((cookie) => ({
...cookie,
expires: cookie.expires?.toString(),
})),
headersSize: -1, // TODO: get the actual size
queryString: Object.entries(request.url().split("?")[1] ?? {}).map(([name, value]) => ({ name, value })),
url: request.url(),
method: request.method(),
headers: Object.entries(request.headers()).map(([name, value]) => ({ name, value })),
postData: postData ? {
text: postData,
mimeType: request.headers()["content-type"],
} : undefined,
},
response: {
httpVersion: "HTTP/2.0", // TODO: is it possible to get this from playwright?
bodySize: body.length,
cookies: respHeaders["set-cookie"]?.split(";").map((cookie) => {
const [name, value] = cookie.split("=");
return { name, value };
}),
headersSize: -1, // TODO: get the actual size
content: {
text: body.toString(),
size: body.length,
mimeType: respHeaders["content-type"],
},
headers: Object.entries(resp.headers()).map(([name, value]) => ({ name, value })),
redirectURL: resp.url(),
status: resp.status(),
statusText: resp.statusText(),
},
};
}
26 changes: 26 additions & 0 deletions tests/setup.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { describe } from "node:test";

Check failure on line 1 in tests/setup.ts

View workflow job for this annotation

GitHub Actions / test-package

'describe' is defined but never used

Check failure on line 1 in tests/setup.ts

View workflow job for this annotation

GitHub Actions / test-package

'describe' is defined but never used
import { test } from "../lib/index";

test("record", async ({ page, advancedRouteFromHAR }) => {
Expand All @@ -8,3 +9,28 @@ test("record", async ({ page, advancedRouteFromHAR }) => {
await page.goto("https://demo.playwright.dev/todomvc");
await page.close();
});

test("record test with a joke", async ({ page, advancedRouteFromHAR }) => {
await advancedRouteFromHAR("tests/har/temp/joke.har", {
update: true,
updateContent: "embed",
});
await page.goto("https://v2.jokeapi.dev/joke/Any?blacklistFlags=nsfw,religious,political,racist,sexist,explicit");
await page.close();
})

Check failure on line 20 in tests/setup.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 20 in tests/setup.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

test("record test with a joke and postprocess", async ({ page, advancedRouteFromHAR }) => {
await advancedRouteFromHAR("tests/har/temp/joke-postprocess.har", {
update: true,
updateContent: "embed",
matcher: {
postProcess(entry) {
entry.response.content.text = "This is a joke";
return entry;
}
}
});
await page.goto("https://v2.jokeapi.dev/joke/Any?blacklistFlags=nsfw,religious,political,racist,sexist,explicit");
await page.waitForSelector("text=This is a joke");
await page.close();
})

Check failure on line 36 in tests/setup.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 36 in tests/setup.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon
2 changes: 1 addition & 1 deletion tests/teardown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ import fs from "fs";

test("teardown", async ({}) => {

Check failure on line 4 in tests/teardown.ts

View workflow job for this annotation

GitHub Actions / test-package

Unexpected empty object pattern

Check failure on line 4 in tests/teardown.ts

View workflow job for this annotation

GitHub Actions / test-package

Unexpected empty object pattern
// clean up
await fs.promises.rm("tests/har/temp/demo.playwright.dev.har");
await fs.promises.rmdir("tests/har/temp", { recursive: true });
});
58 changes: 58 additions & 0 deletions tests/test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,61 @@ async function waitForFile(path: string) {
}
throw "can't read file";
}

test("test a joke recording with postprocess", async ({ page, advancedRouteFromHAR }) => {
await advancedRouteFromHAR("tests/har/temp/joke-postprocess.har", {
update: true,
updateContent: "embed",
matcher: {
postProcess(entry) {
entry.response.content.text = "This is a joke";
return entry;
}
}
});
await page.goto("https://v2.jokeapi.dev/joke/Any?blacklistFlags=nsfw,religious,political,racist,sexist,explicit");
await page.waitForSelector("text=This is a joke");
await page.close();
})

Check failure on line 188 in tests/test.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 188 in tests/test.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

test("test a joke recording with different postprocess that was not recorded", async ({ page, advancedRouteFromHAR }) => {
await advancedRouteFromHAR("tests/har/temp/joke-postprocess.har", {
update: true,
updateContent: "embed",
matcher: {
postProcess(entry) {
entry.response.content.text = "This is not a joke";
return entry;
}
}
});
await page.goto("https://v2.jokeapi.dev/joke/Any?blacklistFlags=nsfw,religious,political,racist,sexist,explicit");
await page.waitForSelector("text=This is not a joke");
await page.close();
})

Check failure on line 204 in tests/test.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 204 in tests/test.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

test("test a postprocess that change only part of the output", async ({ page, advancedRouteFromHAR }) => {
await advancedRouteFromHAR("tests/har/temp/joke-postprocess.har", {
update: true,
updateContent: "embed",
matcher: {
postProcess(entry) {
const json = JSON.parse(entry.response.content.text ?? "{}");
console.log(json);
console.log(entry.response.content.text);
json.flags.custom = true;
entry.response.content.text = JSON.stringify(json);
return entry;
}
}
});
await page.goto("https://v2.jokeapi.dev/joke/Any?blacklistFlags=nsfw,religious,political,racist,sexist,explicit");
const flags = await page.evaluate(() => {
return JSON.parse(document.body.textContent ?? "{}").flags;
});
expect(flags.custom).toBe(true);
expect(flags.nsfw).toBe(false);
await page.close();
})

Check failure on line 228 in tests/test.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 228 in tests/test.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon


0 comments on commit fd74278

Please sign in to comment.