Build Youtube in React 06: Snapshot Testing using Jest and Enzyme
1. Testing React components in Jest and Enzyme
Just one more thing before we go on. We have already quite a few components and as part of our a professional software development approach, we would also like to test them as well.
Right now, our components are basically just markup and don’t contain any logic. But we can still test them!
1.1. Snapshot Testing
snapshot can be compared with taking a photo in the real world. When you create a
snapshot, you basically create a photo of the component, i.e. you somehow store, how the component is supposed to look. Now if the component is changed later on, the photo (the
snapshot) will look differently than before. When you run the available snapshot tests, you can compare the last stored
snapshot with the current component. Therefore, it is immediately apparent what has changed. This approach is way easier and faster to do than other types of frontend testing we can do. These
snapshot tests are unit tests. They don’t test how the different components interact, but are focused on one single component.
Fortunately there is a variety of tools out there that make our
snapshot testing life much easier. One of the most popular
snapshot testing packages is Enzyme which is developed and maintained by AirBnB. Enzyme itself is responsible for creating and storing component
snapshots. However, to set up a test bench, we need more functionality than creating
snapshots. We need a package that allows us to assertions and can compare different
snapshots. Therefore, Enzyme is often used together with Jest, one of the most popular
We’re also going to use them together.
1.2 Setting up Jest and Enzyme in create-react-app
First, we need to install Jest and Enzyme via
The nice thing about
create-react-app is that Jest is already pre-installed. So we only need Enzyme.
So the thing is that
Enzyme for itself is not sufficient. Depending on which
React version you use, the overall render process is different.
React 15 renders component differently than
React 16 and so on. Since we want to use one universal API for Enzyme, we need an adapter that connects Enzyme to the
React version we are using. As we are using
React 16.x we install the enzyme-adapter-react-16 component.
Why do we also need the react-test-renderer package? The thing is that
React typically renders your component to the
DOM. However, when we are testing, we don’t want to render to a
Finally, we also install the enzyme-to-json package. Jest and Enzyme are basically two separate libraries, so per default
Jest does not understand Enzyme objects. Therefore, we need a package so that we Enyzme wrappers are compatible with Jest.
1.3. So why again do we need this adapter?
I’ll give an analogy on why Enzyme needs a
React adapter. Maybe that’s easier to understand.
Suppose you want to connect some periphery to your computer. Your machine only has USB-C ports. So if you want to a device with USB-A, you need a USB-C to USB-A adapter. If you want to connect to a monitor, you need a USB-C to HDMI / display port cable. So by having USB-C only, you have a universal physical interface that you can use to connect other devices to. So no matter what physical interface your periphery has, you can always connect to it as long as you have an adapter.
In this analogy, USB-C is the Enzyme API you use to write your testing code. We don’t want this API to change because then the Enzyme API would differ depending on which
React version we use. Continuing with the analogy, the different peripheral devices that have USB-A / Display port /HDMI interfaces are the different
React versions that you can write your tests against.
1.4 Configure Testing in create-react-app
Wow that was a lot of explanation. But don’t worry – since we have all the packages above, setting up testing in our
create-react-app based application is really easy.
create-react-app has documentation on how to setup up testing. Its test setup allows us to create a file in
src/setupTests where we can configure our testing.
- Create a new file in
srcand name it
setupTests.js. The naming here is important.
Paste the following code into this file to configure your test setup:
What do we do here? Remember that enzyme-to-json provides a way so that Jest can understand Enzyme wrappers. We basically tell expect (an assertion tool that is part of Jest): look, we have a little bit of additional logic here so in case you encounter an Enzyme wrapper and you don’t know what to do with it, we give you an additional serializer so that it works anyway.
1.5. Testing our setup
Let’s see if our setup works.
Head over to your console and run
If you encounter an error like this:
you have probably mixed
yarn commands. Just delete your
node_modules and your
yarn.lock file and reinstall them again using
Apart from that everything should just work out fine and you a file watcher should have been started.
1.6. Writing tests in create-react-app
The create-react-app docs clearly list how our tests should be organized so that our test runner executes them:
We are going to colocate our
snapshot tests with our components because they are unit tests.
We will also create
__tests__ directories for each component because otherwise our logic is mixed with tests. I typically give unit tests a
.unit.test.js suffix because then it is immediately apparent whether it is a unit or an integration test.
Let’s test the components we already have.
2 Testing our HeaderNav component
- Create a new directory in
src/containers/HeaderNavand name it
__tests__(the directory’s name is important)
- Create a new file called
HeaderNav.unit.test.jsinside the directory you just created.
Let’s create our first
Head over to your console and run
Notice that a folder called
__snapshots__ within our
__tests__ directory has been created that contains
.snap files contain the markup, the
render function returns from our components. Let’s illustrate this really quick.
2.1. Shallow Rendering in Jest and Enzyme
Let’s just talk about
shallow rendering real quick.
Shallow rendering means that we are executing the render method of a component, but don’t step down the entire view hierarchy. We’re just getting the markup that the render method returns and write this to a
snapshot file. Here’s an example that is really easy:
ParentComponent.unit.test.snap file above shows content of the
snapshot file, our test produces. And here you can see the difference between mounting and shallow rendering. Shallow rendering will not execute the
render method of custom components that are used within the current component. This is actually really good because our test for the
ParentComponent should only cover the
ParentComponent and not the elements it makes use of in its
render method. Like so, we are only testing one component. This is ok because each component will have its own
snapshot test, so nothing remains untested.
3 Snapshot test all the components we currently have in our project!
Now that we have understood the basic concepts of
snapshot testing, let’s apply this knowledge to our existing components.
Go ahead an create
snapshot tests similar to the one we have created in section 2 for
For brevity, I won’t show all the code here because it would be very repetitive. Try to do this on your own. You can also head over to this project’s git repository if you need help.
Just one more thing. Some components take different sets of props. E.g.
label as props. You can
snapshot the component with different props like so.
You can also do that for the
SideBarHeader and the
In case you were wondering about the
describe function: we use it to group tests for one component or one functionality together. It’s just best-practise.
4 Wrap Up
I know, testing is probably not your favourite activity. I get it.
But you can have greater confidence in the stuff you actually build. That’s why we do it in the first place.
As always, you can find this project’s code in our Github repo.Follow @productioncoder
Please follow me on Twitter @productioncoder to stay up-to-date. I’m happy to receive feedback of any kind.
If you are interested in more high-quality production-ready content, please enter your email below.