Route Mocking
page.route() intercepts network requests matching a pattern and lets you fulfill with mock data, modify real responses, or abort — essential for stable E2E tests.
Fulfill vs Continue route.fulfill({ status, body, headers }) returns mock response without hitting server. route.continue() forwards to network, optionally with overridden headers or POST data.
Load mock JSON from files with fs.readFileSync or import fixtures directly in TypeScript.
await page.route('**/api/user', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ name: 'Test User', role: 'admin' }),
});
});
await page.goto('/profile');
await expect(page.getByText('Test User')).toBeVisible(); Register route before navigation that triggers the fetch.
Route Handler Patterns await page.route('**/api/**', handler);
await page.route('**/*', route => route.continue()); // passthrough
await page.unroute('**/api/**'); // cleanup Glob patterns match URL strings. Handlers can be async — fetch real response and patch. Multiple routes: most specific registered first. Use route.fetch() to get upstream response then modify. Route Mocking Recipes Common mock scenarios.
Scenario Approach Empty list fulfill({ body: '[]' }) 500 error fulfill({ status: 500 }) Slow network await delay(2000); route.continue() Modify live API route.fetch() then fulfill patched JSON Block analytics route.abort() for tracking domains GraphQL Match POST body operationName in handler
Partial Mock with route.fetch await page.route('**/api/product/*', async route => {
const response = await route.fetch();
const json = await response.json();
json.price = 0; // test free checkout
await route.fulfill({ response, json });
}); fulfill with json Shorthand route.fulfill({ json: { id: 1 } }) sets content-type and serializes automatically — shorter than manual JSON.stringify in the body.
Common Mistakes Mock path mismatch — API URL changed, mock silently unused. JSON body as object instead of string in fulfill. Routes not cleared between tests affecting others. Mocking too much — missing integration bugs. Key Takeaways route.fulfill fully mocks; route.continue passthroughs. Register routes before triggering requests. route.fetch enables modify-then-return patterns. Balance mocked E2E with real API contract tests.
Pro Tip
Assert the app actually called the API with page.waitForRequest + expect on postData — catches tests that pass without hitting your mock.
Network Testing Go to next item