In this short article I wll show how you can verify dispatched Redux actions when your component uses useDispatch from react-redux. Additionslly, as a good practice, I split component logic in two files: one is responsible for presentational layer and the other connects it with data and is called a container.

This way we have separated concerns and we can easily test the presentation. But still, you may want to test the code living in the container that dispatches multiple actions to the store.

What if you want to intercept calls to dispatch while at the same time have mocked store updated?

First, let's set up context. We'll use Jest and Enzyme testing frameworks here.

We start with a simple presentational component:

import * as React from "react";

export function Component({
  onClick,
  someProp
}) {
  return (
      <button onClick={onClick}>Click me</button>
  );
}

Container.js

As you can see all the heavy lifting is placed in Container. It defines onClick action for Component as well as side effects that dispatch some Redux actions.

We'll be using mocking capabilities of Jest to mock useDispatch.

In Container.test.js we import useDispatch from react-redux and mock this package. Please notice that we're not shadowing the whole package, just a piece of it that we're interested in. jest.requireActual comes in handy.

import { useDispatch, Provider } from "react-redux";
import { mount } from "enzyme";
import { Container } from "./Container";

jest.mock("react-redux", () => {
  const { Provider, useSelector } = jest.requireActual("react-redux");

  return {
      useDispatch: jest.fn(),
      // we ensure that these are original  
      useSelector,
      Provider
  };
});

Container.test.js

Later, in a test or in beforeAll we create a wrapper for Container and create a mocked version of dispatch:

const dispatchMock = jest.fn();

const wrapper = mount(
  <Provider>
      <Container />
  </Provider>
);

// now we have access to the store instance
const globalStore = wrapper.find(Provider).prop("store");

Container.test.js

By initiating a Redux Provider we have access to the store instance. Now's the important part - we wrap the real implementation of dispatch with our mocked function that will be intercepting calls:

dispatchMock.mockImplementation(action => globalStore.dispatch(action));

Container.test.js

Finally we can mock the return value of useDispatch:

useDispatch.mockReturnValue(dispatchMock);

Container.test.js

OK, that's it!

We can now write a test or a series of tests and ensure that correct actions given certain conditions are dispatched to the store like:

import { action1, action2, action3 } from "./actions";

expect(dispatchMock).toHaveBeenCalledTimes(3);

expect(dispatchMock).toHaveBeenNthCalledWith(3, action3(3));

Container.test.js