Basic Reducer Test

Build a basic code to test the reducers.

We'll cover the following

Testing reducers is similar to testing action creators because reducers are idempotent. This means that it will return the same new state every time given a state and an action. This makes reducer tests very easy to write, as we simply need to call the reducer with different combinations of input to verify the correctness of the output.

Basic reducer test

For our test, we can create a very crude reducer that handles a single ADD_RECIPE action and whose state is simply an array of recipes:

import { ADD_RECIPE } from 'constants.js';

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_RECIPE:
      return state.concat({ title: action.payload });
  }

  return state;
};

export default reducer;

There are two main test cases to consider, adding a recipe to an empty list and a non-empty one. We can test the first case as follows:

import reducer from 'reducers/recipes';
import { ADD_RECIPE } from 'constants';

// always wrap tests in a describe block
describe('reducers/recipes', () => {
  it('should add recipe to empty list', () => {
    const initialState = [];
    const action       = { type: ADD_RECIPE, payload: 'test' };
    const expected = [{ title: "test" }];
    const actual= reducer(initialState, action);

    expect(actual).toEqual(expected);
  });
};

The steps taken here should already be familiar:

  1. Calculate the initial state (an empty array in our case).
  2. Build the action to send.
  3. Set the expected state the reducer should return.
  4. Call reducer() to calculate the state based on the empty array and our action.
  5. Verify that the actual and expected states match.

Before we simplify the code, let’s consider the second test case, adding a recipe to a non-empty list:

it('should add recipe to non-empty list', () => {
  const initialState = [{ title: "first" }];
  const action = { type: ADD_RECIPE, payload: 'test' };
  const expected = [{ title: "first" }, { title: "test" }];
  const actual = reducer(initialState, action);

  expect(actual).toEqual(expected);
});

In this test, we start with a single item list and update our expected result to match. While this works, it has a maintenance problem. What will happen if our recipes contain more fields in the future?

Get hands-on with 1200+ tech skills courses.