Want to test your React app when making a fetch request? This article will go over how to integrate msw
(Mock Service Worker) to intercept a specific network request made on your app. To test and make sure our app behaves as intended.
1. Creating our Component
The component that we will be testing will be simple. The component will fetch the randomuser API to retrieve a random first and last name. And then display a text on the screen The name is {firstname} {lastname}
.
First, create a React App using npx create-react-app
. Then run npm install axios msw
in the terminal to install axios
andmsw
(Mock Service Worker) as a dependency. Lastly, we'll build our component in App.js
.
import { useState, useEffect } from "react";
import axios from "axios";
const url = 'https://randomuser.me/api/?inc=name'
export default function App() {
const [fullName, setFullName] = useState('')
useEffect(() => {
axios.get(url)
.then(({data}) => {
const {first, last} = data.results[0].name
setFullName(`${first} ${last}`)
})
}, [])
return (
<div className="App">
<p>The name is {fullName}</p>
</div>
);
}
We use useEffect
to make our fetch request when the component mounts. Then we extract the first
and last
and update our fullName
state. And at the end, we return our JSX to print out the text, including the full name from our state. If you run npm start
everything should display correctly.'
2. MSW(Mock Service Worker) Setup
To set up our msw
, we first create a new mocks
folder in our src
directory. Then create two files in our mock
directory. The first file will be named server.js
, and the second will be handlers.js
.documentation reference
Now go into your handlers.js
file and paste the code below.
import { rest } from 'msw';
export const handlers = [
rest.get('https://randomuser.me/api', (req, res, ctx) => {
return res(
ctx.json({
results: [
{
name: {
title: "Mrs",
first: "Chris",
last: "Lemus"
}
}
],
})
);
}),
];
Here we add the response data to any network request whenever we run our test. And the handlers
array to store all of our mock server responses. For this demo, we only need to add a mock server response for a GET request made to https://randomuser.me/api/?inc=name
.
The response will return an object containing data for the first name and last name, in the same format our randomuser
API would respond.
Next, paste the code below into server.js
to set up the server.
// src/mocks/server.js
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
// This configures a request mocking server with the given request handlers.
export const server = setupServer(...handlers);
The last step to setting up our msw
is to update our React test configuration; this will intercept all network requests specified in our handlers
. So paste the code below into setupTests.js
in the src
directory. Reference to the code provided can be found on the msw documentation.
import { server } from './mocks/server.js'
// Establish API mocking before all tests.
beforeAll(() => server.listen())
// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => server.resetHandlers())
// Clean up after the tests are finished.
afterAll(() => server.close())
3. write test
Finally, we write the test in App.test.js
.
import { render, screen } from '@testing-library/react';
import App from './App';
test('displays name from api correctly', async() => {
render(<App />);
const text = await screen.findByText(/chris lemus/ig);
expect(text).toBeInTheDocument();
});
The test ensures that the name is printed correctly after making the network request. Since we will be making a network request in our App.js
component, we will provide an asynchronous callback function for our test.
The last step will be to run npm test
, where our test should run successfully.
Top comments (2)
A great overview, Chris!
One thing I'd point out, is that you don't have to specify query parameters when declaring the request URL in your handler:
Query parameters don't describe the path to the requested resource and should be dropped. The values of those parameters can still be accessed under
req.url.searchParams
in your resolver if you need them.I've updated the request URL in my handler. Thanks for the feedback!