Advanced Chapter 18 · 15 min read

Network Interception & Mocking

Intercept, modify, mock, and abort network requests to test edge cases without requiring a live backend.

Why Mock the Network?

Real backends are slow, stateful, and can return errors that are hard to reproduce. Network mocking lets you simulate any API response — including server errors, empty lists, timeouts, and malformed JSON — without changing the backend code. This makes it trivial to test every branch of your frontend error-handling logic and lets you run tests in environments with no backend at all.

Tip: Use network mocking for unit-style UI tests and real backend calls for end-to-end integration tests. A good test suite has both — mocked tests run fast and catch regressions early; real-backend tests verify the full system.

Route and Fulfill

page.route(pattern, handler) intercepts every request matching the URL pattern. Inside the handler you can call route.fulfill() to return a synthetic response, route.abort() to simulate a network failure, or route.continue() to let the request pass through (optionally with modified headers or body). The pattern can be a string, glob, or regular expression.

HAR Files

For complex scenarios with many API endpoints, record a HAR (HTTP Archive) file from a real session and then replay it in tests. Playwright can record HAR with context.recordHar() and replay it with context.routeFromHAR(). This gives you a complete network snapshot that tests can run against without any live backend.

network-mock.spec.js
import { test, expect } from '@playwright/test';

test('mock API response for empty list', async ({ page }) => {
  // Intercept before navigating
  await page.route('**/api/products', route =>
    route.fulfill({ json: [] })
  );
  await page.goto('/products');
  await expect(page.getByText('No products found')).toBeVisible();
});

test('simulate 500 server error', async ({ page }) => {
  await page.route('**/api/users', route =>
    route.fulfill({ status: 500, body: 'Internal Server Error' })
  );
  await page.goto('/users');
  await expect(page.getByText('Something went wrong')).toBeVisible();
});

test('abort image requests to test fallback', async ({ page }) => {
  await page.route('**/*.{jpg,png,webp}', route => route.abort());
  await page.goto('/gallery');
  // Should show alt text / placeholder
  await expect(page.getByAltText('Photo of product')).toBeVisible();
});

test('modify request headers', async ({ page }) => {
  await page.route('**/api/**', async route => {
    const headers = { ...route.request().headers(), 'x-test-flag': 'true' };
    await route.continue({ headers });
  });
  await page.goto('/dashboard');
});
NetworkMockTest.java
import com.microsoft.playwright.*;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

class NetworkMockTest {
  void mockEmptyResponse(Page page) {
    page.route("**/api/products", route ->
      route.fulfill(new Route.FulfillOptions()
          .setBody("[]")
          .setContentType("application/json")
      )
    );
    page.navigate("/products");
    assertThat(page.getByText("No products found")).isVisible();
  }

  void simulateServerError(Page page) {
    page.route("**/api/users", route ->
      route.fulfill(new Route.FulfillOptions()
          .setStatus(500)
          .setBody("Internal Server Error")
      )
    );
    page.navigate("/users");
    assertThat(page.getByText("Something went wrong")).isVisible();
  }

  void abortImageRequests(Page page) {
    page.route("**/*.jpg", Route::abort);
    page.route("**/*.png", Route::abort);
    page.navigate("/gallery");
  }
}
test_network_mock.py
import json
from playwright.sync_api import Page, Route, expect

def test_mock_empty_list(page: Page):
    def handle_products(route: Route):
        route.fulfill(
            status=200,
            content_type="application/json",
            body=json.dumps([])
        )

    page.route("**/api/products", handle_products)
    page.goto("/products")
    expect(page.get_by_text("No products found")).to_be_visible()

def test_simulate_server_error(page: Page):
    page.route(
        "**/api/users",
        lambda r: r.fulfill(status=500, body="Internal Server Error")
    )
    page.goto("/users")
    expect(page.get_by_text("Something went wrong")).to_be_visible()

def test_abort_images(page: Page):
    page.route("**/*.{jpg,png,webp}", lambda r: r.abort())
    page.goto("/gallery")
    expect(page.get_by_alt_text("Photo of product")).to_be_visible()

def test_modify_request_headers(page: Page):
    def add_flag_header(route: Route):
        headers = {**route.request.headers, "x-test-flag": "true"}
        route.continue_(headers=headers)

    page.route("**/api/**", add_flag_header)
    page.goto("/dashboard")

Playwright Advanced Network Interception & Mocking

Written by PV

© 2026 All Rights Reserved