Playwright Network Mocking — Mock Response Shape Mismatch
Frontend renders no data; console shows 'undefined' errors because mock response keys don't match TypeScript interfaces.
- page.route() intercepts HTTP requests before they leave the browser.
- route.fulfill() returns a fake response with custom status, headers, and body.
- route.continue() lets the request proceed, optionally modifying headers or payload.
- route.abort() blocks unwanted requests (trackers, images, fonts).
- Mocking eliminates backend flakiness — tests become deterministic and fast.
- Performance: aborting heavy assets can cut test execution time by up to 40%.
Think of network mocking like a stunt double for your backend. Instead of your browser talking to the real server, Playwright replaces the conversation with a pretend server that returns exactly what you want. This lets you test your UI in any scenario — success, failure, slow network — without waiting for the real server to be ready.
Testing a modern frontend often feels like a hostage situation — you are at the mercy of the backend's availability and speed. Playwright's network interception capabilities break this dependency.
By leveraging the route API, you can turn your browser automation into a powerful mocking engine. Whether you need to simulate a 500 Internal Server Error, mock a slow 3G connection for performance testing, or entirely replace a JSON response to test a specific UI state, Playwright handles it natively via the DevTools protocol. This guide moves beyond basic automation into advanced network manipulation strategies for production-grade test suites.
The Core Concept — page.route()
In Selenium, mocking network traffic usually required a separate proxy like BrowserMob. In Playwright, you simply define a routing rule. When the browser makes a request that matches your pattern (URL or Glob), Playwright intercepts it and gives you control over the route object.
route.fulfill(): Provide a mock response (status, headers, body).route.continue(): Let the request proceed to the internet (possibly with modifications).route.abort(): Kill the request (useful for blocking ads or analytics).
- Patterns are checked in order of registration
- First match wins, so define specific routes before generic fallbacks
- You can chain multiple handlers by calling
route.fallback()in advanced scenarios
page.goto().route.fulfill() with a realistic JSON body.route.continue() with modified headers/body.route.abort() — no response sent.Simulating Edge Cases: API Failures and Timeouts
One of the hardest things to test is how your UI behaves when the server dies. Using Playwright, you can force a 500 error or even a total connection failure to ensure your error handling actually works.
route.abort() simulates a dropped connection.route.fulfill() with the appropriate status code.route.fulfill() with a very long delay or call route.abort() after a timeout.route.fulfill() with an empty body or invalid JSON.Advanced: Modifying Outgoing Requests
Sometimes you don't want to mock the whole response, but you need to inject a specific header (like an Auth token) or modify a payload before it leaves the browser. Use for this.route.continue()
route.continue_() works, but some headers (Content-Length, Host) are read-only. Playwright will warn if you try to override them.Performance Testing: Mocking Slow Networks
Playwright's browser_context lets you simulate network conditions like offline mode or specific throughput limits — useful for testing how your app degrades gracefully.
Asserting Network Activity: Testing That Requests Were Made
Sometimes you don't need to mock a request — you just need to verify that a specific API call was made with certain parameters. Playwright provides and page.wait_for_request() for this. These are critical for confirming analytics events, logging calls, or form submissions actually fired correctly.page.wait_for_response()
You can combine these with route interception to validate both the outgoing request and the incoming response.
page.wait_for_request() for most test scenarios.route.abort() is too aggressive, the request never reaches the mock handler.page.expect_request() to capture the outgoing request.page.expect_response() to capture the response (mocked or real).Mock Response Shape Mismatch
- Always align mock response structure exactly with the API contract.
- Use TypeScript types or OpenAPI specs as the source of truth for mock shapes.
- Add a test that validates mock response against the real API schema — catch mismatches early.
r.abort()) before any navigation.context.route() to apply a route handler to all pages in the same browser context.Key takeaways
page.route for fine-grained control over individual HTTP requests based on URL patterns.expect_request to verify that the right data was sent.Common mistakes to avoid
4 patternsUsing hardcoded full URL instead of glob pattern
Forgetting to register routes before page navigation
page.route() before page.goto() or before the action that triggers the request. Routes are attached per-page and only intercept future requests.Mocking a response with incorrect Content-Type
route.fulfill() to match the expected MIME type, e.g., content_type='application/json'. Use the browser's network panel to copy the original response headers.Overusing route.continue() without proper handling
route.continue() when you need to modify the request. For most test scenarios, route.fulfill() or route.abort() is sufficient. Reduce the glob pattern scope to avoid intercepting every resource.Interview Questions on This Topic
How does Playwright's network interception differ from using a library like 'Responses' or 'HTTPretty' in Python?
Frequently Asked Questions
That's Python Libraries. Mark it forged?
3 min read · try the examples if you haven't