The course is part of this learning path
This module looks at testing in React. You’ll learn how to set up a test environment, Jest, and other useful tools to test your React App.
The objectives of this module are to provide you with an understanding of:
- How to set up the test environment
- Snapshot testing
- How to test with Props
- How to mock components for testing
- Mock functions
- How to test components asynchronously
- How to test components with routing
- How to test custom hooks
This learning path is aimed at all who wish to learn how to use the ReactJS framework.
We welcome all feedback and suggestions - please contact us at firstname.lastname@example.org to let us know what you think.
Now we're going to find out about how to test components that use asynchronous data. To fully test components, we need to know that they make the right asynchronous calls, that they respond appropriately to data or errors that are returned. And conditional rendering works. This is probably the most difficult aspects to testing React components. There are so many moving parts and time delays to deal with.
One way this can be made easier is to use a third party package to handle asynchronous calls. This means the whole module can be marked. One such module we could use is called axios. Axios is commonly used. In fact, the jest documentation shows examples of mocking responses with it. Basically, it simplifies HTTP requests by having functions that are the same name as the verbs we use.
The definite advantage is that it automatically throws an error if a 200 status is not received, meaning only good data pass through to set our state. It also puts the data straight into a data key in the response object removing the need to await the call to JSON.
Before we get into the testing, we're showing you a component that has a fetch call made with axios. There's a similar pattern to what we discussed in an earlier course, we have a use effect hook that calls an asynchronous function get data. This is where the axios call is made. Line nine if you haven't spotted it yet, like fetch for get requests, we just pass in the URL for the request.
For the calls like posts, we can configure an object like we did for fetch. You can see its error handling is much simpler than fetch calls were made before. We surround it in a try catch blocks. Dealing with the error object generated by axios and handling the response status is here, it's much cleaner. If you look at the rendering of the JSX elements we return in this component, you'll notice that there are data test ID attributes attached to the elements. These are there so we can identify the components for testing. There'll be included in your production code. And there is a babel package that can be used to remove them. But that's not really necessary.
We'll move on to the testing now. We're going to test the asynchronous calls axios makes, we should provide a mock for it. We've created a folder called mocks with a double underscores around them, and a file called axios, which you can see in the file explorer on the left of the screen. In this file, we export an object. This contains the names of the functions we want to mark as keys in the object. The values are what we want to provide as the mock functionality. In this instance, we might get as a jest function and have it marked resolved value of an object with an empty data key.
If we wanted to mock more axios function say post, we would have the mock implementation here, adding a key of post, and whatever we wanted to add. As we have this folder and jest has been set up through create react app to look for mocks before performing actual imports. This will be used whenever we import axios in our tests. This is not well documented, so you do well to remember it. The actual test file for the component is set up in the same way we have set up for the tests. We'll discuss the imports from react testing library as we need to, and the jest don't extend expect so we can use some additional matches.
Notice that we import axios mock from axios. We alias our function just to be explicit that we have mocked the module. Remember that's in our mocks folder, line seven called afterEach with cleanup. Cleanup is a utility function from react testing library that removes a tree rendered as part of a test. It's good practice to do that.
The first spec in the file is to test the fetching and displaying of data. Note that its async as we're dealing with asynchronous actions. Line 11 makes a call to axiosMock.get And we override the mock resolve value with mock resolve value once and a value to return, they should reflect the data structure that the endpoint returns and it will replace the call in the components. We then render the component destructuring the get by test ID, and get all by test ID functions to use.
To ensure that the loading message is initially rendered, we use its test ID attribute of loading and assert that the element has text content of loading data. The next part initiates the asynchronous use effect call. We make an array of Li elements that have resolved. This is done awaiting the wait for function and supplying a call back to return any element has a test ID have resolved. The wait for function is part of react testing library. It will wait for the DOM to become stable before moving on.
We then assert that there are the correct number of allies rendered, in this case two, and we check that the access mop get function has been called exactly once, a check that those cyclic requests are not being made. At the time of recording, we have to update react testing library to version 10. And also installed and updated the jest environment JSDOM 16 to use these features. We updated the other testing library packages for adventure two.
It's worth noting that create react app is not always up to date with the latest packages. And searching online can often help with suggestions if things appear to go wrong. We've also tested for errors for making the axios get function, reject its promise with particular data. The system with a simple error object in the case of a network error, we follow the same pattern as for the resolved promise. But this time look for an error element with a test ID of network error. And for it to have the text content that's the same as is rendered in the component.
For the response errors, we create an error object that has a response object with status and status text keys, and use this in the promise reject. We check for an element within a test ID of response error, and then assert that the correct message is displayed. As a reminder, at the time of recording, we have to update react testing library to version 10. And also install an update of the jest environment JSDOM 16 to use these features.
So now you can test asynchronous calls and components using react testing library, mocking the package that makes the calls and checking data and errors dealt with appropriately.
Introduction to Testing React with Jest - How to set up the Test Environment - Jest - The What and How of Testing in React - Snapshot Testing - Testing Components with Props - Mocking Components for Testing - Testing State Events Interactions - Mocking Functions - Testing Components with Routing - Testing Custom Hooks
Ed is an Outstanding Trainer in Software Development, with a passion for technology and its uses and holding more than 10 years’ experience.
Ed is responsible for delivering QA’s Programming Foundations course using the Eclipse IDE. His skillset extends into the DevOps sphere, where he is able to deliver courses based around Agile/Scrum practices, version control, and CI/CD.