React and Redux – Testing Redux


Welcome to Part 13 of this comprehensive review and summary of Cory House’s Pluralsight course Building Applications with React and Redux in ES6.

Cory is a Microsoft MVP in C#, founder of, avid tech reader, and speaker.

He believes in clean code, pragmatic development, and responsive native UIs.

Also in this series:

Part 1 – Introduction and Background

Part 2 – Environment Setup

Part 3 – React Component Approaches

Part 4 – Initial App Structure

Part 5 – Intro to Redux

Part 6 – Actions, Stores and Reducers

Part 7 – Connecting React to Redux

Part 8 – Redux Flow

Part 9 – Async in Redux

Part 10 – Async Writes in Redux

Part 11 – Async Status and Error Handling

Part 12 – Testing React

Testing Redux

Redux was designed with testability in mind, but as we’ll see in this module, it’s a little more challenging than just testing basic React presentation components. Once you’ve seen these challenges surmounted, you’ll be able to do the same yoursel, and will be able to write your Redux tests with confidence.

Testing Connected Components

Cory puts it simply: we have two objectives here:

  1. Test our component’s markup
  2. Test the component behavior

As we’ve already seen examples of testing markup in Part 12 – Testing React, we focus on testing behavior now.

Cory explains that all container components are wrapped in a call to connect, and in this clip he describes two ways to handle this:

We can create a custom store for our test by wrapping our component with a Provider.

If you only want to test the local rendering and state related behavior, just add a named export for an unconnected component.

The demonstration begins at (1:45) and we begin with ManageCoursePage.test.js, adding the necessary imports, and writing the spec

it(‘sets error message when trying to save empty title’,

Again we’re using enzyme to simplify our tests, and we see how to use mount. Our first roadblock is the error:

Invariant Violation: Could not find “store” in either the context or props of “Connect(ManageCoursePage)”. Either wrap the root component in a <Provider>, or explicitly pass “store” as a prop to “Connect(ManageCoursePage)”.

This error is helpful and tells us that we can either wrap our component in a Provider component, or export the raw component. If you want to test Redux related code such as mapStateToProps, use the former as the solution.

Cory prefers the second option, and demonstrates exporting the ManageCoursePage class and updating the import in ManageCoursePage.test.js. Unfortunately we still get an error:

TypeError: Cannot create property ‘map’ of undefined

We see that in SelectInput.js we are not exporting the information that we need in our test, and how we can easily fix this. But a minute later we get a similar error:

TypeError: Cannot create property ‘saveCourse’ of undefined

To solve this, Cory defines all props in an object in the test, and passes that property into the component using the ES6 spread operator.

We also stub our saveCourse action to return merely a resolved promise: effectively a no-op.

Cory could have made this look much simpler and easier by just pasting this code all in from the beginning, but here we see a realistic test troubleshooting process, which I think is far more valuable.

The test passing now but we haven’t written our assertion yet. Once added, we’re back to failing again. But this is because we haven’t written this production code yet. So we’re at the beginning of our Test Driven Development experience in React and Redux.

To get this test passing, Cory creates a new function, courseFormIsValid() in ManageCoursePage.js

We also see this running up in the browser successfully.

Testing mapStateToProps

So we’ve tested our connect components but not yet tested the Redux related pieces. mapStateToProps is a function that can potentially get complex, and we should not forget to also test this.

Our ManageCoursesPage.js is now huge. Cory extracts the function authorsFormattedForDropdown into a new file selectors.js. The idea is any functions that select data are selectors.

We create selectors.test.js to test

it(‘should return author data formatted for use in a dropdown’

Testing Action Creators

We begin with courseActions.test.js:

it(‘should create a CREATE_COURSE_SUCCESS action’

Testing Reducers

“One feedback I hear particularly often is that people who never wrote unit tests for front-end apps started writing them because it is just so easy to test reducers.”
– Dan Abramov

All we need to do is say given this input, assert this output.

Cory introduces us to Conor Hastings’ Redux Test Recorder. Because it’s currently experimental we don’t use it in this course, but it is a great idea and in my opinion a project well worth supporting.

Onto the demo, and we are testing our courseReducer.js with 2 tests:

it(‘should add course when passed CREATE_COURSE_SUCCESS’

it(‘should update course when passed UPDATE_COURSE_SUCCESS’

Testing Thunks

We mock two things:

  1. Store, with redux-mock-store
  2. HTTP calls, with nock

In courseActions.test.js, we add imports for both of these as well as thunk from ‘redux-thunk’.

We create our mockStore with configureMockStore, passing in our thunk middleware as an argument to configureMockStore.

This test doesn’t have the same high signal to noise ratio that our reducer test had. It quite a lot of code, which Cory explains in this clip.

Testing the Store

Cory explains that we’re writing integration tests rather than unit tests, and why this is so.

it(‘Should handle creating courses’

Here we’re testing the result that we get from the Store equals our expected value.

And that covers all of the different elements of a Redux app that you’ll want to test.

The final module of the course is on setting your production build.

Further Reading on Testing Redux

Redux Writing Tests Recipes

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s