polvara.me

Mocking Context with React Testing Library

Mar 23, 2019 · This post is popular! ⭐️

I noticed several people getting 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:

The more your tests resemble the way your software is used, the more confidence they can give you.

Kent C. Dodds

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", () => {
  render(
    <UserContext.Provider value={null}>
      <UserGreeter />
    </UserContext.Provider>
  );
  expect(screen.getByText("Hello stranger!")).toBeInTheDocument();
});

test("UserGreeter salutes a user", () => {
  const user = { name: "Giorgio" };
  render(
    <UserContext.Provider value={user}>
      <UserGreeter />
    </UserContext.Provider>
  );
  expect(screen.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", () => {
  renderUserGreeter(null);
  expect(screen.getByText("Hello stranger!")).toBeInTheDocument();
});

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

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