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

OptionTypeDescription
statusnumberHTTP status code
headersRecord<string, string>Response headers
contentTypestringContent-Type header shorthand
bodystring | BufferResponse body
jsonunknownJSON body (sets Content-Type automatically)
pathstringPath to a file to use as body
responseResponseBase on a real response

route.continue() options

OptionTypeDescription
urlstringOverride URL
methodstringOverride HTTP method
headersRecord<string, string>Override headers (replaces all)
postDatastring | BufferOverride 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.com

context-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

MethodDescription
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,
});