Stubbing Responses With Cypress
Tools can be used in various ways in testing. Some of them are better than others. I do not mandate writing too many checks, but I like tools because they can help me become a more powerful tester. One of the useful ways in which I can use Cypress is stubbing network responses.
First of all, what am I talking about? Let’s suppose you test an application where there’s a frontend app written in JS (most likely some framework like Vue.js), and a backend REST API service that provides the business logic for the frontend app. If I attempt to draw it, it can look like this:

FE and BE applications talk to each other via HTTP protocol. An example could be the following request and response:
POST /api/login HTTP/1.1
Accept: application/json
Content-Type: application/json
User-Agent: PostmanRuntime/7.28.4
Cache-Control: no-cache
Host: localhost:3000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 65
{
"email": "samanpavel@test.io",
"password": "12345a"
}
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
x-powered-by: Express
vary: Origin, Accept-Encoding
access-control-allow-credentials: true
cache-control: no-store, no-cache, must-revalidate, proxy-revalidate
pragma: no-cache
expires: 0
surrogate-control: no-store
x-content-type-options: nosniff
content-type: application/json; charset=utf-8
content-length: 206
etag: W/"ce-yeRVTu3ODNSmqUtpXfm7BjGjoeE"
date: Sun, 21 Nov 2021 11:47:34 GMT
connection: close
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNhbWFucGF2ZWxAZ21haWwuY29tIiwiaWF0IjoxNjM3NDk1MjU0LCJleHAiOjE2Mzc0OTg4NTQsInN1YiI6IjEifQ.3vlfxdeOZaOG6yQ-aUjhKlS1lK5OdQ7Yu-6ei9g1JX4"
}
When the FE app receives a response, it will (most likely) react to it somehow, do what it’s programmed to do.
All this is a fairly straighforward scenario. But what if something goes wrong on the backend? There are multiple scenarios when the server will return a different response than 200 OK with an access token, e.g. the user does not exist, or I do not send a correct password, or I send no password at all.
Many of these alternative scenarios could be easily tested using the real server. If I want to test that a user does not exist, I simply ask for a user that does not exists in the database.
But how about if I want to test that an error occured on the server? How can I make the server respond with something like the following status code?
HTTP/1.1 500 Internal Server Error
That’s much harder to do with a real server, because in an ideal situation, the server will never return 500. Returning 500 is like saying “there was an error, but we didn’t know what to do with it, so here is 500 and deal with it yourself”.
Having said that, you will likely not be able to find a request that causes the server to return 500. But you still want to test this, because you’re testing the frontend app now and in the unlikely situation when the server does return 500, you want to know that the frontend app reacts to it in a sensible way and for example shows a meaningful message to the user.
This is a situation when tools become useful. Let’s have a look at how to use Cypress for this.
Cypress has a useful command cy.intercept()
that is worth looking at. One of the uses is it can substitute the real server responses with whatever you define instead:
cy
.fixture('credentials')
.then(user => {
cy
.intercept('POST', /api\/login/, {
statusCode: 500,
});
cy
.fillInLoginForm(user);
cy
.get('[data-cy=login-submit]')
.click();
cy
.contains('There was an error, please try later')
.should('be.visible');
cy
.url()
.should('match', /login$/);
});
Notice how the 3rd argument to cy.intercept()
is an object where I define what status code I want Cypress to return. That’s exactly it.
cy
.intercept('POST', /api\/login/, {
statusCode: 500,
});
This means Cypress will tap into the communication between the frontend and backend and if it finds a request to POST api/login endpoint, it will substitute the real status code with 500 status code and eventually return it to the frontend app.
What I achieved here in a few characters is (in an ideal situation) something I’d never be able to achieve with a real backend.
This is called stubbing and you can definitely find more information in Cypress documentation. From my own experience, this is an ideal approach in situations where:
- I want to test the frontend,
- and it’s difficult to make the real server respond with a certain data or status code.
In other words, it’s likely to be an uncommon situation I want to experiment with. On the other hand, it’s important to be aware of the fact that by using this approach, you’re not testing the backend, nor are you performing an intergation testing, both of which are important should the final product bring value to somebody.