Skip to content

backendMocks

The backendMocks fixture is the Playwright-facing API for routing outbound Node traffic.

ts
import { test, expect } from "@playwright-backend-mocks/playwright";

test("mocks a backend call", async ({ page, backendMocks }) => {
  await backendMocks.route("https://api.example.test/users", async (route) => {
    await route.fulfill({ json: [{ id: 1, name: "Ada" }] });
  });

  await page.goto("/users");
});

Fixture exports

ts
export { test, expect } from "@playwright-backend-mocks/playwright";

The package also exports TypeScript types such as BackendMocks, BackendRoute, BackendRequest, BackendResponse, RouteMatcherInput, and BackendMocksWorkerOptions.

backendMocks.route(matcher, handler, options?)

Registers an HTTP route for this test.

ts
await backendMocks.route(
  { url: "https://api.example.test/charges", method: "POST" },
  async (route, request) => {
    expect(request.postDataJSON()).toEqual({ amount: 2000 });
    await route.fulfill({ status: 201, json: { id: "ch_mock" } });
  },
  { times: 1 },
);
ParameterTypeDescription
matcherRouteMatcherInputGlob, RegExp, predicate, URLPattern, or { url, method, clientId }.
handler(route, request) => Promise<void> | voidRuns in the Playwright worker when this test owns the request.
options.timesnumberAutomatically unregister after this many handled matches.

HTTP routes are newest-first within one test. Use route.fallback() to continue to the next matching route.

backendMocks.unroute(matcher?, handler?)

Removes HTTP routes from this test.

ts
const handler = async (route: BackendRoute) => {
  await route.fulfill({ json: [] });
};

await backendMocks.route("**/users", handler);
await backendMocks.unroute("**/users", handler);
CallEffect
unroute()Remove all HTTP routes for this test.
unroute(matcher)Remove routes whose matcher is equal to matcher.
unroute(matcher, handler)Remove routes matching both the matcher and handler reference.

backendMocks.unrouteAll(options?)

Removes all HTTP routes for this test.

ts
await backendMocks.unrouteAll({ behavior: "wait" });
OptionTypeDefaultDescription
behavior"default" | "wait" | "ignoreErrors""default"How to treat active route handler invocations.

"default" force-continues in-flight HTTP routes. "wait" waits for active handlers. "ignoreErrors" suppresses errors from active handlers.

WARNING

unrouteAll() removes HTTP routes only. WebSocket routes survive it.

backendMocks.routeFromHAR(file, options?)

Registers HAR replay or recording as an HTTP route.

ts
await backendMocks.routeFromHAR("tests/fixtures/api.har", {
  url: "https://api.example.test/**",
  notFound: "fallback",
});

See HAR.

backendMocks.routeWebSocket(url, handler)

Registers a WebSocket route.

DANGER

WebSocket interception only supports app code using globalThis.WebSocket.

ts
await backendMocks.routeWebSocket("wss://events.example.test/socket", async (ws) => {
  ws.send("hello from test");
});

See WebSocketRoute.

backendMocks.waitForRequest(matcher, options?)

Waits for a future outbound request.

ts
const request = await backendMocks.waitForRequest(
  (request) => request.method() === "POST" && request.url().endsWith("/charges"),
  { timeout: 10_000 },
);
OptionTypeDefault
timeoutnumber30000
signalAbortSignalnone

backendMocks.waitForResponse(matcher, options?)

Waits for a future outbound response.

ts
const response = await backendMocks.waitForResponse(
  (response) => response.url().endsWith("/charges") && response.status() === 201,
);

expect(await response.json()).toEqual({ id: "ch_123" });

Options are { timeout?, signal? }.

backendMocks.requests(matcher?)

Returns observed requests for this test, optionally filtered by a normal route matcher.

ts
const requests = await backendMocks.requests({
  url: "**/charges",
  method: "POST",
});

expect(requests[0]!.clientId).toBe("api-server");

backendMocks.takeErrors()

Returns and clears proxy/handler errors recorded for this test.

ts
const errors = backendMocks.takeErrors();
expect(errors[0]?.message).toMatch(/Ambiguous backend mock routing/);

Any remaining errors fail fixture teardown.

Mock the outside world. Keep the real app.