Day 2 of 5

Testing React Components

React Testing Library (RTL) tests components the way users interact with them — by querying the DOM, not component internals. Today you will render components, fire events, and assert on screen output.

bash
npm install --save-dev @testing-library/react @testing-library/user-event @testing-library/jest-dom
jsx
// Button.test.jsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';

test('renders label and calls onClick', async () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>Save</Button>);

  const btn = screen.getByRole('button', { name: /save/i });
  expect(btn).toBeInTheDocument();

  await userEvent.click(btn);
  expect(handleClick).toHaveBeenCalledTimes(1);
});
jsx
// Form.test.jsx — async state updates
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { LoginForm } from './LoginForm';

test('shows error on empty submit', async () => {
  render(<LoginForm />);

  await userEvent.click(screen.getByRole('button', { name: /login/i }));

  await waitFor(() => {
    expect(screen.getByText(/email is required/i)).toBeInTheDocument();
  });
});

test('calls onSubmit with credentials', async () => {
  const onSubmit = jest.fn();
  render(<LoginForm onSubmit={onSubmit} />);

  await userEvent.type(screen.getByLabelText(/email/i), '[email protected]');
  await userEvent.type(screen.getByLabelText(/password/i), 'secret123');
  await userEvent.click(screen.getByRole('button', { name: /login/i }));

  expect(onSubmit).toHaveBeenCalledWith({
    email: '[email protected]',
    password: 'secret123',
  });
});

Exercise: Test a Form Component

  1. Build a ContactForm with name/email/message fields
  2. Write a test: empty submit shows validation errors
  3. Write a test: valid submit calls onSubmit with values
  4. Write a test: fields clear after successful submit
  5. Mock a fetch call and assert the API was called

Day 2 Summary

Finished this lesson?