Testing with React-Redux Hooks

With the rise of React Hooks, many developers have added hooks into their open source libraries. If you are using react-redux libraries, they also provided hooks such as useSelector and useDispatch as well.

Although hooks allow us to use redux with ease in React, however, there is not much documentation about unit testing with hooks. Thus, I’m going to show you how to unit test your react-redux hooks.

In class component, we can create a mock of the redux actions and states and pass them into the component for unit testing. As a matter of fact, there is not much difference in unit testing functional components with hooks. Instead of passing the mock state into the components, we can mock the implementation of `useSelector` to return state.

Imagine we have a component that looks like this:

import React from 'react';
import { useSelector } from 'react-redux';

const HelloWorld = () => {
  const user = useSelector(state => state.user);
  const skills = useSelector(state => state.skills);

  const { firstName } = user;

  return (
    <div>
      <p>First Name: {firstName}</p>
      <p>My Skills:</p>
      <ul>
        {skills.map(skill => (
          <p key={skill.id}>{skill.name}</p>
        ))}
      </ul>
    </div>
  );
}

export default HelloWorld;

We know useSelector is a function that takes a callback as the parameter. All we need to do is to mock the state and pass to the callback. The unit test would look like this:

import React from 'react';
import { render } from '@testing-library/react';
import { useSelector } from 'react-redux';
import HelloWorld from './HelloWorld';

jest.mock('react-redux', () => ({
  useDispatch: jest.fn(),
  useSelector: jest.fn(),
}));

describe('HelloWorld', () => {
  test('renders user with skills', () => {
    useSelector.mockImplementation((selector) => selector({
      user: {
        firstName: 'Tek Min',
      },
      skills: [
        {
          id: '1',
          name: 'Javascript',
        },
        {
          id: '2',
          name: 'React',
        },
      ],
    }));
    const { container } = render(<HelloWorld />);
    expect(container).toMatchSnapshot();
  });

  test('renders user without skills', () => {
    useSelector.mockImplementation((selector) => selector({
      user: {
        firstName: 'Tek Min',
      },
      skills: [],
    }));

    const { container } = render(<HelloWorld />);
    expect(container).toMatchSnapshot();
  });
});

If you check the snapshot, you will probably see something like this:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`HelloWorld renders user with skills 1`] = `
<div>
  <div>
    <p>
      First Name: 
      Tek Min
    </p>
    <p>
      My Skills:
    </p>
    <ul>
      <p>
        Javascript
      </p>
      <p>
        React
      </p>
    </ul>
  </div>
</div>
`;

exports[`HelloWorld renders user without skills 1`] = `
<div>
  <div>
    <p>
      First Name: 
      Tek Min
    </p>
    <p>
      My Skills:
    </p>
    <ul />
  </div>
</div>
`;

Great! we get the snapshot as we wanted, the components render correctly with different redux state.

You may find another way of testing with redux hooks in Google, but I find that this is one of the simplest version of doing it without additional libraries. Hope you find it helpful and have a nice day!

Leave a Reply

%d bloggers like this: