React Testing Examples

react-testing-library
GitHubAbout
All examples

The component reads and updates a server counter using the Fetch API.

We test that the component renders the counter value from the mocked API response. Then we click on the increment button, which makes a POST request to increment the counter, and afterwards test that the component renders the incremented value.

These tests are async because server requests don't resolve immediately. We wait for the button to appear before interacting with our component.

We use @react-mock/fetch to mock the server requests.

test.js
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
render(
<FetchMock
mocks={[
{ matcher: '/count', method: 'GET', response: { count } },
{ matcher: '/count', method: 'POST', response: { count: count + 1 } }
]}
>
<ServerCounter />
</FetchMock>
);
it('renders initial count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
// It takes time for the counter to appear because
// the GET request has a slight delay
await waitForElement(() => getByText(/clicked 5 times/i));
});
it('increments count', async () => {
// Render new instance in every test to prevent leaking state
const { getByText } = renderComponent({ count: 5 });
// It takes time for the button to appear because
// the GET request has a slight delay
await waitForElement(() => getByText('+1'));
fireEvent.click(getByText('+1'));
// The counter doesn't update immediately because
// the POST request is asynchronous
await waitForElement(() => getByText(/clicked 6 times/i));
});
// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
  render(
    <FetchMock
      mocks={[
        { matcher: '/count', method: 'GET', response: { count } },
        { matcher: '/count', method: 'POST', response: { count: count + 1 } }
      ]}
    >
      <ServerCounter />
    </FetchMock>
  );

it('renders initial count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  // It takes time for the counter to appear because
  // the GET request has a slight delay
  await waitForElement(() => getByText(/clicked 5 times/i));
});

it('increments count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 });

  // It takes time for the button to appear because
  // the GET request has a slight delay
  await waitForElement(() => getByText('+1'));
  fireEvent.click(getByText('+1'));

  // The counter doesn't update immediately because
  // the POST request is asynchronous
  await waitForElement(() => getByText(/clicked 6 times/i));
});