Skip to content

Commit

Permalink
feat: advanced matchers with postprocess option
Browse files Browse the repository at this point in the history
  • Loading branch information
NoamGaash committed Feb 13, 2024
1 parent 1d52a5c commit 3f0eafb
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 13 deletions.
21 changes: 21 additions & 0 deletions README.md
Expand Up @@ -77,6 +77,27 @@ test("pick arbirtrary response", async ({ page, advancedRouteFromHAR }) => {
});
```

apply post-proccessing on the chosen HAR entry:

```typescript
test("get the largest number... squared!", async ({ page, advancedRouteFromHAR }) => {
// the file contains 3 responses - 42, 1234, 5
await advancedRouteFromHAR("tests/har/differentNumbers.har", {
matcher: {
postProcess(entry) {
entry.response.content.text = (parseInt(entry.response.content.text || "0") ** 2).toString();
return entry;
},
matchFunction: customMatcher({
scoring: (request, entry) => parseInt(entry.response.content.text || "0"),
}),
}
});
await page.goto("https://noam-gaash.co.il");
await page.getByText((1234**2).toString()).waitFor();
});
```

for more examples, please see our `tests` directory

# Contribution
Expand Down
22 changes: 13 additions & 9 deletions src/utils/serveFromHar.ts
@@ -1,15 +1,16 @@
import { Content, Har } from "har-format";
import { Matcher } from "..";
import { Page, Request, Route, test } from "@playwright/test";
import { type Matcher, defaultMatcher } from "..";
import { type Page, type Request, type Route, test } from "@playwright/test";
import path = require("path");
import { promises } from "fs";
import { AdvancedMatcher } from "./types";

export async function serveFromHar(
har: Har,
options: {
notFound?: "abort" | "fallback" | ((route: Route) => Promise<void>);
url?: string | RegExp;
matcher: Matcher;
matcher: Matcher | AdvancedMatcher;
dirName: string;
},
page: Page,
Expand All @@ -21,7 +22,12 @@ export async function serveFromHar(
"advancedRouteFromHAR",
async () => {
await page.route(options.url ?? /.*/, async (route) => {
const entry = findEntry(har, route.request(), options!);
let entry = typeof options.matcher === 'function' ?

Check failure on line 25 in src/utils/serveFromHar.ts

View workflow job for this annotation

GitHub Actions / test-package

Strings must use doublequote

Check failure on line 25 in src/utils/serveFromHar.ts

View workflow job for this annotation

GitHub Actions / test-package

Strings must use doublequote
findEntry(har, route.request(), options!.matcher) :
(options.matcher.findEntry ?? findEntry)(har, route.request(), options!.matcher.matchFunction);
if('postProcess' in options.matcher && options.matcher.postProcess) {

Check failure on line 28 in src/utils/serveFromHar.ts

View workflow job for this annotation

GitHub Actions / test-package

Strings must use doublequote

Check failure on line 28 in src/utils/serveFromHar.ts

View workflow job for this annotation

GitHub Actions / test-package

Strings must use doublequote
entry = options.matcher.postProcess(entry, route);
}
if (entry === null) {
if (options?.notFound === "fallback") {
route.fallback();
Expand All @@ -43,15 +49,13 @@ export async function serveFromHar(
);
}

function findEntry(
export function findEntry(
har: Har,
request: Request,
options: {
matcher: Matcher;
},
matcher: Matcher = defaultMatcher
) {
// score each entry
const entriesWithScore = har.log.entries.map((entry) => ({ entry, score: options.matcher(request, entry) }));
const entriesWithScore = har.log.entries.map((entry) => ({ entry, score: matcher(request, entry) }));

// filter out entries with negative scores
const goodEntries = entriesWithScore.filter(({ score }) => score >= 0);
Expand Down
12 changes: 8 additions & 4 deletions src/utils/types.ts
@@ -1,10 +1,14 @@
import type { Request, Route } from "@playwright/test";
import type { Entry } from "har-format";
import type { findEntry } from "./serveFromHar";

export type Matcher = (request: Request, entry: Entry) => number;
export type CustomMatcher = Matcher & {
then: (matcher: Matcher) => CustomMatcher;
};

export type AdvancedMatcher = {
findEntry?: typeof findEntry;
matchFunction?: Matcher;
postProcess?: (entry: Entry, route?: Route) => Entry;
}

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

Expand Down Expand Up @@ -48,7 +52,7 @@ export type RouteFromHAROptions = {
* if the number is negative, the entry is not used.
* the entry with the highest score will be used to respond to the request.
*/
matcher?: Matcher;
matcher?: Matcher | AdvancedMatcher;
};

export type AdvancedRouteFromHAR = (filename: string, options?: RouteFromHAROptions) => Promise<void>;
50 changes: 50 additions & 0 deletions tests/advancedMatchers.spec.ts
@@ -0,0 +1,50 @@
import { customMatcher, test } from "../lib/index";

test("largest number squared - using explicit findEntry", async ({ page, advancedRouteFromHAR }) => {
// the file contains 3 responses - 42, 1234, 5
await advancedRouteFromHAR("tests/har/differentNumbers.har", {
matcher: {
findEntry(har, request) {

Check failure on line 7 in tests/advancedMatchers.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

'request' is defined but never used

Check failure on line 7 in tests/advancedMatchers.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

'request' is defined but never used
const chosen = har.log.entries.reduce((max, entry) => {
const number = parseInt(entry.response.content.text || "0");
const maxNumber = parseInt(max.response.content.text || "0");
return number > maxNumber ? entry : max;
});
return {
...chosen,
response: {
...chosen.response,
content: {
...chosen.response.content,
text: (parseInt(chosen.response.content.text || "0") ** 2).toString(),
},
},
}

Check failure on line 22 in tests/advancedMatchers.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon

Check failure on line 22 in tests/advancedMatchers.spec.ts

View workflow job for this annotation

GitHub Actions / test-package

Missing semicolon
}
}
});
await page.goto("https://noam-gaash.co.il");
await page.getByText((1234**2).toString()).waitFor();
});

test("largest number squared - using postprocess", async ({ page, advancedRouteFromHAR }) => {
// the file contains 3 responses - 42, 1234, 5
await advancedRouteFromHAR("tests/har/differentNumbers.har", {
matcher: {
postProcess(entry) {
entry.response.content.text = (parseInt(entry.response.content.text || "0") ** 2).toString();
return entry;
},
matchFunction: customMatcher({
scoring: (request, entry) => parseInt(entry.response.content.text || "0"),
}),
}
});
await page.goto("https://noam-gaash.co.il");
await page.getByText((1234**2).toString()).waitFor();
await page.reload();
// note - the postProcess is called again, and the number is squared again each time the response is used
await page.getByText((1234**4).toString()).waitFor();
});


0 comments on commit 3f0eafb

Please sign in to comment.