Giorgio Polvara's Blog

Mocking Context with React Testing Library

Photo by Mae Mu

I noticed several people get confused on how to test React components that rely on a context with react-testing-library. Before I even explain how to test such components let me get something out of the way:

There is no need to mock your contexts in order to test them.

jest.mock and friends are extremely helpful for many test scenarios, but context is not one of them. So how do we go about testing it?

The answer is all in react-testing-library's core principle:

What does resemble the way your software is used mean in our case? Let's see a practical example:

const UserContext = React.createContext();

function App() {
  const user = getUserOrMaybeNot();

  return (
    <UserContext.Provider value={user}>
      <UserGreeter />
    </UserContext.Provider>
  );
}

function UserGreeter() {
  const user = React.useContext(UserContext);

  if (!user) return "Hello stranger!";
  return `Hello ${user.name}!`;
}

In this particular case, user could or could not be defined depending on what getUserOrMaybeNot returns.

You probably want to test that UserGreeter renders the correct thing in both cases. You might be tempted to render UserGreeter and mock the context somehow. That's not how your software is used though. Your component is rendered within a provider. Let's do that then.

test("UserGreeter salutes an anonymous user", () => {
  const { getByText } = render(
    <UserContext.Provider value={null}>
      <UserGreeter />
    </UserContext.Provider>
  );
  expect(getByText("Hello stranger!")).toBeInTheDocument();
});

test("UserGreeter salutes a user", () => {
  const user = { name: "Giorgio" };
  const { getByText } = render(
    <UserContext.Provider value={user}>
      <UserGreeter />
    </UserContext.Provider>
  );
  expect(getByText(`Hello ${user.name}!`)).toBeInTheDocument();
});

To avoid the repetition, you can move the render method in a helper function:

function renderUserGreeter(user) {
  return render(
    <UserContext.Provider value={user}>
      <UserGreeter />
    </UserContext.Provider>
  );
}

test("UserGreeter salutes an anonymous user", () => {
  const { getByText } = renderUserGreeter(null);
  expect(getByText("Hello stranger!")).toBeInTheDocument();
});

test("UserGreeter salutes a user", () => {
  const user = { name: "Giorgio" };
  const { getByText } = renderUserGreeter(user);
  expect(getByText(`Hello ${user.name}!`)).toBeInTheDocument();
});

If you want more information about testing context with react-testing-library check out the official docs and join the spectrum community for help getting you started.

Would you like to have a civil discussion about this post? Hit me up on twitter.