If you make multiple requests to the same endpoint and want to mock each response differently based on the order that they occur, cypress appears to be unable to do it unless you wait X milliseconds between requests. If there is no pause between requests, cypress will never catch the first cy.wait(...) and will mock every request to that endpoint with the same response.
cy.server()
cy.route(url, res1).as(get)
cy.wait(@get)
cy.route(url, res2).as(get)
Should result in the first GET request to url responding with res1 and the second GET request to url responding with res2, regardless of the amount of time between requests.
Run tests here
I can recreate this behavior in Cypress 3.4.0 with the tests here.
In the example provided, the application does a request every 200ms, and if you want the response to change for each response - like id: 1, id: 2, id: 3, it'll always respond with the first cy.route() response definition, even though you want it to respond with the 2nd at that point. It's almost as if we want to have a waitOnce.

Same. Need a way to specify the response of the Nth request.
Following this as I have the same problem
Following
i'm interested in this one, have anyone found a workaround?
I came up with a really odd way thats solved a similar problem but not quite the same.
In the context of cypress we append an intent queryString so cypress will deem it as different. Note: Depending on how you are triggering these calls will also determine if you can use this.
export function createCypressUrlOrDefault(url, intent) {
if (!url) {
throw Error('Url must be supplied!');
}
if (!intent) {
throw Error('A value must be supplied for intent for cypress stubbing!');
}
if (root.Cypress) {
return `${url}?${intent}`;
}
return url;
}
@bautistaaa @avilaj I considered that too but didn't really want to have the client do different things in test mode. Another option would be to add an artificial delay in the client code (between the requests). Again though that requires special code to run in the client for test mode only which is less than ideal.
@jennifer-shehane any followup on this? Mocking GraphQL calls is near impossible without this.
@lifeiscontent
one way to solve this using Apollo is to change your URL to include the queryname as a param. It allowed me to track requests in Cypress like
cy.route('POST', '**?q=getThing**)
@lifeiscontent if you can add a dummy ?q=${operationName} to all of the calls made by Apollo, you could alias that in Apollo
@aaron-peloquin @btferus5 sure, but that's clearly a hack, I'd expect cypress to have support for this, not having to hack the library, then later once they've figured it out, undo all the hacks.
@lifeiscontent no need to hack the library, it's a built in option using context.
It also gives you better visibility in and outside of Cypress just debugging issues and tracking network requests.
I also don't see how cypress would implement an alternative way to track requests that all share the same URL
Following this issue.
bump
I have the same kind of question.
it('calls the route twice', () => {
// Assign: stub first request
cy.route('POST', `**/employees/options`, 'fixture:employees/options/post-200-unfiltered.json').as('firstRequest')
// Act
cy.openDetail(customerId)
// Assign: Override the route to now only return the filtered options
cy.wait('@firstRequest').then(() => {
// This second request has some filters in the request body
cy.route('POST', `**/employees/options`, 'fixture:employees/options/post-200-filtered-byid.json').as('secondRequest')
})
// Assert
cy.wait('@secondRequest')
})
In this case second request is never asserted. Also without the then-callback it is not fired.

Should be possible to discrimate request with body's content?
Apollo/GraphQL user here too :wave:. I was really surprised this didn't work, because based on the documenation, it should...
https://docs.cypress.io/api/commands/wait.html#Wait-automatically-increments-responses
But in the documentation it's actually make new requests, it's not making multiple XHR calls on page load.
any news?
also experiencing this issue, are there any updates?
anyone able to get around this ?
i have same shit ;/
@jennifer-shehane any updates on this one?
Experiencing same issue. Some updates would be nice.
Jup. Also have this issue. Have a polling service I'm trying to test. Want it to poll a few times, then change the response, and then it should trigger a call to a new endpoint. Doesn't matter what I do, it just returns the original response.
I've run into the same issue and have created a command that supports 2 different methods which should be a good jumping off point for those that need it.
route('POST', url, requestBody => requestBody.property1 == 'something', 'some response')route('POST', url, ...rand(1, 1000)) // some sort of counter endpointFollowing, I'm running into the same issue. Any updates on this?
Following, I am also looking for something similar. need to capture all the traffic having same url.
Following, also got the same problem.
Following, having same issue.
Following, I have the same issue
Also have the same issue!
Following, having the same issue.
Also have the same issue!
@ folks who have the same issue, please don't forget to 馃憤 the OP. It's easier to see how many people are interested in this by seeing the 馃憤 number. It's also pretty difficult to read the comment discussion if all we see is rounds and rounds of "me too" "me too".
This works for me
cy.wait("@Request1");
cy.wait("@Request2");
cy.wait(0);
cy.wait("@Request2");
Any progress on this issue? This is kind-of a big deal.
It would be a non-breaking change to introduce a new cy-route-like API such as cy.listen(...) and cy.unlisten(...) that has the ability to:
Also joining to the above requests. This is a very basic requirement that has gone unanswered for a long time it seems (saw other issues opened years ago).
I found a (very ugly) workaround for my need to respond with a different header to requests made to the same URL in quick succession. This is very specific but can be changed to match other needs.
let reqCount = 0;
const createUrls = ["123", "456"];
cy.route({
method: "POST",
url: "http://test.com/upload",
response: { success: true },
headers: {},
onResponse: (xhr) => {
let closureCounter = reqCount;
reqCount+=1;
const orgGetHeader = xhr.xhr.getResponseHeader;
xhr.xhr.getResponseHeader = (name) => {
return (name === "Location") ?
`http://test.com/upload/${createUrls[closureCounter]}` :
orgGetHeader.call(this, name);
};
},
}).as("createReq");
Hopefully cypress can add this very needed functionality soon so ugly hacks like these can be removed...
Same issue, unable to identify the same request (even with little differences) with different aliases.
Right now, the hack I found was to add a delay between my requests in my application code following the example here
same here, i have to same url called twice but it still picking up the 1st one when i do the then statement:
json1 = { test: one}
json 2= { test: two}
beforeEach('', () => {
cy.server();
cy.route('GET', 'url' , json1 ).as(getItem)
})
it('test1', () =>{}
cy.route('GET', 'url' , json2 ).as(getItem)
cy.get('button).click()
cy.wait('@geitem).then((xhr) => {
console.log (xhr.response.body[test])
// this test would display one instead of two.
})
This works for me:
cy.route('POST', '**/app/globalSearch', 'fixture:globalSearchErr.json').as('error')
cy.get('#searchInput')
.type('1234567890 {enter}')
.wait(['@error'])
cy.route('POST', '**/app/globalSearch', 'fixture:globalSearch.json').as('success')
cy.get('#searchInput')
.type('1762336105094 {enter}')
cy.wait(['@success'])
Really looking forward to a fix for this as I'm trying to test an API client that automatically refreshes a JWT upon failure. I need to mock the same endpoint with the exact same data twice so I can make it fail the first time and succeed the second.
Does anyone have a solution for this, i am trying to stub different responses for same url but its always taking the first one.
@jennifer-shehane Are we targetting this one for any release?
Ran into this problem as well. Need to be able to mock Nth request per route. Can we expect to see a solution in the foreseeable future?
I was able to modify response content from the same URL. I was tapping into that URL in question during page load but my second cy.visit() was getting the same response as the first one. The solution was to reload the page like so :
// cy.route() with first response with '@alias'
// cy.route() with second response
...
cy.visit(MY_PAGE);
// flushing first request to resource availabilities and reloading for the new response.
cy.wait('@alias');
cy.reload();
I want to make multiple requests to the same endpoint but having different response:
cy.route("POST", "/api/v1/resource_package_deploy", {
code: 1,
msg: "Fail",
}).as("stubbedError");
cy.route("POST", "/api/v1/resource_package_deploy", {
code: 0,
msg: "Success",
}).as("stubbedDeploy");
cy.visit("/maintenance/resourceManagement");
cy.get("[data-cy-deployBtn=pkg02]").click();
cy.get("[data-cy=robot-cb]")
.first()
.find("input.mat-checkbox-input")
.check({ force: true });
cy.get("[data-cy=robot-cb]")
.eq(2)
.find("input.mat-checkbox-input")
.check({ force: true });
cy.get("[data-cy=deploy-submit]").click();
cy.wait("@stubbedError");
cy.wait("@stubbedDeploy");
But I got a timeout on waiting for the first request. How do I fix this?
I used the suggestions in this thread to write a blog post with something I hope is reusable across projects. Please take a look:
https://medium.com/life-at-paperless/cypress-graphql-response-mocking-7d49517f7754
This works for me:
cy.route('POST', '**/app/globalSearch', 'fixture:globalSearchErr.json').as('error') cy.get('#searchInput') .type('1234567890 {enter}') .wait(['@error']) cy.route('POST', '**/app/globalSearch', 'fixture:globalSearch.json').as('success') cy.get('#searchInput') .type('1762336105094 {enter}') cy.wait(['@success'])
U saved my life!! It worked for me too
Most helpful comment
@ folks who have the same issue, please don't forget to 馃憤 the OP. It's easier to see how many people are interested in this by seeing the 馃憤 number. It's also pretty difficult to read the comment discussion if all we see is rounds and rounds of "me too" "me too".