Playwright Cheatsheet
Network Mocking
Use this Playwright reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
route() — intercept & mock
// Abort a request await page.route('**/api/ads', route => route.abort()); // Fulfill with mock data await page.route('**/api/users', async route => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([{ id: 1, name: 'Alice' }]), }); }); // Modify the request before it goes out await page.route('**/api/**', async route => { const headers = { ...route.request().headers(), 'X-Custom': 'value' }; await route.continue({ headers }); }); // Modify the response await page.route('**/api/data', async route => { const response = await route.fetch(); const json = await response.json(); json.extra = 'injected'; await route.fulfill({ response, json }); });
route.fulfill() options
| Option | Type | Description |
|---|---|---|
status | number | HTTP status code |
headers | Record<string, string> | Response headers |
contentType | string | Content-Type header shorthand |
body | string | Buffer | Response body |
json | unknown | JSON body (sets Content-Type automatically) |
path | string | Path to a file to use as body |
response | Response | Base on a real response |
route.continue() options
| Option | Type | Description |
|---|---|---|
url | string | Override URL |
method | string | Override HTTP method |
headers | Record<string, string> | Override headers (replaces all) |
postData | string | Buffer | Override POST body |
URL matching patterns
// Exact URL await page.route('https://example.com/api', handler); // Glob patterns await page.route('**/api/**', handler); // ** = any path segment(s) await page.route('**/api/*.json', handler); // Regex await page.route(/\/api\/users\/\d+/, handler); // Custom predicate function await page.route(url => url.hostname === 'api.example.com', handler);
Mocking from a HAR file
// Record a HAR during a test await page.routeFromHAR('example.har', { update: true }); // Replay (serve from HAR, never hit the network) await page.routeFromHAR('example.har'); await page.routeFromHAR('example.har', { url: '**/api/**', // only mock matching URLs notFound: 'abort', // 'abort' | 'fallback' (default: 'abort') });
Record a HAR from CLI
npx playwright open --save-har=example.har --save-har-glob='**/api/**' https://example.comcontext-level routing (all pages in context)
await context.route('**/api/**', async route => { await route.fulfill({ json: { mocked: true } }); }); // Applies to every page opened in this context
Removing a route
const handler = async (route: Route) => route.abort(); await page.route('**/ads/**', handler); // ... test await page.unroute('**/ads/**', handler); await page.unroute('**/ads/**'); // remove all handlers for this pattern
Intercepting WebSockets
page.routeWebSocket() (v1.48+) intercepts connections before they are made — the mock replaces the real server:
// Mock: the page never connects to the real server await page.routeWebSocket('wss://example.com/ws', ws => { ws.onMessage(message => { if (message === 'ping') ws.send('pong'); }); }); // Proxy: connect to the real server, intercept/modify frames await page.routeWebSocket('wss://example.com/ws', ws => { const server = ws.connectToServer(); ws.onMessage(message => server.send(message)); // client -> server server.onMessage(message => ws.send(message)); // server -> client });
Passive inspection (no interception)
page.on('websocket', ws => { console.log(`WebSocket opened: ${ws.url()}`); ws.on('framesent', frame => console.log('sent:', frame.payload)); ws.on('framereceived', frame => console.log('recv:', frame.payload)); ws.on('close', () => console.log('WebSocket closed')); });
Inspecting requests & responses
// Listen to all requests page.on('request', request => { console.log(request.method(), request.url()); console.log(request.headers()); console.log(request.postData()); }); page.on('response', response => { console.log(response.status(), response.url()); }); page.on('requestfailed', request => { console.log('FAILED:', request.failure()?.errorText); }); page.on('requestfinished', request => { const timing = request.timing(); console.log('dns:', timing.domainLookupEnd - timing.domainLookupStart); });
Waiting for specific requests
const [request] = await Promise.all([ page.waitForRequest('**/api/submit'), page.locator('#submit').click(), ]); console.log(request.postDataJSON()); const [response] = await Promise.all([ page.waitForResponse(res => res.url().includes('/api/data') && res.ok()), page.locator('#load').click(), ]); const data = await response.json();
API testing with request fixture
test('API test', async ({ request }) => { const response = await request.get('https://api.example.com/users'); expect(response.ok()).toBeTruthy(); const body = await response.json(); expect(body).toHaveLength(5); }); test('POST request', async ({ request }) => { const response = await request.post('/api/users', { data: { name: 'Alice', email: 'alice@example.com' }, }); expect(response.status()).toBe(201); });
APIRequestContext methods
| Method | Description |
|---|---|
request.get(url, opts?) | GET |
request.post(url, opts?) | POST |
request.put(url, opts?) | PUT |
request.patch(url, opts?) | PATCH |
request.delete(url, opts?) | DELETE |
request.head(url, opts?) | HEAD |
request.fetch(url, opts?) | Arbitrary method |
request.dispose() | Dispose context |
Request options
await request.post('/api/users', { data: { name: 'Alice' }, // JSON body (auto content-type) form: { key: 'value' }, // application/x-www-form-urlencoded multipart: { file: fs.createReadStream('photo.jpg') }, headers: { Authorization: 'Bearer token' }, timeout: 5000, params: { page: 1, limit: 20 }, // query string failOnStatusCode: true, // throw if status >= 400 });
Seeding localStorage / sessionStorage
// Before any page script runs (applies to every future navigation) await page.addInitScript(() => { localStorage.setItem('featureFlags', JSON.stringify({ newUI: true })); }); await page.goto('/'); // On the live page, after load await page.evaluate(() => { sessionStorage.setItem('token', 'test-token'); });
Throttling network speed
// Via CDP (Chromium only) const client = await page.context().newCDPSession(page); await client.send('Network.emulateNetworkConditions', { offline: false, downloadThroughput: (500 * 1024) / 8, // 500 kb/s uploadThroughput: (500 * 1024) / 8, latency: 150, });