Snapshot Testing with Jest. It’s not a Joke!
Getting Started Using Jest To Test Your React App
There are tons of different testing libraries out there, but for today I’m going to focus specifically on Jest and React testing.
What To Test
I’ve always had a bit of imposter syndrome surrounding testing. On the one hand, I can easily imagine a scenario in which I don’t write a test for something really important, and even though everything is passing, I end up accidentally breaking my app. On the other hand, I can also see myself writing tons of tests that are so fine-grained they aren’t necessary and take so much time to write that I never actually finish the project. So the first thing I wanted to figure out was, how do I find that sweet spot in the middle?
After doing some brief research, I found an article which lays out some totally reasonable guidelines about what to test.
- Does it render?
- Is the output correct?
- Test all states (Anything conditional should be tested)
- Test all events
- Test the edge cases (e.g., Are you rendering an array? what if its empty?)
To get started, we first need to install Jest:
yarn add --dev jest
Since we are going to want to test components we are also going to need:
yarn add --dev react-test-renderer
To help test our component that renders image files, we need
yarn add --dev jest-transform-stub
If you’re using Babel you need
yarn add --dev babel-jest babel-core
Now that we have our dependencies squared away, we need to go into the package.json file and change a few things.
To start, at the top level we need to add a
“jest” key like this:
This is where you will put all of your config options. In our case, we set
verbose to true so that we get a display of each test when we run them. We are using
moduleNameMapper in conjunction with
jest-transform-stub, which we installed earlier, to mock our image files when testing any components that contain images.
Next, we need to change the value of
“scripts”. Mine looks like this:
For reference, my package.json file ended up looking like this:
Before I start writing any tests, I’m going to create a __test__ folder inside src, and then I’ll build a separate file for each component that includes all the tests for that component. The name of the folder is important for Jest to function correctly.
Writing the Tests
The structure of tests in Jest is pretty straightforward. There is a
test() method that you call every time you want to test something. It takes two arguments; The first is a string that describes what we are testing — this is for humans and gets printed to the terminal when you run the test. It mainly functions as a label. The second argument is a callback that contains the logic for the actual test.
In the example above, we can get a pretty good idea of how our tests will be written. Inside the callback, we call
expect and pass it the thing that we are testing. We chain another function, called a matcher, to the
expect (in this case
toBe()) which takes the desired outcome as it’s argument. There are a lot of different matchers to choose from, based on the thing you are trying to test.
There is another syntax we can use which works the same way. We can call
describe() just like we were calling
test()and pass it arguments with the same structure. Inside of the callback, we can nest
it() which also takes the same syntax as
The choice between the two seems to be mostly stylistic. Describe allows you to nest and group your tests. However, if the indentation is getting out of control you can just use
Snapshot testing is exactly what you think it is. The first time the test is run, Jest creates a ‘snapshot file’ that it will compare your code against in the future. On future runs of the test, Jest will compare the output with the previous snapshot. If they match, you pass!
This does mean that if you change the structure of your component, you will need to update that snapshot file, which you can do with the following command:
To test our React app, we use the
react-test-renderer package that we installed earlier. It allows us to render our component and set it equal to a variable that we can then pass to our tests.
At the top of our test file, we need to import React, the component to be tested and TestRenderer. Let’s start with the
Since we need to pass
CardBack a roll object as a prop, we should also create a fake one.
Then we use the
create() method from
react-test-renderer to render the component for testing and set it equal to a variable. Our first test can check that the component renders correctly by using the
.toMatchSnapshot() matcher to compare it to the snapshot.
If we run our test from the command line using
It passes! So our component is rendering as expected. Since this is a pretty basic component, that’s probably all of the testing it requires for the moment. Since, we already included all of that mumbo-jumbo for mocking images, we can test the CardFront in almost exactly the same way.
Nav is even simpler since it doesn’t require any props.
Let’s see how we are doing:
We’ve gotten our test suite set up and built simple tests for our three basic components. Next time we can tackle the container components and look at how to test components with state and asynchronous functions like fetch requests!