'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:
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")
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")
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/
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 |