← Back to libraryQuestion 173 of 273
🎭PlaywrightIntermediate

Network Interception & Mocking (route/fulfill)

📌 Definition:

page.route() lets you intercept matching network requests and decide their fate: fulfill them with a mock response, modify and continue them, or abort them. This makes tests deterministic by removing dependence on live backends and lets you simulate hard-to-reproduce states.

📖 Detailed Explanation:

Selenium can't see or control network traffic without extra proxies; Playwright exposes it natively because it observes the browser protocol directly. With page.route('**/api/products', handler) you match a URL pattern and, in the handler, call route.fulfill({ json: [...] }) to return canned data, route.continue({ headers }) to modify and pass through, or route.abort() to simulate a failed request. This is invaluable for testing error and edge states — empty lists, 500 errors, slow responses, rate limits — that are painful to trigger against a real server. Mocking also decouples UI tests from backend availability, so a broken staging API doesn't fail your front-end suite.

🔑 Key Points:
  • route.fulfill() returns a mock response; route.continue() modifies+passes through; route.abort() fails it
  • Deterministic UI tests: no dependence on live backend data or uptime
  • Simulate edge states cheaply: empty results, 500s, timeouts, 429 rate limits
  • Match with glob or regex URL patterns; unhandled routes hit the real network
  • Prefer mocking at the network boundary over injecting stubs into app code
🌍 Real-World Example:

You need to verify the 'No products found' empty state, but staging always has products. page.route('**/api/products', r => r.fulfill({ json: [] })) forces an empty response, so the UI renders the empty state on demand — reliably, in every browser, without touching the backend.

📎 Code Example:
// Mock a successful but empty product list
await page.route('**/api/products', route =>
  route.fulfill({ status: 200, json: [] })
);
await page.goto('/shop');
await expect(page.getByText('No products found')).toBeVisible();

// Simulate a server error to test the error UI
await page.route('**/api/products', route =>
  route.fulfill({ status: 500, json: { error: 'Internal Server Error' } })
);

// Modify a request in flight (e.g. add an auth header) then continue
await page.route('**/api/**', route =>
  route.continue({ headers: { ...route.request().headers(), 'x-test': '1' } })
);

// Simulate an outage
await page.route('**/api/products', route => route.abort());
🎯 Scenario-Based Interview Question:

Scenario: The team wants front-end tests to stop failing whenever the shared staging API has bad data or downtime, but still cover the empty-state, error-state and slow-response UIs. How do you use Playwright to achieve this?