How to use stub multiple API requests dynamically in Cypress
Tags: testing, frontend, cypress, javascript
Published: 2020-02-12 20:11:00

---
title: How to use stub multiple API requests dynamically in Cypress
published: true
description: 
tags: testing, frontend, cypress, javascript
---

**Update**: You can now to this with Cypress new `intercept` command 🎉: https://www.cypress.io/blog/2020/11/24/introducing-cy-intercept-next-generation-network-stubbing-in-cypress-6-0/

------

Recently, as part of refactoring on how we handle mocking Cypress network request, I had to find a way to mock the same request made multiple times but with different responses in our test suite.

At the moment, with Cypress, there is no way you can make the mock results dynamic depending on what was requested.

### The problem

We have a POST request made to a very simple endpoint. Depending on the request, we get different results.

We already have a very long file with non-formatted JSON responses that are linked to the request using a matching object to match the request payload to a specific answer dynamically. So we already have some of the logic here, which will take ages to extract or break down. Ideally, we want to reuse this.

Some of the cypress default commands were overwritten ( `routes` and `visit`) to handle this case, as well as mocking fetch.

We moved away from this and removed those to use the default cypress commands. We are using the trick describe [here](https://dev.to/mjsarfatti/how-to-test-your-fetch-requests-with-cypress-bh5) to mock fetch. Now we need to handle the dynamic stubbing part as well.
### The solution

This is inspired from a comment on this [Cypress issue on GitHub](https://github.com/cypress-io/cypress/issues/521#issuecomment-427472588) related allowing dynamic stubbing.

We have added a new command to mock request to our endpoint dynamically on-demand using [xhook](https://github.com/jpillora/xhook) (library to intercept and modify XHR request and responses) :

```js
// commands.js 
    Cypress.Commands.add('mockArticlesRequest', () => {
      Cypress.once('window:before:load', window => {
        const script = window.document.createElement('script');
        script.onload = function() {
          window.xhook.after((request, response) => {
            const { method, url, body } = request;
            if (
              method === 'POST' &&
              (url.endsWith('/articles'))
            ) {
              const articlesResponses = require('../fixtures/responses.json');
              const parsedBody = JSON.parse(body);
              const newResponse = articlesResponses.find(({ matches }) =>
                Object.keys(matches).every(
                  key =>
                    JSON.stringify(parsedBody[key]) === JSON.stringify(matches[key])
                )
              );
              if (!newResponse) {
                return;
              }
              response.data = JSON.stringify(newResponse.response);
              response.text = JSON.stringify(newResponse.response);
            }
          });
        };
        script.src = '//unpkg.com/xhook@latest/dist/xhook.min.js';
        script.id = 'xhook';
        window.document.head.appendChild(script);
      });
    });
```

I'm using `Cypress.once` so xhook script is not added to other tests on page load.

Then in a test file where calls to that endpoint will be made, we use

```js
// articles.spec.js
describe('Articles page', () => {
  beforeEach(() => {
    cy.mockArticlesRequest();
    cy.server();
    cy.route('/user', 'fixture:user.json');
     ...
  });
});
```

And this what the fixture response file look like:

```js
// fixtures/responses.json
{
  "matches": {
    "id": 1
  },
  "response": {
    "data": [{
      ...
   }]
  }
}
```
And that's it :tada: Happy testing :rocket:

**Note**: There seems to an issue where this doesn't work when `cy.clock` is used.