Playwright MSW
A Mock Service Worker (MSW) integration layer for Playwright.
Features
- Powerful. Intercept and mock network requests that are performed by browsers during Playwright test execution.
- Flexible. Runs within context of an individual test, mocks can be safely manipulated on a per-test basis without interfering with others that are executing in parallel.
- Easy to implement. No code changes are required to your app. 1
Getting started
Prerequisites
This library assumes that you have the following peer dependencies are already installed:
Install
To start, install the dependency using your preferred package manager:
npm install playwright-msw --save-dev
# or
yarn add playwright-msw --dev
Setup
Create mock handlers
If you haven't already done so, create some mock handlers for API calls that your app will perform. e.g. within a handlers.ts file:
import { rest } from "msw";
export default [
rest.get("/api/users", (_, response, context) =>
response(
context.delay(500),
context.status(200),
context.json([
{
id: "bcff5c0e-10b6-407b-94d1-90d741363885",
firstName: "Rhydian",
lastName: "Greig",
},
{
id: "b44e89e4-3254-415e-b14a-441166616b20",
firstName: "Alessandro",
lastName: "Metcalfe",
},
{
id: "6e369942-6b5d-4159-9b39-729646549183",
firstName: "Erika",
lastName: "Richards",
},
])
)
),
];
Create a the worker fixture
The next step is to create a custom fixture using the createWorkerFixture function from playwright-msw
. e.g. within a custom test.ts file:
import { test as base, expect } from "@playwright/test";
import type { MockServiceWorker } from "playwright-msw";
import { createWorkerFixture } from "playwright-msw";
import handlers from "./handlers";
const test = base.extend<{
worker: MockServiceWorker;
}>({
worker: createWorkerFixture(...handlers),
});
export { test, expect };
Use the custom test fixture
The final step is to use the extended test
implementation within your playwright tests. e.g. within a demo.spec.ts file:
import { rest } from "msw";
import { expect, test } from "../test";
test.describe.parallel("A demo of playwright-msw's functionality", () => {
test("should use the default handlers without requiring handlers to be specified on a per-test basis", async ({
page,
}) => {
await page.goto("/");
await expect(page.locator('text="Alessandro Metcalfe"')).toBeVisible();
});
test.only("should allow mocks to be overridden on a per test basis", async ({
page,
worker,
}) => {
await worker.use(
rest.get("/api/users", (_, response, context) =>
response(context.delay(250), context.status(403))
)
);
await page.goto("/");
await expect(page.locator('text="Alessandro Metcalfe"')).toBeHidden();
await expect(page.locator('text="Failed to load users"')).toBeVisible();
});
});
API
createWorkerFixture
The createWorkerFixture(...handlers)
function creates a fixture that mocks api calls on a per-test basis that is automatically started even if the test does not use it directly. The provided handlers will be used by all tests by default. The created MockServiceWorker fixture can be optionally used to customise mocks on a per-test basis.
Refer to the Getting Started: Create a the worker fixture for a usage example. If this abstraction layer is over-simplified for your use case, the createServer function can be used instead.
createServer
The createServer(page: Page, ...handlers: RequestHandler[])
function creates a server that intercepts and mocks API calls for an individual playwright page. The createServer
returns a MockServiceWorker object which can be used for further customization.
Usage example:
import { test as base, expect } from "@playwright/test";
import { createServer, MockServiceWorker } from "playwright-msw";
import handlers from "./handlers";
const test = base.extend<{
worker: MockServiceWorker;
}>({
worker: [
async ({ page }, use) => {
const server = await createServer(page, ...handlers);
await use(server);
},
{
scope: "test",
auto: true,
},
],
});
export { test, expect };
MockServiceWorker
The MockServiceWorker
instance exposes a number of utility functions to facilitate additional customisations:
use(...customHandlers: RequestHandler[])
: Prepends given request handlers to the list of existing handlers. This is useful for overriding mocks on a per test behaviour, e.g. testing what happens if a particular API call fails.resetHandlers(...customHandlers: RequestHandler[])
: Resets request handlers to the initial list given to the createServer call, or to the explicit next request handlers list, if given.