-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Cypress 6.0.0] Overriding interceptors doesn't work. #9302
Comments
I was really excited to use the new |
I believe this is the crux of the issue cypress/packages/net-stubbing/lib/server/route-matching.ts Lines 110 to 116 in 197f309
Assuming I understand everything correctly - it looks like the order by which the routes are being matched is the original order they're pushed in. Changing the code to this might solve it export function getRouteForRequest (routes: BackendRoute[], req: CypressIncomingRequest, prevRoute?: BackendRoute) {
const possibleRoutes = prevRoute ? routes.slice(_.findIndex(routes, prevRoute) + 1) : routes
- return _.find(possibleRoutes, (route) => {
+ return _.find(possibleRoutes.slice().reverse(), (route) => {
return _doesRouteMatch(route.routeMatcher, req)
})
} From what I could tell, previously it let the driver do this matching instead cypress/packages/driver/src/cypress/server.js Lines 268 to 277 in 197f309
Unfortunately, I don't have much time setting up a local environment to test & verify that it's indeed the issue - if anyone wants to do it they're more than welcome to use my code diff :) |
This issue blocks me to update to 6.0.0 version |
Just wanted to add that I am also blocked from updating due to this. |
@Romanchuk @ThatGuyHS this shouldn't block you from upgrading to 6.0.0, using |
@flotwig Yes, but for me |
+1 Once cy.intercept() is declared for some route, you can not override its behaviour. It is quite annoying and until fixed will block me to update since we usually mock a '200' response, but we also need to test other ones. Looking forward a pull request to fix it. |
We are currently looking into ways to make this possible with |
For the future, it would be useful to mention this critical breaking change in your CHANGELOG or migration guides. All of these resources imply that
There is nothing indicating the issues mentioned in this thread. I recommend you adjust both articles above and mention this difference for others attempting to upgrade. |
It is indeed a huge blocker. And what @samijaber said: Inability to overwrite or clear an interceptor should be explicitly stated in the docs. In my case, I am testing my application to re-authenticate after a failing request and then to retry that failed request with the new credentials. No way to do that if I cannot override or clear the previous interceptor. |
It also breaks the below cases which were working with cy.route(): Before:
After:
Before:
After:
though it's working fine with below code:
but not with this:
Also, is there any way to get the last call of the same endpoint? something like this:
|
Huge thanks for the Cypress team for all of their hard work on this and other new features. Complex feature changes and new APIs always have some rough edges. Always impressed with the quality of your work. 👏 |
@manojhans The issue with cy.get() returning null was fixed in 6.2.0: #9306 |
Thanks @jennifer-shehane. It's working fine in 6.2.0 |
The tests are still failing, because we can't redefine the intercept of the config. A workaround needs to be looked for. See issue: cypress-io/cypress#9302 Signed-off-by: Erik Michelson <[email protected]>
- Replace cy.route() commands with cy.intercept() alternative - Removed cy.server() commands - Add a 'cy.dynamicIntercept()' command to save and overwrite network mocks. For more details, see issue cypress-io/cypress#9302 Signed-off-by: Davide Briani <[email protected]>
This would seriously help us loads with our suite. Our example is a graphql single endpoint, and I want to change certain responses dependent on when we fire mutations. e.g. when we load a table, load with intiial mock data, after firing a successful create record mutation then responding with a new set of mock data to include that record. Structure wise within our tests and app I'm really happy with it, it just all relies on this being possible! |
If you want to make the answer dependent on the parameter value, this example might be helpful too:
The way to extract q parameter may differ depending on how it was passed. |
The tests are still failing, because we can't redefine the intercept of the config. A workaround needs to be looked for. See issue: cypress-io/cypress#9302 Signed-off-by: Erik Michelson <[email protected]>
I'm in the processes of doing a user-land workaround but it's still not fully functional. // This is called from the `support/index.js` file
beforeEach(() => {
const staticMimeTypes = ['text/css', 'text/html', 'text/javascript', 'font/otf', 'font/ttf', 'font/woff', 'font/woff2', 'image/avif', 'image/webp', 'image/apng', 'image/svg+xml', 'image/*'];
const staticFileExtensions = ['\\.html$', '\\.css$', '\\.js$', '\\.map$', '\\.md$', '\\.woff$', '\\.woff2$', '\\.ttf$', '\\.eot$', '\\.jpg$', '\\.jpeg$', '\\.png$', '\\.svg$'];
const methods = ['GET', 'POST', 'DELETE', 'PUT', 'PATCH', 'OPTIONS'];
const ignoredDomains = ['content-autofill.googleapis.com', 'safebrowsing.googleapis.com', 'accounts.google.com', 'clientservices.googleapis.com'];
cy.intercept({
url: /.*/,
}, (req) => {
if (staticMimeTypes.some(mime => (req.headers.accept || '').includes(mime))
|| staticFileExtensions.some(extension => req.url.match(extension))
|| ignoredDomains.some(url => req.url.includes(url))
|| !req.method
|| methods.every(method => req.method !== method)) {
req.reply();
} else {
const mocks = cy.state('__INTERNAL_MOCK_DEFINITIONS__');
const mock = mocks.find(mock => mock.method === req.method && Cypress.minimatch(req.url, mock.url));
if (mock) {
req.reply(mock.status, mock.response);
} else {
throw new Error(`Route not stubbed.\nPlease add a cy.route() for url: "${req.url}" and method "${req.method}".`)
}
}
});
}); Then, I also have a Cypress.Commands.add('mock', { prevSubject: true }, ({ method, url, response, status, headers }) => {
cy.state('__INTERNAL_MOCK_DEFINITIONS__', [{
method: method || 'GET',
url,
response,
status,
headers
}].concat(cy.state('__INTERNAL_MOCK_DEFINITIONS__') || []));
}); this allows me to do something like this: cy.wrap({
method: 'POST',
url: '**/login',
status: 200,
response: {
data: {}
},
}).mock(); The reason this "works" is because I have just one route handler that matches everything, then, in that handler I check the routes defined through There are problems though, as you can see, there are a bunch of urls I need to ignore because they're called by the browser itself that for some reason are also being intercepted here 😳 In addition, sometimes requests aren't being intercepted here even though they should, and it passes through to the underlying server. (in my case the server doesn't actually know about these routes and it responds with a 404). Also, it looks like it needs to "warm up" because when I use If anyone makes progress with this kind of workaround I'd be happy to know about :) |
How about this quick monkey patch to solve the issue until an official solution is provided? Works for me with 6.6.0. Just put the following into your commands.js. Not sure about side effects but studying the code did not reveal any downsides of implementing a Assume you have defined your intercept as follows
and calling it like that
then you can clear it with
Here is the command
Update: This does not quite work as expected in all cases. Needs more investigation as more elements of the state seem to be touched. |
cy.route has been deprecated in cypress 6.0 in favor of cy.intercept and will be removed soon. So migrate code stubbing network requests to the intercept API. The only drawback of the intercept API is that currently stubbed responses can not be overridden but hopefully a simple workaround can be used (see cypress-io/cypress#9302).
(11th December 2020) At this point in time, are you able to say wether interceptors will eventually get overriding behaviour @jennifer-shehane? I am asking because this issue is preventing us from rolling out some internal tooling using |
We've been running into this problem as well - trying to return different stubs for the same request, so we can test different responses. Our solution is to use In it('should return response One', () => {
Cypress.config('request_type', 'type_one');
cy.visit('/some-page'); // This page makes a GET call to /some-api-route
cy.wait('@getResponseOne');
});
it('should return response Two', () => {
Cypress.config('request_type', 'type_two');
cy.visit('/some-page'); // This page makes a GET call to /some-api-route
cy.wait('@getResponseTwo');
}); And in our cy.intercept(
{
url: '/some-api-route',
method: 'GET',
},
(req) => {
const requestType = Cypress.config('request_type');
if (requestType === 'type_one') {
req.alias = 'getResponseOne';
req.reply({ fixture: 'response-one.json' });
} else if (requestType === 'type_two') {
req.alias = 'getResponseTwo';
req.reply({ fixture: 'response-two.json' });
}
},
); Values set by Hopefully there will be a way to clear/override intercepts introduced soon, but until then this method seems to work well for us! |
Is the improvement already being worked on in PR #14543 ? |
@FrancoisCamus indeed :) Feel free to take a look at the issue comment in #14543 and let me know if it will cover your needs. |
What about this workaround? is working for me with cypress 6.2.0
|
Cypress v6 doesn't support overriding `cy.intercept` routes. Instead, we have to define them individually within each tests that they're referenced in order to prevent scope issues. See: cypress-io/cypress#9302
In my case using a global variable to change the fixture wasn't a solution, as I need to return a different fixture in the same test (I tried with @chris5marsh and @ejpg solutions with no luck). What works for me is using a
|
@Tintef What works for me is using a global variable and changing it from within the test (in a 'then' callback) let fixture = 'default'
beforeEach(() => {
cy.intercept('url', (req) => {
req.reply((res) => {
res.send({ fixture: fixture });
});
});
});
it('test', () => {
// fixture is 'default'
cy.get('button.submit').then(() => {
fixture = 'other_fixture';
});
// fixture is 'other_fixture'
}); |
@LirSegev That didn't work for me for some reason 🤷♂️ Anyway, I ended up not using |
My way to workaround this for now is creating two global vars, one for the response itself and another to change the httpStatus. let flag = false
let httpStatus = 200
describe('testing the page', () => {
it('should verify something', () => {
cy.intercept('/flag', (req) => {
req.reply((res) => {
res.send(httpStatus, {
successful: true,
flag
})
flag = true
httpStatus = 202
})
})
// The test which need two different values from /flag request
})
}) |
The code for this is done in cypress-io/cypress#14543, but has yet to be released. |
Released in This comment thread has been locked. If you are still experiencing this issue after upgrading to |
Current behavior
With Version <6.0.0, if you used
c.route
with a stub, you could then use it again with a new stub and it would take the second fixture for the second request.With version >6.0.0 It doesn't happen, the override doesn't work with
cy.intercept
and it always returns the initial fixture.The use case is very simple.
Imagine my app loads with 0 items, using a GET.
Then, I do some stuff, do a POST, and then GET those items again.
I want to stub it with
[item]
, instead of the initial[]
.So what happens is that it always return
[]
, not[item]
as it used to.I'm quite sure it's not a problem with my code, used to work perfectly fine till today.
The first image is the initial intercept, you can see it gets


2
The second image is what is shown for the second GET, the one that should've matched and return
[item]
Desired behavior
I want to be able to override interceptors
The text was updated successfully, but these errors were encountered: