How to Emulate Axios/Fetch to Handle HTTP Requests in Tests With Msw.JS
By: David Zavala
Tags: Msw, Mockservice, Jest, React, Testing

How to Emulate Axios/Fetch to Handle HTTP Requests in Tests With Msw.JS

If you want to read this post in Spanish, click here.

When we talk about testing our applications, one of the main issues we need to keep in mind is how we should deal with the requests that our application makes to the server, as virtually every application interacts with requests in some way.

To many, this process may sound familiar and even simple. If you already have experience with this part, perhaps the first thing that comes to mind is to simply create a mock with jest , something like this (axios):

However, it may not be the best solution or at least the most robust one, what do I mean by that?

When we mock some library as axios, we are inferring that the request was made correctly, that is, that if our request required sending certain headers, for example, these were sent correctly when perhaps they were not and, since our test is probably not focused on making sure those headers were sent, we run the risk of letting a mistake go by.

On the other hand, this is not the only complexity that can be presented to us with this approach, as many know, another of the needs that the form outlined above requires, is to repeat code so that each test can have the implementation and response that we need. This can result in very large files that are difficult to maintain.

The alternative… msw.js

msw stands for Mock Service Worker , a tool that takes care of intercepting all requests made at your network level. Let’s explain a little more in detail what this is all about.

The basic idea of msw is to create a fake server that intercepts all requests and handles them like a real server. This implies that you can implement this tool as a set of “databases” either from json files to “seed” the data, or “constructors” like fakerJS and then create drivers (similar to the express API) and interact with that simulated database. This allows us to test our application under conditions very similar to those in production, either for development, testing, or debugging. In the case of testing, which is what we will focus on today, it allows for quick and easy tests to be written.

Once all this is explained, we can move on to writing code.

What we will do this time is a very simple demo of how to work with msw , we will take as a base a very basic ToDos application made with create-react-app and exploring the tests with jest and react-testing-library .

Let’s get started.

Installation

msw provides us with an npm package (also available with yarn) to use in our project.

$ npm i msw -D $ yarn add msw -D

2. Creating our first controller

As we commented previously, msw works with a syntax very similar to what we know from express making it very fast and easy to build the drivers that will take care of emulating our backend.

As we can see in the code, we created a file called server.js inside a folder called mocks , in that file we made the import of an object called rest from msw, since it is the architecture that we will follow, however, it is important to highlight that msw also allows you to emulate the flow if you work with GraphQL.

Besides the import, we created a constant called handlers that will contain all the controllers we want to include in our server. The server object contains methods corresponding to the http verbs like get and post , the syntax is very simple, the method only needs to be passed 2 parameters, the url and a “resolver” which will receive req, res and ctx which we will explain a little later:

req , contains information about the petition.

, contains information about the petition. res , a functional utility that takes care of sending the response.

, a functional utility that takes care of sending the response. ctx , a group of functions that allow us to configure status codes, headers, the body of the response, among other things.

In order for msw to intercept the request, it is important that we place the url correctly, there are 3 ways in which msw can evaluate the matches.

Using the exact URL e.g. http://localhost:4000/todos

Using the path e.g. /todos

Through regular expressions

You can find more information about it here.

3. Jest Configuration

For this step, we are going to take advantage of creating an application with the create-react-app since it gives us a completely configured environment with the tools we are going to need not only to be able to develop our project but also to be able to test it correctly.

Inside our project, we’ll find a file called setupTests.js setupTests.js inside the src folder, it’s here where we’ll be able to add extra configuration that will be useful in our tests, for example, by default it comes imported the module “@testing-library/jest-dom/extend-expect” that allows us to use affirmations like toBeInTheDocument or toHaveAttribute , it’s inside this file where we’ll add the following:

As we can see, the required configuration is very simple, just import the server we have just configured and added three global conditions for our tests:

beforeAll , raise the server so that it is waiting for the requests before my tests start running.

, raise the server so that it is waiting for the requests before my tests start running. afterEach , after each test it will reset the drivers to the initial values, and during the tests we can add new drivers that were not defined previously, a topic that we will cover a little later, this to avoid that these new drivers affect other tests.

, after each test it will reset the drivers to the initial values, and during the tests we can add new drivers that were not defined previously, a topic that we will cover a little later, this to avoid that these new drivers affect other tests. afterAll , after all the tests are finished, we finish the “server”.

By this point we have covered everything we need to configure msw in our project, but how do we implement it?

4. Implementation

Actually the implementation is just as easy as the configuration we have done so far. Let’s consider that we have a simple component that just requests our ToDos from the server and draws them in the browser as follows:

Simple, isn’t it? Now let’s create our tests:

We’re already in the home stretch, let’s explain a little what all this code is we have here. First of all, remember that we are going to use testing-library for our tests, so we import render, screen and waitFor , the import of react, it’s too much to explain, we import in the same way “server” and “rest”, maybe you wonder why, in a moment we explain it, finally the component that we are going to test in this case App .

In our first test that we call fetch todos and render we are testing that the request is being made and our component is handling it correctly, is here where it comes one of the first things that is interesting, remember that the requests are asynchronous processes so these can delay, is for this reason that we need to make use of the waitFor method, since it will help us to make our test wait for an element with the role of listitem , once an element of that type is found in the DOM, we can proceed to make our statements, in this case we only made a simple one, the answer of our false “server” returned us only one ToDo (defined in the controller) because the statement consists in that the number of elements that match the role of listitem is only one.

In this process that we have just explained, we focus on the first test that consists of the successful case, in which everything goes well. Now we’ll look at the other case, when we want to test the failure case.

It is very similar to the previous one at the level of statements. However, there is a difference, in our second test we are making use again of the “server” and the rest object, this with the intention of making that for that specific test, the answer is different, what we are doing is indicating that the answer to the request now has to be a failure and therefore our component has to behave differently and draw the message “http error” that we configured.

Conclusion

This time we reviewed an alternative to emulate our http request process in our applications, we learned how to configure msw.js a tool that allows us to intercept the requests that are made and respond in the same way that our server would in our testing and development.

I hope this post will be very useful and help you to make your testing easier, I leave below some references in addition to the full code on Github.

Code

References