Skip to content

Commit b339ad8

Browse files
authored
feat: advanced matchers with post-process option (#11)
1 parent 1d52a5c commit b339ad8

File tree

4 files changed

+92
-13
lines changed

4 files changed

+92
-13
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ test("pick arbirtrary response", async ({ page, advancedRouteFromHAR }) => {
7777
});
7878
```
7979

80+
apply post-proccessing on the chosen HAR entry:
81+
82+
```typescript
83+
test("get the largest number... squared!", async ({ page, advancedRouteFromHAR }) => {
84+
// the file contains 3 responses - 42, 1234, 5
85+
await advancedRouteFromHAR("tests/har/differentNumbers.har", {
86+
matcher: {
87+
postProcess(entry) {
88+
entry.response.content.text = (parseInt(entry.response.content.text || "0") ** 2).toString();
89+
return entry;
90+
},
91+
matchFunction: customMatcher({
92+
scoring: (request, entry) => parseInt(entry.response.content.text || "0"),
93+
}),
94+
}
95+
});
96+
await page.goto("https://noam-gaash.co.il");
97+
await page.getByText((1234**2).toString()).waitFor();
98+
});
99+
```
100+
80101
for more examples, please see our `tests` directory
81102

82103
# Contribution

src/utils/serveFromHar.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { Content, Har } from "har-format";
2-
import { Matcher } from "..";
3-
import { Page, Request, Route, test } from "@playwright/test";
2+
import { type Matcher, defaultMatcher } from "..";
3+
import { type Page, type Request, type Route, test } from "@playwright/test";
44
import path = require("path");
55
import { promises } from "fs";
6+
import { AdvancedMatcher } from "./types";
67

78
export async function serveFromHar(
89
har: Har,
910
options: {
1011
notFound?: "abort" | "fallback" | ((route: Route) => Promise<void>);
1112
url?: string | RegExp;
12-
matcher: Matcher;
13+
matcher: Matcher | AdvancedMatcher;
1314
dirName: string;
1415
},
1516
page: Page,
@@ -21,7 +22,12 @@ export async function serveFromHar(
2122
"advancedRouteFromHAR",
2223
async () => {
2324
await page.route(options.url ?? /.*/, async (route) => {
24-
const entry = findEntry(har, route.request(), options!);
25+
let entry = typeof options.matcher === "function" ?
26+
findEntry(har, route.request(), options!.matcher) :
27+
(options.matcher.findEntry ?? findEntry)(har, route.request(), options!.matcher.matchFunction);
28+
if("postProcess" in options.matcher && options.matcher.postProcess) {
29+
entry = options.matcher.postProcess(entry, route);
30+
}
2531
if (entry === null) {
2632
if (options?.notFound === "fallback") {
2733
route.fallback();
@@ -43,15 +49,13 @@ export async function serveFromHar(
4349
);
4450
}
4551

46-
function findEntry(
52+
export function findEntry(
4753
har: Har,
4854
request: Request,
49-
options: {
50-
matcher: Matcher;
51-
},
55+
matcher: Matcher = defaultMatcher
5256
) {
5357
// score each entry
54-
const entriesWithScore = har.log.entries.map((entry) => ({ entry, score: options.matcher(request, entry) }));
58+
const entriesWithScore = har.log.entries.map((entry) => ({ entry, score: matcher(request, entry) }));
5559

5660
// filter out entries with negative scores
5761
const goodEntries = entriesWithScore.filter(({ score }) => score >= 0);

src/utils/types.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import type { Request, Route } from "@playwright/test";
22
import type { Entry } from "har-format";
3+
import type { findEntry } from "./serveFromHar";
34

45
export type Matcher = (request: Request, entry: Entry) => number;
5-
export type CustomMatcher = Matcher & {
6-
then: (matcher: Matcher) => CustomMatcher;
7-
};
6+
7+
export type AdvancedMatcher = {
8+
findEntry?: typeof findEntry;
9+
matchFunction?: Matcher;
10+
postProcess?: (entry: Entry, route?: Route) => Entry;
11+
}
812

913
export type Method = "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" | "CONNECT" | "TRACE";
1014

@@ -48,7 +52,7 @@ export type RouteFromHAROptions = {
4852
* if the number is negative, the entry is not used.
4953
* the entry with the highest score will be used to respond to the request.
5054
*/
51-
matcher?: Matcher;
55+
matcher?: Matcher | AdvancedMatcher;
5256
};
5357

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

tests/advancedMatchers.spec.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { customMatcher, test } from "../lib/index";
2+
3+
test("largest number squared - using explicit findEntry", async ({ page, advancedRouteFromHAR }) => {
4+
// the file contains 3 responses - 42, 1234, 5
5+
await advancedRouteFromHAR("tests/har/differentNumbers.har", {
6+
matcher: {
7+
findEntry(har) {
8+
const chosen = har.log.entries.reduce((max, entry) => {
9+
const number = parseInt(entry.response.content.text || "0");
10+
const maxNumber = parseInt(max.response.content.text || "0");
11+
return number > maxNumber ? entry : max;
12+
});
13+
return {
14+
...chosen,
15+
response: {
16+
...chosen.response,
17+
content: {
18+
...chosen.response.content,
19+
text: (parseInt(chosen.response.content.text || "0") ** 2).toString(),
20+
},
21+
},
22+
};
23+
}
24+
}
25+
});
26+
await page.goto("https://noam-gaash.co.il");
27+
await page.getByText((1234**2).toString()).waitFor();
28+
});
29+
30+
test("largest number squared - using postprocess", async ({ page, advancedRouteFromHAR }) => {
31+
// the file contains 3 responses - 42, 1234, 5
32+
await advancedRouteFromHAR("tests/har/differentNumbers.har", {
33+
matcher: {
34+
postProcess(entry) {
35+
entry.response.content.text = (parseInt(entry.response.content.text || "0") ** 2).toString();
36+
return entry;
37+
},
38+
matchFunction: customMatcher({
39+
scoring: (request, entry) => parseInt(entry.response.content.text || "0"),
40+
}),
41+
}
42+
});
43+
await page.goto("https://noam-gaash.co.il");
44+
await page.getByText((1234**2).toString()).waitFor();
45+
await page.reload();
46+
// note - the postProcess is called again, and the number is squared again each time the response is used
47+
await page.getByText((1234**4).toString()).waitFor();
48+
});
49+
50+

0 commit comments

Comments
 (0)