DEV Community

Calum Flanagan
Calum Flanagan

Posted on • Edited on

Playing with Jest

I stole this image from this great article https://medium.com/codeclan/testing-react-with-jest-and-enzyme-20505fec4675

I recently started playing with Jest for a bit of fun and to see how it compared to the stack I usually use to test my React components - Jasmine (with Enzyme) and Karma as a test runner. I've heard a lot of good t h i n g s about Jest and how it basically does all the things that Jasmine does (since it was based on it)… and more now that Facebook have modified it and built on it to expand on what Jasmine does.

Quick and easy

The first and one of the most useful advantages of Jest that I noticed when building an app from scratch, was how quickly I was able to set it up and get on with writing tests. Previously I had to setup Jasmine and then Karma, along with Karma's config file that you have to mess with. With Jest it was much quicker and much easier. Simply npm i jest then add the jest command to your package.json in the npm test script like this:

"scripts": {
  "test": "jest --coverage"
}

and you're done. Running tests is ridiculously fast too, because you're no longer having to spin up a Node.js process that invokes Karma.

You may have noticed the addition of --coverage paired with the jest command in my package.json. This allows you to have complete code coverage, so when you run your tests you should get an output that looks something like this:

coverage output

Now, you can see at the very bottom that Jest ran a test suite which failed for one reason or another, but above that might be an indicator as to why certain test have failed. In the table above, it details how much of my code has and hasn't been tested. So it's possible that some of that untested code is making my tests fail. It also saves this data as a file you can open in the browser, where you can see exactly which lines of code you've not tested in any of your components. Fantastic! All that value and all you have to do is append --coverage to the jest command.
NOTE: you can also do this with Karma, but I thought it was worth mentioning anyway, while we're already talking about tests!

Familiarity

The second cool thing about it, especially if you're transitioning from Jasmine (with Enzyme) like me, is that you can still write tests in the exact same way as Jasmine and use all of the same utilities with it (from what I've seen so far). This means that your beloved Enzyme "mount" and "shallow" can still be called upon…

Enzyme is still your friend

With Jest, you are still able to use AirBnB's popular React testing utility - Enzyme. Enzyme does lots of cool things, but one cool thing I want to mention is it's ability to allow you to shallow render components in your tests. Shallow rendering a component basically means you are only rendering the component itself, not all of its children. This is particularly useful when it comes to Jest's best feature (in my opinion) - Snapshot testing, which I'll get to soon.
If you're gonna use Enzyme, you might want to setup a jestsetup.js file. Here's what mine looks like:

import Enzyme, { shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter()});

global.shallow = shallow;
global.mount = mount;

This isn't a necessity for using enzyme, but if you want to be able to use the shallow and mount methods in your tests without having to import them every single time, then this is how you share them globally.

In addition to this, in your package.json you will need to tell Jest where this setup file lives, like so:

"jest": {
  "setupFiles": [
    "./tests/unit/jestsetup.js"
  ],
  "snapshotSerializers": [
    "enzyme-to-json/serializer"
  ]
}

Snapshot tests

Snapshot testing in Jest is what makes the switch from Jasmine worthwhile. Along with the fast setup and the fact you can do away with Karma now, writing a snapshot test in Jest is ridiculously easy and just as fast. In short, a snapshot test will basically capture the entire output of a component (hence shallow rendering is useful here), then when the test is ran it will compare what it captured to the actual output. So you are covering every area the code in your components.

Failing snapshots

If a snapshot test fails due to a bug in your code, this will easily be picked up by the test. So we simply fix the issue, re-run the test and check that the snapshot test is passing again. However, you might be thinking what happens if changes are made to the code in a component? Won't the snapshot be out of date? Yes, but Jest has a solution. Sometimes a snapshot test can fail due to an intentional change in your code, because the snapshot for the updated component no longer matches the original snapshot for the test. To resolve this, you simply need to run this command jest --updateSnapshot and the snapshot will be updated.
Of course, this is where you have to be careful not to record a snapshot for a component that still has buggy behaviour. So only update your snapshot when you are happy that there are no more bugs in your code i.e. your unit tests are passing.

Multiple snapshot tests

When playing with Jest I created an app that allows the user to enter a search term into a search box, which in turn hits an API endpoint and returns with some results. I then pass these results through to another component using props and display them there (a search-results component). Therefore, my component would have a couple of different states based on whether or not it is populated with data from the API or not. So in conjunction with this, Jest allows me to have multiple snapshot tests to cater for the different states of the component. An example might be as follows:

it('matches snapshot', () => {
  //Assertions here
});

//Then another test for when the component has props >>>>

it('matches snapshot after receiving props', () => {
  //Assertions here
});

What I plan to look at next

I haven't yet looked far enough into how mocking works in Jest, but if my assumptions are right, I should still be able to mock using a Jasmine spy - since Jest allows you to use other Jasmine conventions.

Top comments (0)