Note:
cy.route2
has been renamed to cy.intercept and became official in Cypress v6.0.0 release.
route
Cypress has two commands for controlling the network during tests: cy.route and newer cy.route2. This blog post explains the difference.
Cypress executes tests in the same browser window as the application itself, just in a different iframe. When loading the application Cypress wraps all methods of the object XMLHttpRequest
. Thus when the application executes new XMLHttpRequest() ...
to fire a network request, Cypress is aware of the network call by the virtue of the application calling the already wrapped methods.
While the above approach works, it is very limited. For example, you could not spy or stub HTTP calls made using fetch
function. If your application was using fetch
and you wanted to observe or control those network calls from your tests you had to either delete window.fetch
and force your application to use a polyfill built on top of XMLHttpRequest, or you could stub the window.fetch
method using cy.stub via Sinon library.
For a short workaround we have implemented automatic fetch
polyfill via experimentalFetchPolyfill option, but this was still not enough. We really wanted to allow the test code to observe, stub, and modify any HTTP request.
route2
Enter route2
- a universal HTTP network control function. It fundamentally is a different beast from route
. It no longer works in the browser - instead the network interception and control happen in the network proxy module outside of the browser. When Cypress launches a browser, it points the browser back at Cypress, so that the browser "thinks" Cypress is its network proxy. You can see this command line switch when running Chrome for example by going to the chrome://version
tab
If Cypress is the proxy for the application, then all HTTP traffic from the application is observable: the page loaded, the static resources like CSS, JavaScript, and images, and any Ajax request, no matter how it is made by the app. You can observe these requests flowing through the proxy module by running Cypress with an environment variable DEBUG
set
1 | DEBUG=cypress:network:* npx cypress open |
The above terminal log shows the application request the document itself, then requesting styles.css
and app.js
resources. These requests all go through the Cypress network proxy module where they can be observed (spied upon), modified (both outgoing and incoming), and stubbed (where the proxy responds with mock data).
🗃 Find the code examples from this post in the "cy.route2" recipe in the cypress-example-recipes
We can modify any request, for example we might want to insert some CSS into the styles.css
during a test
1 | cy.route2('styles.css', (req) => { |
The above code modifies the response from the server by appending an extra CSS rule.
Similarly, it is simple to stub fetch
calls and avoid going to the server completely.
1 | it('shows fruits', function () { |
Even better is to spy on the server's response to make sure both the server responds correctly and the application renders the list the right way.
1 | beforeEach(function () { |
Because we can inspect the request before deciding how to proceed, we can deal with the application's network requests in any way we want. For example, we can create a flexible way to spy on or stub GraphQL requests. Something like this is possible:
1 | const allTodos = [...] |
Read my blog post Smart GraphQL Stubbing in Cypress for details.
You can even rewrite the page itself (using plain text operations, or via bundled Cypress.$)
1 | it('modifies the page itself', () => { |
👏
cy.route2
would not become a reality without hard work by Zach Bloomquist who does not have time to tweet much, but lots of time to code.
See more
- cy.route and cy.route2 API pages
- Cypress Network Requests Guide
- cy.route2 recipe
In the future we plan to retire the original cy.route
and replace it with cy.route2
. We also plan to retire experimentalFetchPolyfill
in favor of cy.route2
.