Unit testing your Redux actions and reducers is nice, but you can do even more to make sure nothing breaks your application. Since React is the view layer of your app, let's see how to test Components too!
React provides us with a nice add-on called the Shallow Renderer. This renderer
will render a React component one level deep. Lets take a look at what that
means with a simple
This component renders a
<button> element containing a checkmark icon and some
Note: This is a stateless ("dumb") component
It might be used in another component like this:
Note: This is a stateful ("smart") component!
When rendered normally with the standard
ReactDOM.render function, this will
be the HTML output
(Comments added in parallel to compare structures in HTML from JSX source):
Conversely, when rendered with the shallow renderer, we'll get a String containing this "HTML":
If we test our
Button with the normal renderer and there's a problem
CheckmarkIcon then the test for the
Button will fail as well.
This makes it harder to find the culprit. Using the shallow renderer, we isolate
the problem's cause since we don't render any other components other than the
one we're testing!
The problem with the shallow renderer is that all assertions have to be done manually, and you cannot do anything that needs the DOM.
In order to write more maintainable tests which also resemble more closely the way our component is used in real life, we have included react-testing-library. This library renders our component within an actual DOM and provides utilities for querying it.
Let's give it a go with our
<Button /> component, shall we? First, let's check that it renders our component with its
children, if any, and second that it handles clicks.
This is our test setup:
Let's start by ensuring that it renders our component and no changes happened to it since the last time it was successfully tested.
We will do so by rendering it and creating a snapshot which can be compared with a previously committed snapshot. If no snapshot exists, a new one is created.
For this, we first call
render. This will render our
<Button /> component into a container, by default a
<div>, which is appended to
document.body. We then create a snapshot and
expect that this snapshot is the same as
the existing snapshot, taken in a previous run of this test and committed to the repository.
render returns an object that has a property
container and yes, this is the container our
<Button /> component has been rendered in.
As this is rendered within a normal DOM we can query our
container.firstChild. This will be our subject for a snapshot.
Snapshots are placed in the
__snapshots__ folder within our
tests folder. Make sure you commit
these snapshots to your repository.
Great! So, now if anyone makes any change to our
<Button /> component the test will fail and we get notified of what
Onwards to our last and most advanced test: checking that our
<Button /> handles clicks correctly.
We'll use a mock function for this. A mock function is a function that
keeps track of if, how often, and with what arguments it has been called. We pass this function as the
onClick handler to our component,
simulate a click and, lastly, check that our mock function was called:
Our finished test file looks like this:
And that's how you unit test your components and make sure they work correctly!
Also have a look at our example application. It deliberately shows some variations of implementing tests with react-testing-library.
Continue to learn how to test your components remotely!