Testing in React with Jest and Enzyme: An Introduction
By: Ross Bulat
Tags: React, ES6, Programming, JavaScript, Software Engineering

Not using Create React App?

If you are not using Create React App, you can install Jest with npm or yarn:

yarn add --dev jest

#or

npm install --save-dev jest

In order to run jest with npm test , replace or append a test script to your scripts block within your package.json file:

...

scripts: {

"test": "jest",

...

}

Within a Create React App environment this will look slightly different, as react-scripts is called instead of jest : (Nothing needs to be changed here)

...

scripts: {

"test": "react-scripts test",

...

}

To verify things are working, run npm test now in your Terminal at your project root directory. You will now be in watch mode, and should see a prompt displaying something similar to “No tests found related to files changed since last commit”, along with some shortcuts to run tests in various ways.

So what is the best way to introduce tests to your React project? Let’s visit this first before diving into some more useful tools.

Start Using Jest

Jest discovers test files within your project via their filenames, of which can be located at any depth of your project. There are 3 naming conventions we can adopt in order for Jest to pick up our tests:

Any file with a .test.js suffix or a .spec.js suffix. This may be preferable when a component (e.g. App.js ) can be accompanied by an App.test.js file in the same directory, where they will reside next to each other. This optimises discoverability and keeps import statements to a minimum.

This may be preferable when a component (e.g. ) can be accompanied by an file in the same directory, where they will reside next to each other. This optimises discoverability and keeps import statements to a minimum. Any .js file within __tests__ folders throughout your project. If you have multiple test files to test a particular component or component directory, a __tests__ folder allows a more coherent structure whereby your tests and components are not mixed. This may be preferable in larger projects.

Which method you adopt is your call and will depend on your project.

Now let’s write a simple test to examine Jest syntax. Let’s add an App.test.js file within the same directory as App.js . This test will have no relation to App.js just yet, but instead will introduce some key methods of Jest; describe() and it() , as well as the expect() methods:

// App.test.js describe('Examining the syntax of Jest tests', () => {



it('sums numbers', () => {

expect(1 + 2).toEqual(3);

expect(2 + 2).toEqual(4);

});

});

Upon first glance you may find this test quite obvious, and that is a good thing; readability is an intentional design choice to keep tests simple and easy to understand.

Now, upon saving this test and provided you have Jest running in the Terminal, you should receive an output similar to the following:

Let’s break down the above example to understand this syntax:

describe() : An optional method to wrap a group of tests with. describe() allows us to write some text that explains the nature of the group of tests conducted within it. As you can see in the Terminal, the describe() text acts as a header before the test results are shown.

: An optional method to wrap a group of tests with. allows us to write some text that explains the nature of the group of tests conducted within it. As you can see in the Terminal, the text acts as a header before the test results are shown. it() : Similar in nature to describe() , it() allows us to write some text describing what a test should successfully achieve. You may see that the test() method is used instead of it() throughout the Jest documentation, and vice-versa in the Create React App documentation. Both are valid methods.

: Similar in nature to , allows us to write some text describing what a test should successfully achieve. You may see that the method is used instead of throughout the Jest documentation, and vice-versa in the Create React App documentation. Both are valid methods. expect() and .toEqual() : Here we carry out the test itself. The expect() method carries a result of a function, and toEqual() , in this case, carries a value that expect() should match.

expect() makes assertions: what is an assertion?

expect() is a global Jest function for making assertions. An assertion takes a boolean valued function and always expects that return value to be true — hence the name expect. In the event that false is returned, the test fails and execution stops within the corresponding it() or test() block.

toEqual() is a matcher: what is a matcher?

toEqual() is called a matcher. A matcher is a function whose resulting value must be true relative to what it is testing from expect() . Jest have documented the full list of matchers here, ranging from toContain , toBeFalsy , toMatch(regexpOrString) and toThrow(error) . It’s worthwhile familiarising yourself with what is available to optimise your test syntax.

We get a full breakdown of each test result in the Terminal. Green ticks highlight a success whereas red crosses highlight a failure.

To highlight a failure (hopefully a rare occasion!) let’s change the last test to expect(2 + 2).toEqual(5) :

Our terminal now displays some handy output, including exactly where our test failed within the script itself, line number and code.

Why test two or more sums instead of just one?

Our first example above tested a sum function twice, the first time with 1 + 2 and then with 2 + 2. This is important; and to demonstrate why, let’s now introduce a sum() function instead of hard-coding our sums:

// math.js export const sum = (x, y) => x + y;

And run the test with the updated sum() :

// App.test.js import {sum} from './math'; describe('Examining the syntax of Jest tests', () => {



it('sums numbers', () => {

expect(sum(1, 2)).toEqual(3);

expect(sum(2, 2)).toEqual(4);

});

});

Making these changes will again yield successful tests. However, what if we change sum() to the following:

export const sum = (x, y) => 3;

What we have done here is simply return a hard-coded value, 3, from our sum function. Now, if we simply left our test suite with a singular assertion of a 1 + 2 sum, the tests would have passed even though the sum function itself does not function as we wish — it always returns 3!