JavaScript testing #4. Mocking API calls and simulating React components interactions

JavaScript Testing

This entry is part 4 of 18 in the JavaScript testing tutorial

A common thing is for our application to fetch some data from the API. A problem with it is that might fail for various reasons, such as the API being down. We want our tests to be reliable and independent and to ensure that we can mock some of our modules.

Mocking

For the purpose of providing an example, we modify our ToDoList component to be a smart component.

app/components/ToDoList.component.js

It fetches the data using axios, therefore, we need to mock that module, because we don’t want actual requests to be made. Such mocks are defined in a __mocks__ directory where the filename is treated as a name of the mocked module.

__mocks__/axios.js

If you want to mock some of the core modules of Node (for example fs or path) you need to explictly call jest.mock(‘moduleName’) in the mock file

Jest allows us to spy on functions:  let’s now test if the get function that we created is called.

app/components/ToDoList.test.js

Thanks to calling   Jest replaces axios with our mock – both in the test and the component.

The spyOn function returns a mock function. For a full list of its functionalities visit the documentation. Our test checks if the components call the get function from our mock after rendering and running it will result with a success.

If you are spying on your mocked functions in more than one test, remember to clear mock calls between each test, for example by running  . Otherwise, the number of function calls would persist between tests. You can also make it a default behavior by adding this snippet in your package.json file:

Mocking Fetch API

Another common situation is using Fetch API. A trick to it is that it is a global function attached to the window object and to mock it, you can attach it to the global object. First, let’s create our mocked fetch function.

__mock__/fetch.js

Then, let’s import it in the setupTests.js file.

app/setupTests.js

Please note that you need to provide the path to the setupTests.js file in the package.json – it is covered in the second part of the tutorial.

Now you are free to use fetch in your components: thanks to our mock, it will now be available.

When setting up a spy, remember to set it to the window.fetch

app/components/ToDoList.test.js

Simulating React components interactions

In the previous articles we’ve mentioned reading the state or props of the component, but this is the time to actually interact with it. For that purpose of explaining it, let’s add a functionality of adding new tasks to our ToDoList.

app/components/ToDoList.js

As you can see, we use axios.post here. This means we need to expand our axios mock.

__mocks__/axios.js

I’ve introduced the currentId variable because we want to keep our IDs unique

Since we’ve got that out of our mind, let’s get to testing: the first thing to test is to check if modifying the input value changes our state.

app/components/ToDoList.test.js

A crucial thing here is the simulate function call. It is a function of the ShallowWrapper that we’ve mentioned a few times now. We use it to simulate events. The first argument is the type of the event (since we use onChange in our input, we should use change here), and the second one is a mock event object.

To take things further, let’s test if an actual post request gets send from our component after the user clicks the button.

Thanks to our mock and simulating events, the test passes!

Now things will get a bit trickier. We will test if the state updates with our new task. The interesting part is that the request is asynchronous.

As you can see, the postSpy.mock.results is an array of all the results of the post function and by using it, we can get to the promise that is returned: it is available in the value property.

Returning a promise from the test is a way to make sure that Jest waits for it to resolve.

Summary

In this article, we covered mocking modules and used it to fake API calls. Thanks to not making actual requests, our tests can be more reliable and faster. Aside from that, we’ve simulated events throughout the React component. We’ve checked if it resulted in an expected outcome, such as a request made by the component or the state changing. To do that, we’ve learned the concept of a spy.

Series Navigation<< JavaScript testing #3. Testing props, the mount function and snapshot tests.JavaScript testing #5. Testing hooks with react-hooks-testing-library and Redux >>
Subscribe
Notify of
guest
3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Kenny Huynh
Kenny Huynh
6 years ago

Hi,

Thank you for writing this up! This really helped me with understanding how to do mock api calls!

A question I have is..

What if you have a lot of get requests that you want to test? in the mocks file, would you create multiple mock “get” but with each having a different url?

Thanks!

JackChoumine
JackChoumine
1 year ago
Reply to  Kenny Huynh

how do you do this?

Caleb Rotich
Caleb Rotich
5 years ago

Awesome series.