Playwright Network Interception and Mock |
\\n\\nThis chapter introduces how to use Playwright to intercept, modify, and mock network requests, enabling independent testing without relying on backend APIs.
\\n\\n\\n\\n
What is Network Interception?
\\n\\nNetwork interception allows you to intervene when the browser initiates HTTP requests.
\\n\\nYou can block requests, modify responses, or return mock data, making tests independent of external APIs or network conditions.
\\n\\n\\n\\n
Intercepting Requests with page.route()
\\n\\npage.route(url, handler) intercepts all network requests matching the specified URL pattern.
Basic Interception
\\n\\nExample
\\n\\ntest('Intercept all image requests', async ({ page })=>{\\n\\n// Intercept all PNG and JPEG images\\n\\n await page.route('**/*.{png,jpg,jpeg}', route => route.abort());\\n\\n// Navigate to the page (images will not be loaded)\\n\\n await page.goto('');\\n\\n// Page may load faster since images are not downloaded\\n\\n});\\n\\nURL matching patterns support the following formats:
\\n\\n| Pattern | \\nExample | \\nDescription | \\n
|---|---|---|
| Full URL | \\n'https://api.example.com/users' | \\n Exact match | \\n
| Glob wildcard | \\n'**/api/**' | \\n ** matches any path | \\n
| Regular expression | \\n//api/vd/users/ | \\n Flexible matching | \\n
| Function | \\nurl => url.includes('/api/') | \\n Programmatic logic matching | \\n
\\n\\n
route.abort() β Blocking Requests
\\n\\nExample
\\n\\ntest('Block third-party analytics scripts', async ({ page })=>{\\n\\n// Block analytics scripts like Google Analytics\\n\\n await page.route('**/*analytics*', route => route.abort());\\n\\n// Block CSS files\\n\\n await page.route('**/*.css', route => route.abort());\\n\\nawait page.goto('');\\n\\n// Page loads without styles, but functionality testing remains unaffected\\n\\n});\\n\\n\\n\\n
route.fulfill() β Mocking Responses
\\n\\nroute.fulfill() is the most powerful mocking method, allowing you to return any custom response.
Mocking JSON Data
\\n\\nExample
\\n\\ntest('Mock Users List API', async ({ page })=>{\\n\\n// Intercept the users list API and return mock data\\n\\n await page.route('**/api/users', async route =>{\\n\\n await route.fulfill({\\n\\n status:200,\\n\\n contentType:'application/json',\\n\\n json:[\\n\\n{ id:1, name:'tutorial_user', email:'user@'},\\n\\n{ id:2, name:'test_user', email:'test@'},\\n\\n],\\n\\n});\\n\\n});\\n\\nawait page.goto('');\\n\\n// Page displays mock data instead of real API data\\n\\n});\\n\\nMocking Error Responses
\\n\\nExample
\\n\\ntest('Test API error handling', async ({ page })=>{\\n\\n// Simulate a 500 server error\\n\\n await page.route('**/api/data', async route =>{\\n\\n await route.fulfill({\\n\\n status:500,\\n\\n contentType:'application/json',\\n\\n json:{ error:'Server Internal Error'},\\n\\n});\\n\\n});\\n\\nawait page.goto('');\\n\\n// Verify that the error message is displayed correctly\\n\\n await expect(page.getByText('Server Internal Error')).toBeVisible();\\n\\n});\\n\\n\\n\\n
route.continue() β Modifying and Continuing
\\n\\nInstead of directly returning mock data, this method modifies the actual request or response before forwarding it to the server.
\\n\\nExample
\\n\\ntest('Modify request headers', async ({ page })=>{\\n\\n await page.route('**/api/**', async (route, request)=>{\\n\\n// Modify request headers, adding a custom header\\n\\nconst headers ={\\n\\n ...request.headers(),\\n\\n'X-Custom-Header':'TUTORIAL-TEST',\\n\\n};\\n\\n await route.continue({ headers });\\n\\n});\\n\\nawait page.goto('');\\n\\n});\\n\\ntest('Modify POST data', async ({ page })=>{\\n\\n await page.route('**/api/login', async (route, request)=>{\\n\\n// Override the POST request body\\n\\nconst postData = JSON.parse(request.postData()||'{}');\\n\\n postData.mode='test';// Add test flag\\n\\n await route.continue({\\n\\n postData: JSON.stringify(postData),\\n\\n});\\n\\n});\\n\\n});\\n\\n\\n\\n
route.fetch() β Making Real Requests
\\n\\nInside a mock handler, you can use route.fetch() to send the actual request and retrieve the real response, then modify it.
Example
\\n\\ntest('Modify real response', async ({ page })=>{\\n\\n await page.route('**/api/products', async route =>{\\n\\n// First, fetch the real response\\n\\nconst response = await route.fetch();\\n\\nconst body = await response.json();\\n\\n// Modify the response data\\n\\n body.items.name='TUTORIAL Modified Product Name';\\n\\n// Return the modified data\\n\\n await route.fulfill({\\n\\n status: response.status(),\\n\\n contentType:'application/json',\\n\\n json: body,\\n\\n});\\n\\n});\\n\\n});\\n\\n\\n\\n
Context-Level vs Page-Level Interception
\\n\\n| Method | \\nScope | \\nUse Case | \\n
|---|---|---|
page.route() | \\n Only the current page | \\nNetwork mocking for a single page | \\n
context.route() | \\n All pages within the context | \\nShared mocking rules across multiple pages | \\n
Example
\\n\\ntest.beforeEach(async ({ context })=>{\\n\\n// Intercept at the context level; applies to all pages\\n\\n await context.route('**/*.css', route => route.abort());\\n\\n});\\n\\ntest('Test 1', async ({ page })=>{/* No CSS */});\\n\\ntest('Test 2', async ({ page })=>{/* No CSS */});\\n\\n\\n\\n
HAR File Recording and Playback
\\n\\nHAR (HTTP Archive) files can record all network requests made by a page, and then replay them for mocking.
\\n\\nExample
\\n\\ntest('Mock using HAR file', async ({ page })=>{\\n\\n// Load and replay network records from a HAR file\\n\\n await page.routeFromHAR('tests/hars/api-responses.har');\\n\\nawait page.goto('');\\n\\n// All matching requests will get responses from the HAR file\\n\\n});\\n\\n# Record HAR file\\nnpx playwright open --save-har=tests/hars/api-responses.har \\n\\nHAR files are ideal for mocking large or complex API responses. Record once, then replay during testsβno dependency on the real server.
YouTip