Mocking HTTP Request in React using Mock Service Worker
Enhance API testing efficiency with React Testing Library and Mock Service Worker
Have you ever found yourself deploying a new feature and feeling concerned about the possibility of introducing new bugs with each update? A minor change in an API could potentially disrupt the Frontend. What if there were a way to identify issues in an existing app simply by running test cases? In this blog post, we will delve into the use of React Testing Library to replicate DOM manipulation and Mock Service Worker (MSW) to mock HTTP requests. If you’re unfamiliar with React Testing Library, please take a moment to check out our introduction to it.
Understanding the need for mocking HTTP requests
Mocking HTTP requests during testing is essential for several compelling reasons:
- Speed: Mocking HTTP requests is significantly faster than making actual API calls, improving test execution speed.
- Isolation and Stability: Tests are less affected by external factors, ensuring stability.
- Data Control: Developers can create specific scenarios for testing, ensuring components can handle specific edge cases.
- Consistency: Mocked responses remain constant, reducing the likelihood of test failures due to external API changes.
- Cost Reduction: Mocking prevents costs associated with real API calls, particularly when running individual test cases.
Popular mocking libraries used with React
You can choose from many popular mocking libraries options, each offering unique features and advantages:
- MSW(Mock Service Worker) is an API mocking library that allows you to write
client-agnostic mocks
and reuse them everywhere, regardless of tools or frameworks. - Nock is a
Node.js
library specifically designed for mocking HTTP requests which offers a rich set of features for controlling request behaviour and defining expected responses. - axios-mock-adapter is a lightweight and easy-to-use mocking library specifically designed for
Axios
.
Among the various API mocking libraries available, MSW stands out as a powerful tool. We’ll explore how to mock API calls and write test cases using MSW to build robust and reliable applications.
Axios or Fetch ? MSW works with both
MSW simplifies your testing process as it’s independent
of any specific HTTP library like Axios or Fetch.
Prerequisite
Before we start, ensure these in your development environment:
- Install Node.js and npm on your development machine.
- Set up a React development environment with Vite.
How to setup Jest and Testing library in a React project with Vite
Since we are using Vite
for creating a React application, we will use Vitest
package, which is compatible with Vite.
Step 1: Install the necessary dependencies.
npm install -D vitest jsdom @testing-library/react jest jest-environment-jsdom @testing-library/jest-dom
Step 2: After the installation, add test script
in the package.json.
Step 3: Create a new file in the root of your project with the name setupTests.js
.
Step 4: Next, open the vite.config.js
file and add the following code to it.
Note: When we use create-react-app
for creating the project, there’s no requirement for a separate installation of Jest
since it’s already included.
Creating UI for writing test cases
We will create a simple Todo List App that allows users to fetch a list of existing tasks and add new tasks to it.
Here, we will use the freely available JSON Placeholder API for demonstration and testing purposes.
Inside the components folder, create three files namely TodoWrapper.jsx , Todos.jsx and TodoForm.jsx.
Get the whole code from this repository.
Step 1: Inside the TodoWrapper.jsx
component, a get
request is made to fetch a list of todos .
Step 2: Inside the Todos.jsx
component, we map over the todos
props and display them in a list.
If there is no data inside todos props, it will display No todo found
.
Step 3: For adding a new todo to a list, write text inside the input textbox and click on the submit button. On clicking the button, it will call post
API and the new todo will be added to a list.
The most recommended library for mocking when writing tests with the React Testing library is MSW (Mock Service Worker).
MSW setup
Step 1: Install msw
library as a dev
dependency.
npm install msw --save-dev
Step 2: Create a file server.js
inside the mocks
folder.
Step 3: Create a file handlers.js
for handling the HTTP request.
For our scenarios, we need to mock REST API
. Other option available is GRAPHQL API
.
Here, we are mocking GET and POST API responses.
- The first argument is the
same URL
that we are using to fetch todos. - The second argument is the function that returns
Mocked JSON Data
and it shouldmatch the exact response
which the component expects.
Testing with MSW
Now we have MSW set with the server and handlers, let’s write our test for TodoWrapper
component.
Create a file named TodoWrapper.test.jsx
inside the _tests_
folder.
First, let’s ensure that the component renders without any errors and displays the heading correctly.
To run the test in Vite, use the following command.
npm run test
Now, we need to write a test case to ensure the list of todos is displayed when the component mounts and fetch data from the HTTP request.
We have used findAllByRole
method from React testing library
as we expect multiple list items to be present in the DOM.
For our assertion, we expect todo’s array to have a length of 3. Now, where did the 3 come from? Well, it’s the length of the mocked array response that we have passed in handlers
file.
If we run this test, our test fails. You can see that expected length 3 and received length is 10. This is because we have not told our test to use a mock service worker. It has called the actual API endpoint, which returns an array of 10 todos.
To tell our test to use MSW, let’s modify the setupTests.js
with the code snippet below.
Now, if we run our test, it passes. This ensures MSW is considered when running the tests.
Let’s also assert against the mocked response that we passed in our MSW server and check if it renders correctly on DOM.
So now you can see the test for fetching todo passed successfully.
Let’s write some more tests
A test case that verifies the TodoForm
component correctly handles user input, adds the entered todo to the list, and displays the added todo.
Here, we are using fireEvent
from @testing-library/react
to simulate user interaction with input elements and Add Todo
button.
The user enters the text ideas
into the input field using fireEvent.change()
. Then, it triggers the Add Todo
button's click event using fireEvent.click()
.
waitFor()
to ensure that the assertion is executed only after the API response has been processed and the list has been updated.
MSW intercepts the API request and returns a mock response with a status code of 201, representing a successful todo creation.
The assertion checks whether the list item containing the text ideas
is present in the DOM.
MSW error handling
If we take a look at our TodoWrapper’s
component, we are setting an error message when the HTTP request fails.
The same error message is displayed on the DOM that there is an error fetching todos.
Let’s see how to tell MSW to respond with an error status when an HTTP request fails.
So instead of mocking requests in setupTests.js
file, we will mock requests for error handling in the test itself.
It is important to note that this handler for the 500 status code applies to this single test. As we are resetting the handlers using afterEach(() => server.resetHandlers())
after each test runs.
Now, as we run the test, we see all the four test cases are running as expected.
For the complete source code, check out the GitHub repository.🚀
Conclusion
In this blog, we emphasized the importance of mocking HTTP requests. We explored setting up a testing environment for a React app created using Vite from scratch. Using a basic todo list example, we demonstrated how to mock HTTP requests using Mock Service Worker (MSW).
It’s worth noting that MSW offers a wide range of additional features, so feel free to explore its documentation for more comprehensive insights.
For more updates on the latest development trends, follow the Simform Engineering blog.