Isaac.

react

Testing React Components

Write effective unit and integration tests for React applications.

By Emem IsaacOctober 29, 20243 min read
#react#testing#jest#testing library#unit tests
Share:

A Simple Analogy

Testing React components is like quality assurance for assembly parts. Each component is tested independently and in combination.


Why Component Tests?

  • Regression prevention: Catch breaking changes
  • Refactoring confidence: Safe code changes
  • Documentation: Tests show expected behavior
  • Maintainability: Early issue detection
  • User experience: Test actual interactions

Jest Setup

// package.json
{
  "devDependencies": {
    "@testing-library/react": "^14.0.0",
    "@testing-library/jest-dom": "^6.1.0",
    "jest": "^29.0.0"
  }
}

// jest.config.js
export default {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/test/setup.ts'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  }
}

Component Testing

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

describe('Button', () => {
  it('renders with text', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });
  
  it('calls onClick when clicked', () => {
    const onClick = jest.fn();
    render(<Button onClick={onClick}>Click</Button>);
    
    screen.getByText('Click').click();
    expect(onClick).toHaveBeenCalledTimes(1);
  });
  
  it('disables when prop is true', () => {
    render(<Button disabled>Disabled</Button>);
    expect(screen.getByRole('button')).toBeDisabled();
  });
});

User Events

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { LoginForm } from './LoginForm';

describe('LoginForm', () => {
  it('submits form with valid input', async () => {
    const user = userEvent.setup();
    const onSubmit = jest.fn();
    
    render(<LoginForm onSubmit={onSubmit} />);
    
    await user.type(screen.getByLabelText('Email'), 'test@example.com');
    await user.type(screen.getByLabelText('Password'), 'password123');
    await user.click(screen.getByRole('button', { name: /submit/i }));
    
    expect(onSubmit).toHaveBeenCalledWith({
      email: 'test@example.com',
      password: 'password123'
    });
  });
});

Async Testing

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

describe('UserList', () => {
  it('loads and displays users', async () => {
    render(<UserList />);
    
    // Component is loading
    expect(screen.getByText(/loading/i)).toBeInTheDocument();
    
    // Wait for data to load
    await waitFor(() => {
      expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
    });
    
    // Users displayed
    expect(screen.getByText('Alice')).toBeInTheDocument();
    expect(screen.getByText('Bob')).toBeInTheDocument();
  });
});

Mocking Modules

import { render, screen } from '@testing-library/react';
import { ProductPage } from './ProductPage';
import * as api from '@/api/products';

jest.mock('@/api/products');

describe('ProductPage', () => {
  beforeEach(() => {
    jest.mocked(api.getProduct).mockResolvedValue({
      id: '1',
      name: 'Widget',
      price: 29.99
    });
  });
  
  it('displays product data', async () => {
    render(<ProductPage productId="1" />);
    
    expect(await screen.findByText('Widget')).toBeInTheDocument();
    expect(screen.getByText('$29.99')).toBeInTheDocument();
  });
});

Snapshot Testing

import { render } from '@testing-library/react';
import { Card } from './Card';

describe('Card', () => {
  it('renders correctly', () => {
    const { container } = render(
      <Card title="Test">
        <p>Content</p>
      </Card>
    );
    
    expect(container).toMatchSnapshot();
  });
});

Best Practices

  1. Test behavior: Not implementation
  2. Semantic queries: Use accessible queries
  3. User events: Simulate real interactions
  4. Avoid snapshots: Prefer specific assertions
  5. Test user flows: Integration tests matter

Related Concepts

  • End-to-end testing
  • Visual regression
  • Performance testing
  • Accessibility testing

Summary

Use React Testing Library to test components through user interactions rather than implementation details. Focus on what users see and do.

Share:

Written by Emem Isaac

Expert Software Engineer with 15+ years of experience building scalable enterprise applications. Specialized in ASP.NET Core, Azure, Docker, and modern web development. Passionate about sharing knowledge and helping developers grow.

Ready to Build Something Amazing?

Let's discuss your project and explore how my expertise can help you achieve your goals. Free consultation available.

💼 Trusted by 50+ companies worldwide | ⚡ Average response time: 24 hours