Testing React & Redux Applications

Ryan C. Collins
Caffeine and Testing
5 min readSep 25, 2016

--

Just like everything in the JavaScript world, there are 100s of different testing utilities to choose from to test React applications. I am hoping that this article can serve as a starting point for others who are looking to setup a testing stack in their projects.

Background

In the Scalable React Boilerplate project, an open source micro-framework that I maintain, I have gone through numerous different testing setups, finally arriving at the one I am using primarily today. Initially, we started with a setup that used Karma, Mocha, Enzyme, Sinon and Expect. This setup was great, but it required complex setup to get right and it was also very slow, having to spin up a browser (or multiple browsers) each time it ran the test suite.

GrommetUX, an open source React UX framework recently released a new testing setup that primarily uses Facebook’s Jest testing framework. As a contributor to the GrommetUX project, I gained a great appreciation for how much Jest’s snapshotting feature simplified the testing for Grommet, which is a very large and complex UI component library.

You can read a bit about how the Grommet team made the decision to integrate Jest here. The highlight of the article, is the comical analogy of the Jest Snapshot system, as shown below.

This may have been a joke, but realistically it sums up the Jest snapshotting feature better than words could.

Integrating Jest

In order to integrate Jest, I needed to make sure that I could also continue to utilize AirBnb’s Enzyme library, so I created a branch of the boilerplate project to give it a go. What I found was that there is a simple utility called enzyme-to-json that connects Jest and Enzyme together.

After this discovery, I was sold on the idea of transitioning to Jest. I spent an hour or two wiping out the Karma configuration and integrating Jest. It was a very smooth transition and as a result, my component tests have been greatly simplified.

Let’s take a look at a simple test using Jest and Enzyme.

import Header from '../index';
import { shallow } from 'enzyme';
import { shallowToJson } from 'enzyme-to-json';
import React from 'react';
describe('<Header />', () => {
it('should render with default props', () => {
const wrapper = shallow(
<Header
content="Hello World"
/>
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});

As you can see, we are shallow rendering our component. Using the shallowToJson plugin, we are able to create a representation of our shallow rendered component and write that to a snapshot file. In practice, this technique allows you to record a snapshot of your component and use it as a means to record the history of your component. Changes to the component will no longer match the snapshot, which will cause a failing test the next time you run your test suite.

On top of this, we can continue to run non-shapshot based tests doing component introspection with Enzyme, which allows you to make assertions about the structure of your components.

Testing Redux

In integrating Jest, the Redux based tests did not need to be changed at all. Testing Redux applications is actually very easy, as the method for testing Reducers and Action Creators is just as predictable as writing them in the first place. In fact, this is one of the main draws to Redux. It makes testing so darn simple.

Action Creators

Testing action creators is as easy as asserting that given a specific input, they will return a specific output. Since action creators are pure functions that take input and return an Action, it is very simple to reason about the assertions. You can see an example of an action creator test here, and below is a short example.

import expect from 'expect';
import * as actions from '../actions';
import {
LOAD_DATA_INITIATION,
// ... More constants here
} from '../constants';
describe('FeatureFirstContainer actions', () => {
it('should dispatch an action to initiate loading', () => {
const expectedAction = {
type: LOAD_DATA_INITIATION,
};
expect(
actions.loadDataInitiation()
).toEqual(expectedAction);
});
// ... more tests here
});

As you can see, we are asserting that the action creator returns the expected action. Also note that we are still using the Expect library here. Jest does include a built in assertion library, but it is also possible to use any other assertion library simply by importing it in your tests.

Reducers

Testing Reducers is just as easy as testing our action creators since Reducers are also pure functions. All we need to do is make assertions about the state before the reducer and then the state after the reducer. See here for a full example test.

In the example above, we are setting the state to show that the UI is loading data, so our reducer test will look something like this:

it('should initiate loading', () => {
const stateAfter = {
isLoading: true,
data: {},
error: {},
};
expect(
reducer(initialState, {
type: types.LOAD_DATA_INITIATION,
})
).toEqual(stateAfter);
});

Connected Containers

Testing connected containers introduces a bit of complexity because our state needs to be connected to the Redux Store. Redux makes this pretty simple, however, providing us with a mock store.

import FeatureFirstContainer from '../index';
import React from 'react';
import { shallow } from 'enzyme';
import { shallowToJson } from 'enzyme-to-json';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { initialState as featureComponent } from '../reducer';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('<FeatureFirstContainer />', () => {
it('renders with default props', () => {
const store = mockStore({ featureComponent });
const wrapper = shallow(
<FeatureFirstContainer store={store} />
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});

As you can see above, we are able to mock our store fairly easily. We import our initial state and pass it into our mock store with the proper key, in this case featureComponent. Once the store is properly mocked, it’s just like testing any other component.

More Resources

This article is meant to be more of a starting place, rather than an in depth guide to testing React applications. Please feel free to take a look at the setup in the Scalable React Boilerplate project, or any of my other open-source projects.

Included below are some of the resources I used in setting up and testing my React projects.

--

--

Ryan C. Collins
Caffeine and Testing

Hey, I’m Ryan! I work in the Tech industry and post content about tech, leadership, and personal finance. https://www.ryanccollins.com