How to wait for requests and validate responses using playwright?
Asked Answered
B

4

22

This is my first time using playwright and I can't figure out how to wait for requests and validate responses. I've been using cypress for a quite a long time, and it was pretty easy to manage network requests. For example, I need to validate response after clicking a button and this is how I would do it with cypress:

        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')
        })

And this is how I'm trying to do the same thing with playwright, but it validates GET request that was sent long before it even clicked save button. I can't figure out how to manage this request properly and that's a show stopper for my test suite:

        await contacts.clickSaveBtn()

        await page.waitForResponse((resp) => {
            resp.url().includes('/api/contacts')
            expect(resp.status()).toBe(400)
        })

Any help or advice would be really appreciated

Barbel answered 24/3, 2021 at 21:25 Comment(0)
A
41

What you need to do is first start waiting for the response and then click, so the waitForResponse() can catch the actual response coming as a result of the click.

await Promise.all([
    page.waitForResponse(resp => resp.url().includes('/api/contacts') && resp.status() === 400),
    contacts.clickSaveBtn()
]);

This should handle the possible race condition.

Amorette answered 25/3, 2021 at 9:27 Comment(1)
I suggest the following update: const [response] = await Promise.all([, because often times you'll want to use the response after it arrives.Thirzi
B
20

Alternatively, you can assign a promise, then later wait for it:

const responsePromise = page.waitForResponse(resp => resp.url().includes('/api/contacts') && resp.status() === 400);
await contacts.clickSaveBtn();
const response = await responsePromise;

It's more readable and you get the response value.

Blanchard answered 26/12, 2022 at 18:53 Comment(0)
H
2

I was looking for the same, this worked for me:

 const response = await page.waitForResponse((response) => response.url().includes("/api/contacts"));
    
     // Assert the response status and body
     const responseBody = await response.json();
     expect(response.status()).toBe(200);
Hibbitts answered 4/4, 2023 at 19:10 Comment(0)
U
0

How about doing it this way?

import { Page } from "playwright";
import _ from 'lodash';

function expectJsonStructure(json: any, structure: any): boolean {
  return _.every(structure, (value, key) => {
    if (_.isString(value)) {
      return _.has(json, value);
    }

    return expectJsonStructure(json[key], value)
  });
}

async function waitForJsonResponse(page: Page, structure: any) {
  const response = await page.waitForResponse(async (response)=> {
    try {
      const json = await response.json();

      return expectJsonStructure(json, structure);
    } catch (error) {
      return false;
    }
  });

  return await response.json();
}


// Example JSON that matches the expected structure:
const exampleJson = {
  data: {
    foo: {
      items: [
        { id: 1, name: "Item 1" },
        { id: 2, name: "Item 2" }
      ],
      total: 2
    },
    bar: {
      items: [
        { id: 3, name: "Item 3" },
        { id: 4, name: "Item 4" },
        { id: 5, name: "Item 5" }
      ],
      total: 3
    }
  }
};

// Usage example
async function performActionAndWaitForResponse(page: Page, element: any) {
  const [, json] = await Promise.all([
    element.click(),
    waitForJsonResponse(page, [
      { data: { foo: ['items', 'total'] } },
      { data: { bar: ['items', 'total'] } },
    ])
  ]);
  
  console.log('Received JSON:', json);
  return json;
}

see link https://gist.github.com/chamyeongdo/cd7b7c0717bfb58548faf2f2be331f49

Utoaztecan answered 25/7, 2024 at 3:42 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Rory

© 2022 - 2025 — McMap. All rights reserved.