Testing React applications

Testing a React component that uses useContext

Source: Youtube Kent C. Dodds

https://www.youtube.com/watch?v=3yiialslPbc

  1. React Testing Library: https://testing-library.com/docs/react-testing-library/setup
  2. Test Isolation with React: https://kentcdodds.com/blog/test-isolation-with-react
  3. Testing a React Context Provider: https://dev.to/manuartero/testing-a-react-context-provider-5cfg

How to test code within a Provider in React?

Testing code within a React Provider typically involves rendering the component(s) that consume the context provided by the Provider, and then interacting with those components to verify the expected behavior and state changes. Steps to test code within a Provider: Install Testing Libraries: Use libraries like @testing-library/react for rendering and interacting with React components, and a test runner like Jest.

npm install --save-dev @testing-library/react jest

Import Dependencies

In your test file, import render from @testing-library/react, along with the Provider and any consuming components you want to test.

Wrap Components with the Provider

When rendering the components under test, wrap them within the Provider. This allows the consuming components to access the context values.

import { render, screen } from '@testing-library/react';
import { MyProvider } from './MyProvider'; // Your context Provider
import { MyConsumerComponent } from './MyConsumerComponent'; // Component consuming context

test('MyConsumerComponent displays context value', () => {
  render(
        <MyProvider value={{ data: 'test value' }}>
          <MyConsumerComponent />
        </MyProvider>
  );

  // Assertions based on the rendered component's output
  expect(screen.getByText('test value')).toBeInTheDocument();
});

For isolated unit tests, you can provide mock values to the Provider’s value prop. This allows you to control the state and behavior of the context during testing, without relying on external dependencies or complex logic within the actual Provider.

test('MyConsumerComponent handles different context values', () => {
  const mockContextValue = { data: 'another value' };
  render(
        <MyProvider value={mockContextValue}>
          <MyConsumerComponent />
        </MyProvider>
  );
  expect(screen.getByText('another value')).toBeInTheDocument();
});

Simulate User Interactions

If your Provider or consuming components involve state changes or side effects triggered by user interactions (e.g., button clicks), use @testing-library/react utilities like fireEvent or userEvent to simulate these interactions and then assert the resulting changes in the UI or component state.

import { render, screen, fireEvent } from '@testing-library/react';
// ... imports

test('Provider updates state on button click', () => {
  render(
        <MyProvider>
          <MyButtonThatUpdatesContext />
        </MyProvider>
  );

  const button = screen.getByRole('button', { name: /update context/i });
  fireEvent.click(button);

  // Assert that the context-dependent UI has updated
  expect(screen.getByText('Context Updated!')).toBeInTheDocument();
});

By following these steps, you can effectively test the behavior and data flow within your React Providers and the components that consume their context.


Links to this note