Testing Context

When using react-testing-library testing components using React Context is no different than testing any other kind of component.

Since we are testing the generated HTML and not how is it generated, the fact that something happens thanks to using React Context is an implementation detail we should not be interested in.

All we have to do is to wrap the tested component inside the Context.Provider, exactly as you would in a normal application.

For example, a component that uses react-intl can be tested like this

import React from "react";
import { FormattedMessage } from "react-intl";

export function UnreadMessages({ unreadCount }) {
  return (
    <p>
      <FormattedMessage
        id="welcome"
        defaultMessage={`you have {unreadCount, number} {unreadCount, plural,
                      one {message}
                      other {messages}
                    }`}
        values={{ unreadCount }}
      />
    </p>
  );
}

Normal usage

import React from "react";
import ReactDOM from "react-dom";
import { UnreadMessages } from "./UnreadMessages";

// normal usage

ReactDOM.render(
  <IntlProvider locale="en">
    <UnreadMessages />
  </IntlProvider>,
  document.getElementById("container")
);

While testing

test("100 messages", () => {
  const { getByText } = render(
    <IntlProvider locale="en">
      <UnreadMessages unreadCount={100} />
    </IntlProvider>
  );
  getByText("you have 100 messages");
});

test("one message", () => {
  const { getByText } = render(
    <IntlProvider locale="en">
      <UnreadMessages unreadCount={1} />
    </IntlProvider>
  );
  getByText("you have 1 message");
});

Dealing with multiple contexts

Sometimes may not be practical to use the provider directly. For example, if the provider requires a setup involving complex props or we have a high number of providers. In such cases a common approach is to create a testing utility that wraps render with all the providers you use in your app

function renderWithProviders(ui, { reduxState, locale = "en" }) {
  const store = createStore(reducer, reduxState || initialState);
  return (
    <ThemeProvider>
      <ReduxProvider store={store}>
        <IntlProvider locale={locale}>{ui}</IntlProvider>
      </ReduxProvider>
    </ThemeProvider>
  );
}

note: to avoid duplication, you can create a single <AppProvider/> with all the providers you need and ues it both in testing and React app easily.

Author: Jaga Santagostino

results matching ""

    No results matching ""