testing-components

djankies's avatarfrom djankies

Teaches React Testing Library patterns for React 19 components. Use when writing component tests, testing interactions, or testing with Server Actions.

⭐0stars🔀0forks📁View on GitHub🕐Updated Nov 25, 2025

When & Why to Use This Skill

This Claude skill provides expert guidance and standardized patterns for testing React 19 components using React Testing Library (RTL). It focuses on modern best practices for verifying UI components, handling complex user interactions, and implementing robust test suites for the latest React features, including Server Actions and the useActionState hook.

Use Cases

  • Writing unit and integration tests for React 19 components to ensure correct rendering and accessibility compliance.
  • Testing complex form logic and validation states specifically using the new React 19 useActionState hook and Server Actions.
  • Simulating realistic user behaviors such as clicks, typing, and navigation using user-event to validate interactive elements.
  • Verifying component behavior within nested providers by implementing effective testing patterns with React Context.
  • Mocking external modules and API actions with Vitest to isolate component logic and improve test reliability.
nametesting-components
descriptionTeaches React Testing Library patterns for React 19 components. Use when writing component tests, testing interactions, or testing with Server Actions.
allowed-toolsRead, Write, Edit
version1.0.0

Testing React 19 Components

For Vitest test structure and mocking patterns (describe/test blocks, vi.fn(), assertions), see vitest-4/skills/writing-vitest-tests/SKILL.md.

Basic Component Testing

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

test('button renders and handles click', async () => {
  const handleClick = vi.fn();

  render(<Button onClick={handleClick}>Click me</Button>);

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

  await userEvent.click(button);
  expect(handleClick).toHaveBeenCalledTimes(1);
});

Testing Forms with useActionState

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

vi.mock('./actions', () => ({
  submitContact: vi.fn(async (prev, formData) => {
    const email = formData.get('email');
    if (!email?.includes('@')) {
      return { error: 'Invalid email' };
    }
    return { success: true };
  }),
}));

test('form shows error for invalid email', async () => {
  render(<ContactForm />);

  await userEvent.type(screen.getByLabelText(/email/i), 'invalid');
  await userEvent.click(screen.getByRole('button', { name: /submit/i }));

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

test('form succeeds with valid email', async () => {
  render(<ContactForm />);

  await userEvent.type(screen.getByLabelText(/email/i), 'test@example.com');
  await userEvent.click(screen.getByRole('button', { name: /submit/i }));

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

Testing with Context

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

test('displays user name from context', () => {
  const user = { name: 'Alice', email: 'alice@example.com' };

  render(
    <UserProvider value={user}>
      <UserProfile />
    </UserProvider>
  );

  expect(screen.getByText('Alice')).toBeInTheDocument();
});

For comprehensive testing patterns, see: React Testing Library documentation.