{ Testing with Jest. }

Objectives

By the end of this chapter, you should be able to:

  • Test your components with jest, react-test-renderer, and enzyme
  • Explain what snapshot testing is

Getting Started with Jest

Jest is a wonderful testing library created by Facebook to help test JavaScript code, React components, and much more. What's great about Jest is it not only is included with create-react-app (you can read more about that here), but with Jest your tests run in parallel so they are executed much faster than other testing frameworks.

So let's create a new React application write some simple tests!

Writing Simple Specs with Jest

We can use Jest without React, so it's important to understand how that works. Before we start testing our components, let's write some simple specs with Jest and see how the built in test and expect functions work.

Let's first get started with a simple create-react-app application. In the terminal, go ahead and write:

create-react-app learn-testing && cd learn-testing

Inside of here we can run our specs by typing npm test and we will see that we have one spec passing - here's what you should see:

 PASS  src/App.test.js
  ✓ renders without crashing (25ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.393s
Ran all test suites related to changed files.

Watch Usage
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press q to quit watch mode.
 › Press Enter to trigger a test run.

Notice here that we are in watch mode which will constantly look for changes in our test files. The one passing test is coming from src/App.test.js, the starter test file you get whenever you create a project with create-react-app. The inside of that file should look like this:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
});

We can see here that we easily can test that the application has rendered, but before we jump into testing our components, let's get to learn jest a bit better. Start by making a file called learn.test.js in our src directory. Inside of this file, add the following:

test('it works', function() {
  expect(1).toBe(1);
});

Notice that we are using the word test on the first line. This is very similar to it with Jasmine or Mocha. You can actually use the it and describe keywords if you'd like as well!

Matchers

Similar to Chai, Jest has quite a few functions used for assertions/expectations. You can see a full list here, but here are some common ones.

  • toBeDefined
  • toBeGreaterThan / toBeLessThan
  • toBe (uses === to compare)
  • toEqual (for deep object comparison)
  • toContain (see if a value is inside of a collection)

Let's try out a few more examples of the syntax in learn.test.js:

test('arithmetic', function() {
  expect(4 + 4).toBeGreaterThan(7);
  expect(4 + 4).toBeLessThan(9);
});

test('references', function() {
  var arr = [1, 2, 3];
  expect(arr).toEqual([1, 2, 3]);
  expect(arr).not.toBe([1, 2, 3]); // since === doesn't do deep comparison!
  expect(arr).toContain(1);
});

Test Folder Structure

You also might not want to place all of your test files with your files in the src folder. In order for Jest to read your tests, place them in a folder called __tests__ inside of the src folder.

Make sure that your folder is called __tests__ - this is essential! Inside of the __tests__ folder we can place all of the files that we'd like Jest to run.

Snapshot Testing

Now that we have a basic understanding of how to use Jest, let's discuss a nice feature it provides called Snapshot Testing.

Imagine for a second we have a component that looks like this

import React from 'react';

const SimpleComponent = ({ first, last, favFood }) => (
  <div>
    <h1>Hello there!</h1>
    <h2>Welcome!</h2>
    <p>First Name - {first}</p>
    <p>Last Name - {last}</p>
    <p>Favorite Food - {favFood}</p>
  </div>
);

export default SimpleComponent;

If we wanted to test this component we could write all the specs to make sure that when we render the component there are three paragraph tags, one h1 tag and that props are being correctly set on the component.

However, when one small change is made to our UI, this test will fail and we'll have to go edit the test again to account for new UI changes. This process is quite tedious. Fortunately, Jest has an excellent alternative: snapshot testing.

The way snapshot testing works is that Jest will take a snapshot of your component and when future tests are run, it will alert you of any differences between the current snapshot and a previous one. If you would like to update the snapshot, you can simply add a -u flag and update with a new snapshot.

Snapshot testing does not cover all cases. There will be times where you want to test the functionality of a component rather than its appearance. But when testing stateless functional components, snapshot testing is esspecially useful since you don't anticipate these components changing frequently.

Enough about Snapshot testing - let's see the code! First, we'll need to install another module, called `react-test-renderer, which is necessary for rendering our components while testing.

npm i --save-dev react-test-renderer

Next, in our src folder, let's create a new file called SimpleComponent.js and place the following code:

import React from 'react';

const SimpleComponent = ({ first, last, favFood }) => (
  <div>
    <h1>Hello there!</h1>
    <h2>Welcome!</h2>
    <p>First Name - {first}</p>
    <p>Last Name - {last}</p>
    <p>Favorite Food - {favFood}</p>
  </div>
);

export default SimpleComponent;

Now in our __tests__ folder, let's add the following code in a file called SimpleComponent.test.js:

import React from 'react';
import SimpleComponent from '../SimpleComponent';
import renderer from 'react-test-renderer';

describe('<SimpleComponent />', () => {
  it('matches the snapshot', () => {
    var tree = renderer.create(<SimpleComponent />).toJSON();
    expect(tree).toMatchSnapshot();
  });
});

When we run npm test we should see everything passing! We can also see that in our __tests__ folder, a folder called __snapshots__ has been created. In here, we can see our SimpleComponent.test.js.snap file which looks like this:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<SimpleComponent /> matches the snapshot 1`] = `
<div>
  <h1>
    Hello there!
  </h1>
  <p>
    First Name -
  </p>
  <p>
    Last Name -
  </p>
  <p>
    Favorite Food -
  </p>
</div>
`;

This is the saved snapshot! Now let's go and edit our SimpleComponent.js file and insert a new h2 which says Welcome! And let's see what happens with our test. We now see that there is a failing test because the snapshots are different! So we are faced with two choices here

  1. go fix the component because this UI change is not something we wanted

    or

  2. update the snapshot to include our new UI

In our terminal, there is an option for us to press u to update the snapshot, so let's do that and we should see the tests are passing again!

In summary, snapshot testing is fantastic as a really quick and easy way to test the UI of components. Learn more about it here.

When you're ready, move on to Testing with Enzyme

Continue

Creative Commons License