With the library you can build reusable components to build your user interface. When I came across unit testing React components, the first thing that came up was React TestUtils. As Facebook describes, these test utilities should make it easy for the programmer to test their components with the testing framework that they choose. However, things can turn out to be different in the case of unit testing.
The test utilities can mainly be used in two ways:
Using the renderIntoDocument functionality of these TestUtils, the component of choice gets rendered into a fake Document Object Model (DOM). It is then possible to simulate several events on the component and assert the result of the render output.
Although, there are two main problems with this option:
- All child components get rendered. That way you have to deal with the behavior of child components besides the behavior of your component of choice.
- Access limited to the state and props of the component of choice. You want to test and track the changes of these two component properties. However, using this solution is not really possible.
Therefore, render IntoDocument is not really a solution.
2. Shallow rendering (experimental)
Using shallow rendering, it was possible to test a component without an actual DOM. Using this option only allowed me to test the render output of a component, and not ‘unit’ test the actual functions declared within the component. Also the state is not accessible, so fully testing a component was still not possible.
These test utilities allow you to test several things about the render output and simulate events on components, but unit testing React components properly is still not possible. The word “properly” is open for a discussion. In my case, this is a test coverage of a minimum 85%-90%.
The Solution for Unit Testing React Components
While trying to test these components, a question came to my mind multiple times: Can React classes be instantiated like constructors? The test utilities put me on the wrong track, so I tried this a lot combined with these utilities. Turned out I never needed them for unit testing.
By simply instantiating the component with the new keyword and assert the returned object was the solution to all my problems with unit testing React components. The example can be found on my GitHub page.
In a nutshell, these are the advantages of unit testing React components this way:
- Being able to know when the state changes and what it will be, by mocking setState
- Acting as a parent for the component, by generating mock functions and pass them down in the constructor as a property of props.
- Call every function declared within the component without worrying about what children would do.
- Being able to test the render output whenever you want.
Although this may seem awesome and all, it has a few minor disadvantages (it’s really minor, but still worth mentioning)
- The render function needs to be called manually. Though this may not seem a disadvantage, when the component is updated a lot through state and props, your test may grow big.
- The setState function of the component is not invoked by default when testing. You have to manually declare a setState function to assign the new state on the old state.
A tip for testing various render outputs is for the render function to not have any if/else statements. Instead, create functions that return a certain tree of elements (a same kind of tree that the render function returns) and put your logic for showing/hiding elements in these functions. This way you prevent doing really deep assertions of your tree, which results in more readable test code.
So that’s how it’s done. When unit testing React components, this is the way to test components, without any test utilities that React may provide.