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.
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.
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');
});
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");
}
}
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")
Written by PV
© 2026 All Rights Reserved