Testing React.js Applications with Jest

Using Jest Mocks

Your browser needs to be JavaScript capable to view this video

Try reloading this page, or reviewing your browser settings

This video segment introduces mocks, when you should use mocks, using just mocks and testing the handleLogin method using mocks.

Keywords

  • React
  • Jest
  • Testing
  • Mocks

About this video

Author(s)
Gigi Sayfan
First online
22 May 2019
DOI
https://doi.org/10.1007/978-1-4842-3980-3_4
Online ISBN
978-1-4842-3980-3
Publisher
Apress
Copyright information
© Gigi Sayfan 2019

Video Transcript

In this section, we’ll talk about using Jest mocks. The topics we will cover include what are mocks, why should you use mocks, mocks in Jest, mocking async calls, and finally, testing the HandleLogin() method.

Mock objects allow you to inject dependencies into the code under test. For example, if your code depends on a server, like the rumble server, you can replace it with a mock server. The mock server will capture all the calls made by the code, it will provide canned responses, and in some cases it can even provide a complete alternative implementation.

Jest has awesome support for mocking. It all starts with the Jest object. It provides many methods for managing every aspect of the mocking process. You can turn mocking off and on. It provides various mock functions, auto mocking, and control over time and timers. If you need to replace the implementation of a specific functional method, the jest.fn() function comes in very handy. However, if you need to replace a whole module, you can place your mock module in the __mocks__ directory. And when the test imports this module, it will actually import your mock module.

Sometimes you need fine-grained control over the mocking object. In this case, you can use manual mocks instead of Jest’s jest.fn() mocks. Finally, managing time and timers in tests is very complicated. Jest allows you to replace timers with fake timers and stop and continue the flow of time. Testing async calls is one of the most challenging aspects of testing because the code runs in parallel, and your test code doesn’t always know when the code under test finished.

Jest provides excellent support for async calls. You can mock callbacks, promises, and even the new Async/Await syntax. One of the biggest problems with async tests is that if the test finishes before all the assertions actually executed, you may think that the test passed completely because no assertion failed. But actually, no assertion was even running. Jest provides the Expect.assertions() method to wait until all the expected assertions executed, or it will fail.

OK, let’s put all the pieces together. We will be testing the HandleLogin() method of the LoginBar. The HandleLogin() method uses the Axios model for data fetching. Axios is a better fetch. It also calls the onLogin callback function. As part of the test, we will be mocking both Axios and the onLogin callback function. We will instantiate the LoginBar itself, and then we will invoke the HandleLogin() method, the code under test. Finally, we will verify the results. The HandleLogin() method is called when the user clicks the Login button.

On line 22, the first thing that happens is that we prevent the default click event from taking place. Then, on line 23, it invokes the Axios POST method, calling the active user endpoint of the server and passing the credentials that are stored in the state, the username and password. This is a promise that when it returns, on line 25, it invokes the onLogin callback that is passed as part of the props. It’s handing it the user auth information from the result of the login call. Then, on line 26, it sets the state to loggedIn And, on line 27, if there was any problem or some error occurred, then we just log it to the console.

It’s showtime. Let’s see the test for the HandleLogin() method. We’ll start on line number 9, where we tell Jest that we want to mock the Axios module. Then, the test itself starts on line 45. Note that the test is async, which means we’re going to run async code there, and the test should wait for it. Then, on line 47, we mock the onLogin method and use the jest.fn() function. On line 48, we prepare a canned response that we will use later. On line 49, we create the mocked Axios POST method. And then, on line 50, we provide the implementation for this mocked method, which is just a promise that returns the canned response OK that we created in line 48.

In line 51, we create a shallow instance of the LoginBar This is the component that contains the HandleLogin(), which we are about to test. And note that we are passing the props of the LoginBar. We pass as the onLogin callback our mock onLogin mock function.

On line 52, we prepare the stage by setting the credentials that are going to be used by the HandleLogin(). If you recall, the HandleLogin() uses the state username and the state password when it’s calling the server. On line 55, we set the expected assertions to 6. This is very important when testing async code, because if the assertions don’t even run because the test finished before the async code had the chance to run, then no assertions will be executed. And when no assertions execute, then obviously no assertions fail.

On line 58, we finally invoke the HandleLogin() method itself. Note the await syntax, which means we’re going to wait for the HandleLogin() async method to return. And we also mock the preventDefault for the event. At this point, the HandleLogin() method finished, and it’s time to verify the results. For example, we want to make sure that the post.mock object was called only once. We can do it by checking the lengths of the post.mock.calls array. Or, on line 62, an alternative method is to call the toHaveBeenCalledTimes method with 1, which has the same impact.

Then, on line 63, we want to verify that the arguments that were passed to the active user end point were really the correct username and password credentials from the state. And again, on line 64, we have an alternative method to check that with toHaveBeenCalledWith.

On line 67, we want to check that the mock onLogin method was called. This is a callback function, and part of the responsibilities of the HandleLogin() method is to call this callback. So again, we check that it was called just once, on line 67. And similarly on line 68. And finally, on line 69, we want to make sure that the callback function received the canned response that we expect from the server, which is just OK. And that concludes our testing of the HandleLogin() method.