Skip to content

Network Mocking

When to Use

Intercepting HTTP requests for determinism, error-state testing, or speed.

Pattern: URL Patterns

Pattern Example Notes
Glob '**/api/users/*' Default. ** matches across slashes; * does not
RegExp /\/api\/users\/\d+/ When glob isn't expressive enough
Function url => url.pathname.startsWith('/api/') Most flexible

Watch the protocol/host: '**/api/users' matches both your host and third-parties. Anchor as needed.

Pattern: The Four Route Handlers

// 1. fulfill — return a canned response
await page.route('**/api/orders', async route => {
  await route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify([{ id: 1, total: 10 }]),
    headers: { 'X-Mocked': 'true' },
  });
});

// 2. abort — fail the request
await page.route('**/analytics.js', route => route.abort());

// 3. continue — pass through, optionally with overrides
await page.route('**/api/**', async route => {
  const headers = { ...route.request().headers(), 'X-Test': 'true' };
  await route.continue({ headers });
});

// 4. fallback — let the next matching handler decide (handler chain)
await page.route('**/*', route => route.fallback());

route.continue() with no args = "do nothing, real network proceeds." Useful as a logging last-resort handler.

Decision: When to Mock

Mock when Don't mock when
Third-party dependency (Stripe, Algolia, Mapbox) — outages cause flake Auth flows — verify real session behavior
Reproducing error states (500, 429, malformed JSON) the backend can't reliably produce Database writes you intend to assert on later
Slow APIs that aren't the subject of the test The exact thing under test (don't mock /api/orders in a "place an order" test)
Determinism for VR (clock, currency rates) First-run smoke tests — let real wiring break loudly

Pattern: HAR Record/Replay

# Record once
npx playwright codegen --save-har=tests/.fixtures/orders.har https://example.com
// Replay
await context.routeFromHAR('tests/.fixtures/orders.har', {
  url: '**/api/**',
  update: false,        // true = re-record on this run
  notFound: 'fallback', // or 'abort'
});

HAR matches URL + method + (for POST) body strictly. Useful when: - the third-party is unstable - you want byte-exact replay across CI runs - you need to test against an API you can't yet bring up locally

Common Mistakes

  • Globbing too broadly'**/*' blocks essential CSS/JS; scope handlers
  • Mocking the thing under test — defeats the purpose
  • Forgetting to await the route handler setup — race; the test starts before the handler is registered

See Also