Q19 of 42 · Playwright

What is the difference between page.waitForResponse and page.waitForRequest?

PlaywrightMidplaywrightnetworkwait-for-responserace-conditionsmid

Short answer

Short answer: `waitForRequest` resolves when a matching request is *sent*. `waitForResponse` resolves when a matching response is *received*. Pair either with the action that triggers the request inside `Promise.all` to avoid a race where the request happens before the wait registers.

Detail

Both methods watch the network for a matching event. The crucial difference is which event:

  • page.waitForRequest(predicate) — fires when the request leaves the browser. Useful for asserting that the app makes the right request.
  • page.waitForResponse(predicate) — fires when the response comes back. Useful when you need the response body or status.

The race trap: if you call waitForResponse after the action that triggers the request, the request may already be in flight or completed. The wait then hangs until timeout. Fix with Promise.all:

// ❌ Possible race
await page.click('[data-test=submit]');
const response = await page.waitForResponse('**/api/orders'); // may have already happened

// ✅ Register first, click second, await both
const [response] = await Promise.all([
  page.waitForResponse('**/api/orders'),
  page.click('[data-test=submit]'),
]);

Predicate forms:

// String — glob match on URL
await page.waitForResponse('**/api/orders');

// Regex
await page.waitForResponse(/\/api\/orders/);

// Function — fine-grained
await page.waitForResponse(
  (res) => res.url().includes('/api/orders') && res.status() === 200,
);

Asserting on the result:

const response = await page.waitForResponse('**/api/orders');
expect(response.status()).toBe(201);
const body = await response.json();
expect(body.orderId).toBeDefined();

waitForRequest for write-side asserts:

const [request] = await Promise.all([
  page.waitForRequest('**/api/orders'),
  page.click('[data-test=submit]'),
]);
expect(request.method()).toBe('POST');
expect(request.postDataJSON()).toEqual({ items: [...] });

The senior signal: knowing the race pattern and the Promise.all fix; recognising that waitForResponse is more common but waitForRequest is the right tool for asserting on outgoing payloads.

// WHAT INTERVIEWERS LOOK FOR

Knowing the race trap, the `Promise.all` fix, and when to use each (response for status/body, request for outgoing payload).

// COMMON PITFALL

Calling `waitForResponse` after the trigger action and ending up with timeouts because the network event already fired.