Software systems to innovate and grow

6 React Testing Options You Must Try in JavaScript

By Engineering Team February 4, 2019 10 mins read

Testing in JavaScript (JS) has come a long way in the last couple of years, especially in the React ecosystem. Testing in JS is nothing new, and numerous solutions have been kicking around since the advent of frontend application development. Today, the testing landscape is much friendlier than it used to be.

Devs now have plenty of testing options, which are steadily improving as more and more companies jump on the React bandwagon and start providing feedback or pull requests to their preferred frameworks.

With so many great choices, though, comes the dreaded spectre of JavaScript fatigue. Which framework is the best? What combination makes the most sense for your app? For devs less seasoned in software testing, these can be daunting questions.

React does provide recommendations for testing frameworks, but it’s a little more than a few links with brief descriptions and doesn’t explain much.

Luckily, the Gistia team is here to guide you through the wild and evolving world of React testing. We’ll take a look at React’s recommendations, plus a couple of others that we think are pretty awesome.

Let’s get going!

Software Testing Definitions

If you are new to software testing or just need a refresher, it’ll help to have an idea of the types of tests we’ll be discussing.

  • Unit Tests
    • Unit tests are focused on individual units within a program. Expected outputs of functions, components, and modules are the target here, and being able to write unit tests easily is a sign that a program is highly modular.
  • Functional Tests
    • When we want to test the functionality of components in React, we write functional tests. They’re focused on behavior instead of output and usually run in isolation.
  • Integration Tests
    • Integration tests attempt to imitate the actual user experience of an app. These tend to be significantly slower than unit and functional tests since they have to run against a real browser, attempting to test the expectations of the virtual DOM and the real DOM.

Now that we know a bit about terminology, let’s check out the best options for testing in React.

React Testing Options

The official Facebook recommendations for testing are pretty good, but some guidance upfront is necessary to make sense of what to use, and how:

  • Enzyme
    • This is Airbnb’s testing utility for React. It allows you to assert, manipulate, and traverse your components’ output using a jQuery-like API. Enzyme is not a test runner and is usually combined with something like Jest, Jasmine, or Mocha.
  • Jest
    • This is the framework Facebook uses for all its internal JavaScript testing, including React. Built on the popular Jasmine framework, it has extra functionality like snapshots (more on this in a bit) that make it perfect for testing React components.
  • React-testing-library
    • Built by the prolific Kent C. Dodds, this simple React DOM utility library can work with any testing framework, though he does recommend using it with Jest. Designed to be lightweight and resistant to breakage from code refactoring, this is a great addition to any React testing approach.
  • React-unit
    • Another lightweight option, React-unit is ideal when you don’t want to have to install any other big dependencies like JSDOM or a Python runtime.
  • Skin-deep
    • Testing helper that works with React’s built-in shallow rendering testing tools.
  • Unexpected-react
    • A plugin for the Unexpected testing toolkit that allows for full React virtual DOM testing, making it easier to assert over components and trigger events.

Two Additions & One Honorable Mention

Just to add a little complexity to this whole thing, there are several other popular testing frameworks not listed by Facebook on the official React site:

  • Tape
    • Tape is a small TAP-producing JavaScript test harness for unit testing. Because it maintains a minimal core and requires very little configuration, Tape has gained cult status with some JS devs looking for a simple alternative to larger, more opinionated testing frameworks.
  • RITEway
    • Eric Elliott is a thought leader in the JavaScript community, and this is his testing baby. A long-time advocate for functional JS and overall simplicity in code, he built RITEway to be just that: simple, with no automagic effects that can cause confusion in big projects.
  • Mocha
    • We couldn’t talk JavaScript testing without mentioning Mocha. One of the longest-running test frameworks for JS in Node and the browser, many teams still rely on it for all their testing, if for no other reason than they know it well.

      That said, given the reams of content already available on the topic and the current trajectory of the React testing landscape, we won’t be covering Mocha in this post.

A Quick Note on React Test Utilities

ReactTestUtils is a supplemental library from the React team that can be used with essentially any testing tool. In fact, Enzyme requires it to function, wrapping it in a jQuery-like API with two other well-known libraries (JSDOM and CheerIO).

Using it alone is clunky and usually just not done, but some of the testing tools we’ve mentioned will tap into it.

Testing React with Jest & Enzyme

Since we can’t cover every combination of tools listed above, we’re just going to focus on the most popular combination as of this writing: Jest & Enzyme.

Why are they so popular, you ask? Well, as we mentioned above, the two tools were made and are maintained by Facebook and Airbnb, respectively, which gives them significant street cred.

More importantly, though, they were created specifically for React testing, which means you can get going much more quickly and easily than you can with most other test runners and tools.

Let’s go through a quick example and then discuss the pros and cons of this approach.

Getting Started

To get started, we need to install Enzyme:

And, Jest:

Note: Create React App ships with Jest, so you just need to install react-test-renderer if you used it to start your app.

At this point, your package.json should look like this, where is the latest version of the installation:

A Word on Snapshots

Snapshots are a nifty tool specific to Jest. It captures snapshot artifacts, files that contain rendered HTML snippets from your UI and compares it against a stored artifact of the expected result. When the files don’t match, it triggers an error. Cool, right?

Snapshots are one of the reasons Jest is so popular with React devs. Let’s take a look at how to implement a test and then modify it to take a snapshot.

Jest/Enzyme Example

Suppose we have a basic header component in Header.js that we want to test:

To write a test to make sure it’s rendering, we create a file called Header.test.js in a separate tests folder:

We imported Enzyme and shallow from enzyme, as well as the Adapter from enzyme-adapter-react-16. The Adapter is responsible for rendering the UI library (React 16, in this case), and shallow allows us to test the Header component without having to render its children, allowing for a pure unit test.

The test() method runs our test, and the first argument is the test name that will be displayed in the result. The second argument is where we put our expectations for the test. Here, we’re telling our test to expect a rendered Header and return an error if something else happens.

To run the test, add this to your package.json:

The –verbose flag gives you a nice hierarchical view of all your test reports.

In the terminal:

Jest should give you a nice printout of your

Now, let’s modify our test to take snapshots.

Using Snapshots

The key change here is adding toMatchSnapshot() to expect(). Now, when we run our test, it’ll give us an error. Wait, what?

Yep, the first time you run a Snapshot test, it will give you an error, and it’s because you need an initial snapshot to compare with the new one.

To capture that first shot, head back over to the terminal, and in your project directory, type:

Jest will create a subdirectory in your tests directory called __snapshots__. All your snapshots will go in there. The one we just ran is called Header.test.js.snap and looks like this (truncated):

Now, if we make any changes to Header.js without updating the snapshot, Jest will give us an error message when we run it. Sweet!

And there you have it. A unit test that checks our Header component to make sure it renders and does so according to our expectations.

Pros & Cons

Jest and Enzyme both have a ton more to them which is great for those wanting a complete tool that makes getting started with React testing a breeze.

But no solution is perfect. We’ve touched on a few of these already, but let’s quickly review the pros and cons of this approach:

Pros

  • Designed for React
    • As we mentioned earlier, Jest is built by Facebook and is used for all their JavaScript testing, making it perfect for React. Enzyme isn’t built by Facebook but is a very nice react-test-utils wrapper that makes using that library much easier. Taken together, they are a perfect solution for big teams and open source projects.
  • Popularity
    • The Jest/Enzyme combination is very popular in the React community, which means there are loads of blog posts, Stack Overflow answers, and solved Github issues online to get you through any tricky spots.
  • Robust Tooling
    • The testing options you have at your disposal with Jest/Enzyme are ample, including mocking, assertions, setups/teardowns, and asynchronous testing. While other test runners and helper library combinations have these options, none will work quite so simply and easily with React.

Cons

  • Works Automagically
    • Like most of the other big test runners for JavaScript, Jest tries to do a lot right out of the box, including things like automatic mocking. These features seem nice at first since they take the pain out of getting started, but they can create strange side effects that are hard to figure out down the road.
  • Pollutes the Global Namespace
    • Most JavaScript developers have heard of the perils of polluting the global namespace with variables (again, side effects). Jest adds variables to the global namespace like test and describe, which could conflict with variables in the code you’re trying to test.
  • Shared State
    • Global Jest functions like beforeAll() and afterEach() make it possible to share state between tests, something that should generally be avoided. Ideally, you should keep state confined to individual tests, and these functions can make it easy to break that practice.

Wrapping Up

At this point, you should have a good grasp on some of the most popular and varied testing options for React, as well as some familiarity using the most popular tool combo, Jest and Enzyme.

Our next post on testing will delve into a completely different set of tools that manage to avoid the cons listed above: TAPE and RITEway. Of course, since no solution is perfect, there are some tradeoffs that have to be considered, and we’ll get into those in that next tutorial.

In the meantime, give Jest and Enzyme a go, and start getting that test coverage percentage up! Your code and apps will be much better as a result.
Have fun, and keep coding!