'Intercept the same API call multiple times in Cypress

Is it possible to use cy.intercept to intercept the same API call multiple times in the same test? I tried the following:

cy.intercept({ pathname: "/url", method: "POST" }).as("call1")
// ... some logic
cy.wait("@call1")

// ... some logic

cy.intercept({ pathname: "/url", method: "POST" }).as("call2")
// ... some logic
cy.wait("@call2")

I would expect that cy.wait("@call2") would wait for the 2nd time the API gets called. However, the second cy.wait will continue immediately because the first API call is identical to the second one.



Solution 1:[1]

When you set up identical intercepts, the first one will grab all the calls. But you can wait on the first alias multiple times.

Here's a (reasonably) simple illustration

spec

Cypress.config('defaultCommandTimeout', 10); // low timeout
                                             // makes the gets depend on the waits 
                                             // for success

it('never fires @call2',()=>{

  cy.intercept({ pathname: "/posts", method: "POST" }).as("call1")
  cy.intercept({ pathname: "/posts", method: "POST" }).as("call2")

  cy.visit('../app/intercept-identical.html')
  
  cy.wait('@call1')                               // call1 fires 
  cy.get('div#1').should('have.text', '201')

  cy.wait('@call2')                               // call2 never fires
  cy.wait('@call1')                               // call1 fires a second time
  cy.get('div#2').should('have.text', '201')

})

app

<body>
  <div id="1"></div>
  <div id="2"></div>
  <script>

    setTimeout(() => {
      fetch('https://jsonplaceholder.typicode.com/posts', {
        method: 'POST',
        body: JSON.stringify({ title: 'foo', body: 'bar', userId: 1 }),
        headers: { 'Content-type': 'application/json; charset=UTF-8' },
      }).then(response => {
        document.getElementById('1').innerText = response.status;
      })
    }, 500)
  
    setTimeout(() => {
      fetch('https://jsonplaceholder.typicode.com/posts', {
        method: 'POST',
        body: JSON.stringify({ title: 'foo', body: 'bar', userId: 2 }),
        headers: { 'Content-type': 'application/json; charset=UTF-8' },
      }).then(response => {
        document.getElementById('2').innerText = response.status;
      })
    }, 1000)

  </script>
</body>

You can see it in the Cypress log,

command call# occurrence (orange tag)
wait @call1 1
wait @call2
wait @call1 2

Solution 2:[2]

You have many ways to do this:

  1. Create a unique alias for the same endpoint intercepted

    cy.intercept({ pathname: "/posts", method: "POST" }).as("call")
    
    //First Action
    cy.get("button").click()
    cy.wait("@call").its("request.url").should("contain", "somevalue")
    
    //Second Action
    cy.get("button2").click()
    cy.wait("@call").its("request.url").should("contain", "othervalue")
    
  2. Create a specific en endpoint, you can use a glob pattern to generate a dynamic endpoint

    //notice path key instead of pathname
    cy.intercept({path: "/post*parameter1=true", method: "POST"}).as("call1")
    
    //First Action
    cy.get("button").click()
    cy.wait("@call1").its("request.url").should("contain", "somevalue")
    
    cy.intercept({path: "/post*parameter2=false", method: "POST"}).as("call2")
    
    //Second Action
    cy.get("button2").click()
    cy.wait("@call2").its("request.url").should("contain", "othervalue")
    
  3. Validate all endpoints called at the finish

     cy.intercept({ pathname: "/posts", method: "POST" }).as("call")
    
     //First Action
     cy.get("button").click()
     cy.wait("@call")
    
     //Second Action
     cy.get("button2").click()
     cy.wait("@call")
    
     //you can add the number of request at the finish of alias
     cy.get("@call.1").its("request.url").should("contain", "somevalue")
     cy.get("@call.2").its("request.url").should("contain", "othervalue")
    
     //another option instead of add the number of request maybe use the position in letters, but I think that it only works for first and last.
     cy.get("@call.first").its("request.url").should("contain", "somevalue")
     cy.get("@call.last").its("request.url").should("contain", "othervalue")
    

Solution 3:[3]

// wait for 2 calls to complete
cy.wait('@queryGridInput').wait('@queryGridInput')
// get
cy.get("@queryGridInput.all").then((xhrs)=>{});

@alias.all will wait for all the instances to be completed. It will return an array of xhrs containing all the matching @alias.

https://www.cypress.io/blog/2019/12/23/asserting-network-calls-from-cypress-tests/

Cypress: I am trying to intercept the 10 calls which originate from 1 button click but the cy.wait().should is only tapping the last call

Solution 4:[4]

I would have used aliasing on individual requests if your request differ in some way. In my case I made multiple post request to the same route but with a slightly different body. So I ended up doing something like this:

cy.intercept("POST", '/your_route', (req) => {
    if (req.body.hasOwnProperty('your_prop')) {
        req.alias = 'your_alias';
        req.reply(your_response);
    }
});

This will intercept and stub a post request that has a desired property in the body.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 user199960
Solution 3
Solution 4 Hannes Falk