I’m trying to wait for network requests and validate their responses in Playwright. In Cypress, I could easily do:
cy.server();
cy.route('POST', '/api/contacts').as('newContact');
cy.get('.btn').click();
cy.wait('@newContact').then((response) => {
expect(response.status).to.eq(400);
expect(response.responseBody.data.name).to.eq('abcde');
});
But in Playwright, my attempt doesn’t work as expected:
await contacts.clickSaveBtn();
await page.waitForResponse((resp) => {
resp.url().includes('/api/contacts')
expect(resp.status()).toBe(400);
});
The validation triggers for a request sent before clicking the save button, so it doesn’t capture the correct request.
The most reliable approach is to start waiting before the action in a Promise.all, so Playwright knows which request to capture:
const [response] = await Promise.all([
page.waitForResponse(resp => resp.url().includes('/api/contacts') && resp.status() === 400),
contacts.clickSaveBtn(), // action triggers the request
]);
const data = await response.json();
expect(data.name).toBe('abcde');
Key points:
If the request might happen multiple times and you want to handle it dynamically:
page.on('response', async resp => {
if (resp.url().includes('/api/contacts') && resp.status() === 400) {
const data = await resp.json();
expect(data.name).toBe('abcde');
}
});
await contacts.clickSaveBtn();
Key points:
Sometimes you want to capture the exact request first, then validate its response:
const [request, response] = await Promise.all([
page.waitForRequest(req => req.url().includes('/api/contacts') && req.method() === 'POST'),
page.waitForResponse(resp => resp.url().includes('/api/contacts')),
contacts.clickSaveBtn(),
]);
expect(response.status()).toBe(400);
const body = await response.json();
expect(body.name).toBe('abcde');
Key points: