
React Testing
- 1 installs
- 404 repo stars
- Updated August 5, 2026
- aiskillstore/marketplace
react-testing is a skill that provides Jest and React Testing Library patterns for testing React components, hooks, and Zustand stores.
About
This skill provides React testing patterns using Jest and React Testing Library for web applications. It covers Zustand store testing, async store operations, component testing, React Query testing, custom hook testing, and mocking API calls. A developer uses it when writing tests or debugging test failures in React web apps.
- Jest and React Testing Library patterns for web
- Zustand store, React Query, and custom hook testing
- Component testing and API-call mocking recipes
React Testing by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,750 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
react-testing capabilities & compatibility
- Capabilities
- testing · debugging
- Use cases
- testing · debugging · frontend
- Pricing
- Free
What react-testing says it does
Testing patterns for React with Jest and React Testing Library. Use when writing tests, mocking modules, testing Zustand stores, or debugging test failures in React web applications.
React testing requires understanding component rendering, user interactions, and async state management.
npx skills add https://github.com/aiskillstore/marketplace --skill react-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 404 |
| Last updated | August 5, 2026 |
| Repository | aiskillstore/marketplace ↗ |
What it does
Write Jest and React Testing Library tests for React components, hooks, and Zustand stores.
Who is it for?
Developers writing or debugging Jest and React Testing Library tests for React web apps.
Skip if: React Native testing or E2E browser testing.
When should I use this skill?
Writing tests, mocking modules, testing Zustand stores, or debugging React test failures.
What you get
Produces Jest and React Testing Library tests for components, hooks, stores, and API mocks.
- React component tests
- hook and store tests
- API-call mocks
By the numbers
- 6 testing patterns (store, async store, component, React Query, hook, API mocking)
Files
React Testing (Web)
Problem Statement
React testing requires understanding component rendering, user interactions, and async state management. This skill covers Jest with React Testing Library patterns for web applications.
---
Pattern: Zustand Store Testing
Problem: Store state persists between tests, causing flaky tests.
import { useAppStore } from '@/stores/appStore';
const initialState = {
items: [],
loading: false,
error: null,
};
describe('App Store', () => {
// Reset store before each test
beforeEach(() => {
useAppStore.setState(initialState, true); // true = replace entire state
});
it('adds item to store', async () => {
const store = useAppStore.getState();
await store.addItem({ id: '1', name: 'Test' });
expect(useAppStore.getState().items).toHaveLength(1);
});
it('handles loading state', async () => {
const store = useAppStore.getState();
const loadPromise = store.fetchItems();
expect(useAppStore.getState().loading).toBe(true);
await loadPromise;
expect(useAppStore.getState().loading).toBe(false);
});
});Key points:
- Use
setState(initialState, true)to replace (not merge) state - Get fresh state with
getState()after async operations - Don't rely on component re-renders in store tests
---
Pattern: Async Store Operations
Problem: Testing async Zustand actions with proper waiting.
import { act, waitFor } from '@testing-library/react';
it('loads data correctly', async () => {
const store = useAppStore.getState();
// Wrap async store operations in act
await act(async () => {
await store.loadData('123');
});
// Verify state after async completes
await waitFor(() => {
const state = useAppStore.getState();
expect(Object.keys(state.data).length).toBeGreaterThan(0);
});
});
// For complex flows, verify each step
it('completes multi-step flow', async () => {
const store = useAppStore.getState();
// Step 1
await act(async () => {
await store.loadItems();
});
expect(useAppStore.getState().items).toBeDefined();
// Step 2
await act(async () => {
await store.processItems();
});
expect(useAppStore.getState().processed).toBe(true);
});---
Pattern: Component Testing
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
describe('ItemCard', () => {
const mockItem = {
id: '1',
title: 'Test Item',
price: 99.99,
};
it('displays item data', () => {
render(<ItemCard item={mockItem} />);
expect(screen.getByText('Test Item')).toBeInTheDocument();
expect(screen.getByText('$99.99')).toBeInTheDocument();
});
it('calls onClick when clicked', async () => {
const user = userEvent.setup();
const onClick = jest.fn();
render(<ItemCard item={mockItem} onClick={onClick} />);
await user.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledWith(mockItem.id);
});
it('shows loading state', () => {
render(<ItemCard item={mockItem} loading />);
expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
});
});---
Pattern: React Query Testing
Problem: Components using React Query need QueryClientProvider.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render, screen, waitFor } from '@testing-library/react';
function createTestQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
retry: false,
gcTime: 0,
},
},
});
}
function renderWithQuery(ui: React.ReactElement) {
const queryClient = createTestQueryClient();
return render(
<QueryClientProvider client={queryClient}>
{ui}
</QueryClientProvider>
);
}
// Usage in tests
it('fetches and displays data', async () => {
renderWithQuery(<UserProfile userId="123" />);
// Shows loading initially
expect(screen.getByText('Loading...')).toBeInTheDocument();
// Wait for data
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
});
});---
Pattern: Custom Hook Testing
import { renderHook, act, waitFor } from '@testing-library/react';
describe('useAuth', () => {
it('signs in user', async () => {
const { result } = renderHook(() => useAuth(), {
wrapper: AuthProvider, // If hook needs context
});
await act(async () => {
await result.current.signIn('test@example.com', 'password');
});
expect(result.current.user).toBeDefined();
expect(result.current.isAuthenticated).toBe(true);
});
it('handles sign in error', async () => {
const { result } = renderHook(() => useAuth(), {
wrapper: AuthProvider,
});
await act(async () => {
try {
await result.current.signIn('invalid@example.com', 'wrong');
} catch (e) {
// Expected
}
});
expect(result.current.error).toBe('Invalid credentials');
});
});
// Hook with Zustand
describe('useUserData', () => {
beforeEach(() => {
useUserStore.setState(initialState, true);
});
it('returns current user data', () => {
// Pre-populate store
useUserStore.setState({ user: { id: '1', name: 'Test' } });
const { result } = renderHook(() => useUserData());
expect(result.current.user.name).toBe('Test');
});
});---
Pattern: Mocking API Calls
// Mock fetch globally
global.fetch = jest.fn();
beforeEach(() => {
(fetch as jest.Mock).mockClear();
});
it('fetches user data', async () => {
(fetch as jest.Mock).mockResolvedValueOnce({
ok: true,
json: async () => ({ id: '1', name: 'John' }),
});
render(<UserProfile userId="1" />);
await waitFor(() => {
expect(screen.getByText('John')).toBeInTheDocument();
});
expect(fetch).toHaveBeenCalledWith('/api/users/1');
});
// Mock specific module
jest.mock('@/api/users', () => ({
getUser: jest.fn(),
updateUser: jest.fn(),
}));
import { getUser, updateUser } from '@/api/users';
it('loads and updates user', async () => {
(getUser as jest.Mock).mockResolvedValue({ id: '1', name: 'John' });
(updateUser as jest.Mock).mockResolvedValue({ id: '1', name: 'Jane' });
// Test component that uses these
});---
Pattern: Router Testing
import { MemoryRouter, Routes, Route } from 'react-router-dom';
function renderWithRouter(ui: React.ReactElement, { route = '/' } = {}) {
return render(
<MemoryRouter initialEntries={[route]}>
{ui}
</MemoryRouter>
);
}
// Test navigation
it('navigates to profile on button click', async () => {
const user = userEvent.setup();
renderWithRouter(
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/profile" element={<ProfilePage />} />
</Routes>
);
await user.click(screen.getByText('Go to Profile'));
expect(screen.getByText('Profile Page')).toBeInTheDocument();
});
// Test with route params
it('displays user from route params', async () => {
renderWithRouter(
<Routes>
<Route path="/users/:id" element={<UserPage />} />
</Routes>,
{ route: '/users/123' }
);
await waitFor(() => {
expect(screen.getByText('User 123')).toBeInTheDocument();
});
});---
Pattern: Form Testing
import userEvent from '@testing-library/user-event';
describe('LoginForm', () => {
it('submits form with entered data', 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: 'Sign In' }));
expect(onSubmit).toHaveBeenCalledWith({
email: 'test@example.com',
password: 'password123',
});
});
it('shows validation errors', async () => {
const user = userEvent.setup();
render(<LoginForm onSubmit={jest.fn()} />);
// Submit without filling form
await user.click(screen.getByRole('button', { name: 'Sign In' }));
expect(screen.getByText('Email is required')).toBeInTheDocument();
expect(screen.getByText('Password is required')).toBeInTheDocument();
});
it('disables submit while loading', async () => {
render(<LoginForm onSubmit={jest.fn()} loading />);
expect(screen.getByRole('button', { name: 'Sign In' })).toBeDisabled();
});
});---
Pattern: Avoiding act() Warnings
Problem: "Warning: An update inside a test was not wrapped in act(...)"
// WRONG - state update happens after test
it('loads data', () => {
render(<DataComponent />);
// Component fetches data async, updates state after test ends
});
// CORRECT - wait for async completion
it('loads data', async () => {
render(<DataComponent />);
// Wait for loading to complete
await waitFor(() => {
expect(screen.getByText('Data loaded')).toBeInTheDocument();
});
});
// CORRECT - use findBy* (has built-in waitFor)
it('loads data', async () => {
render(<DataComponent />);
const element = await screen.findByText('Data loaded');
expect(element).toBeInTheDocument();
});---
Pattern: Snapshot Testing
When to use:
- UI components with stable structure
- Design system components
- Components where visual regression matters
When to avoid:
- Components with dynamic content
- Components that change frequently
- Large component trees (brittle)
// Good snapshot candidate - stable UI component
it('renders correctly', () => {
const { container } = render(<Button variant="primary">Submit</Button>);
expect(container).toMatchSnapshot();
});
// Bad snapshot candidate - dynamic content
it('renders user list', () => {
// Don't snapshot - list content varies
// Instead, test specific behaviors
});---
Pattern: Testing Context Providers
// Create a wrapper with all providers
function AllProviders({ children }: { children: React.ReactNode }) {
const queryClient = createTestQueryClient();
return (
<QueryClientProvider client={queryClient}>
<AuthProvider>
<ThemeProvider>
{children}
</ThemeProvider>
</AuthProvider>
</QueryClientProvider>
);
}
function renderWithProviders(ui: React.ReactElement) {
return render(ui, { wrapper: AllProviders });
}
// Use in tests
it('renders with all context', () => {
renderWithProviders(<Dashboard />);
// Component has access to all providers
});---
Test Commands
npm test # Run all tests
npm test -- --watch # Watch mode
npm test -- --coverage # Coverage report
npm test -- Button # Run specific test file
npm test -- --updateSnapshot # Update snapshots
npm test -- --runInBand # Run tests serially (debugging)---
Common Issues
| Issue | Solution |
|---|---|
| "Cannot find module" | Check jest moduleNameMapper config |
| act() warning | Wrap state updates in act(), use waitFor/findBy |
| Store state bleeding | Add beforeEach with setState reset |
| Async test timeout | Increase timeout or check for hanging promises |
| Mock not working | Verify mock path matches import path exactly |
| Query not found | Use findBy* for async content, check accessibility |
---
Recommended File Structure
__tests__/
utils/
test-utils.tsx # Custom render with providers
query-test-utils.tsx # QueryClient wrapper
jest.setup.js # Global mocks and setup
jest.config.js # Jest configuration{
"schema_version": "2.0",
"meta": {
"generated_at": "2026-01-16T21:12:34.819Z",
"slug": "cjharmath-react-testing",
"source_url": "https://github.com/CJHarmath/claude-agents-skills/tree/main/skills/react-testing",
"source_ref": "main",
"model": "claude",
"analysis_version": "3.0.0",
"source_type": "community",
"content_hash": "7d2151b1205b4915a8f47ad72daec94bba6a974e3810c4b7fd37adf3581c3346",
"tree_hash": "e6b7b455b53046430f8b71711bc449558361a41ccc14493fb1bea6e567115847"
},
"skill": {
"name": "react-testing",
"description": "Testing patterns for React with Jest and React Testing Library. Use when writing tests, mocking modules, testing Zustand stores, or debugging test failures in React web applications.",
"summary": "Testing patterns for React with Jest and React Testing Library. Use when writing tests, mocking modu...",
"icon": "🧪",
"version": "1.0.0",
"author": "CJHarmath",
"license": "MIT",
"category": "coding",
"tags": [
"react",
"jest",
"testing",
"react-testing-library",
"typescript"
],
"supported_tools": [
"claude",
"codex",
"claude-code"
],
"risk_factors": [
"network",
"external_commands"
]
},
"security_audit": {
"risk_level": "safe",
"is_blocked": false,
"safe_to_publish": true,
"summary": "Pure documentation skill containing only markdown content with TypeScript testing pattern examples. Static findings are false positives - the scanner misinterpreted markdown code formatting and metadata fields as security issues. No executable code, network calls, file system access, or command execution capabilities. Safe for publication.",
"risk_factor_evidence": [
{
"factor": "network",
"evidence": [
{
"file": "skill-report.json",
"line_start": 6,
"line_end": 6
}
]
},
{
"factor": "external_commands",
"evidence": [
{
"file": "SKILL.md",
"line_start": 18,
"line_end": 51
},
{
"file": "SKILL.md",
"line_start": 51,
"line_end": 54
},
{
"file": "SKILL.md",
"line_start": 54,
"line_end": 55
},
{
"file": "SKILL.md",
"line_start": 55,
"line_end": 64
},
{
"file": "SKILL.md",
"line_start": 64,
"line_end": 98
},
{
"file": "SKILL.md",
"line_start": 98,
"line_end": 104
},
{
"file": "SKILL.md",
"line_start": 104,
"line_end": 139
},
{
"file": "SKILL.md",
"line_start": 139,
"line_end": 147
},
{
"file": "SKILL.md",
"line_start": 147,
"line_end": 183
},
{
"file": "SKILL.md",
"line_start": 183,
"line_end": 189
},
{
"file": "SKILL.md",
"line_start": 189,
"line_end": 238
},
{
"file": "SKILL.md",
"line_start": 238,
"line_end": 244
},
{
"file": "SKILL.md",
"line_start": 244,
"line_end": 281
},
{
"file": "SKILL.md",
"line_start": 281,
"line_end": 287
},
{
"file": "SKILL.md",
"line_start": 287,
"line_end": 327
},
{
"file": "SKILL.md",
"line_start": 327,
"line_end": 333
},
{
"file": "SKILL.md",
"line_start": 333,
"line_end": 371
},
{
"file": "SKILL.md",
"line_start": 371,
"line_end": 379
},
{
"file": "SKILL.md",
"line_start": 379,
"line_end": 403
},
{
"file": "SKILL.md",
"line_start": 403,
"line_end": 419
},
{
"file": "SKILL.md",
"line_start": 419,
"line_end": 431
},
{
"file": "SKILL.md",
"line_start": 431,
"line_end": 437
},
{
"file": "SKILL.md",
"line_start": 437,
"line_end": 461
},
{
"file": "SKILL.md",
"line_start": 461,
"line_end": 467
},
{
"file": "SKILL.md",
"line_start": 467,
"line_end": 474
},
{
"file": "SKILL.md",
"line_start": 474,
"line_end": 493
},
{
"file": "SKILL.md",
"line_start": 493,
"line_end": 500
}
]
}
],
"critical_findings": [],
"high_findings": [],
"medium_findings": [],
"low_findings": [],
"dangerous_patterns": [],
"files_scanned": 2,
"total_lines": 681,
"audit_model": "claude",
"audited_at": "2026-01-16T21:12:34.819Z"
},
"content": {
"user_title": "Write React Tests with Jest and Testing Library",
"value_statement": "Testing React components requires understanding component rendering, user interactions, and async state management. This skill provides ready-to-use patterns for Jest and React Testing Library that help you write reliable tests for components, stores, hooks, and async operations.",
"seo_keywords": [
"react testing",
"jest",
"react testing library",
"typescript",
"component testing",
"zustand testing",
"claude code",
"claude",
"codex",
"react hooks testing"
],
"actual_capabilities": [
"Write unit tests for React components with React Testing Library",
"Test Zustand store state management and async actions",
"Mock API calls and module imports in tests",
"Test custom React hooks with renderHook",
"Handle async testing patterns with waitFor and findBy",
"Set up test providers for React Query and routing"
],
"limitations": [
"Does not execute tests - provides patterns only",
"Does not configure Jest or testing environment",
"Does not generate test files automatically",
"Does not run or debug tests in real-time"
],
"use_cases": [
{
"target_user": "React developers new to testing",
"title": "Learn component testing basics",
"description": "Get started with React Testing Library by following patterns for rendering components, finding elements, and verifying behavior."
},
{
"target_user": "Frontend engineers",
"title": "Test complex state management",
"description": "Learn how to test Zustand stores, handle async store operations, and reset store state between tests to avoid flaky tests."
},
{
"target_user": "Full-stack developers",
"title": "Mock APIs and test async flows",
"description": "Set up proper mocking for fetch calls, test React Query integration, and handle loading and error states in components."
}
],
"prompt_templates": [
{
"title": "Basic component test",
"scenario": "Write a test for a button component",
"prompt": "Write a Jest test for a Button component using React Testing Library. The component should accept label and onClick props. Use userEvent for the click interaction."
},
{
"title": "Store reset pattern",
"scenario": "Fix store state bleeding in tests",
"prompt": "Show me how to properly reset Zustand store state between tests to prevent state from leaking between test cases."
},
{
"title": "Async hook test",
"scenario": "Test custom hook with loading state",
"prompt": "Write a test for a useUserData custom hook that fetches user data. Include loading state verification and proper cleanup between tests."
},
{
"title": "Router integration",
"scenario": "Test navigation with params",
"prompt": "How do I test a React Router component that displays user details from URL params using MemoryRouter and waitFor assertions?"
}
],
"output_examples": [
{
"input": "Write a test for a login form that validates email and password fields, shows required errors, and submits data on button click.",
"output": [
"Set up userEvent for realistic form interactions",
"Fill email and password fields with test data",
"Assert validation errors appear when fields are empty",
"Verify submit handler receives form data on click",
"Check loading state disables submit button during submission"
]
}
],
"best_practices": [
"Use getByRole and findBy queries instead of test IDs for accessible element finding",
"Wrap async operations in act() to avoid state update warnings",
"Reset store state in beforeEach to prevent test pollution"
],
"anti_patterns": [
"Using implementation details like class names instead of accessible roles",
"Skipping act() wrappers for async state updates",
"Testing internal state instead of rendered output"
],
"faq": [
{
"question": "Which AI tools support this skill?",
"answer": "This skill works with Claude, Codex, and Claude Code for writing and debugging React tests."
},
{
"question": "What testing frameworks are covered?",
"answer": "The skill covers Jest and React Testing Library patterns for component, store, and hook testing."
},
{
"question": "How do I test components with React Query?",
"answer": "Create a test QueryClient with disabled retry, wrap components in QueryClientProvider, and use waitFor for async assertions."
},
{
"question": "Is my test data safe?",
"answer": "Yes. This skill only provides patterns. Tests run locally in your environment with your test data."
},
{
"question": "Why do I get act() warnings?",
"answer": "State updates happening outside act() cause warnings. Wrap async operations in act() or use findBy queries which include built-in waiting."
},
{
"question": "How is this different from Jest docs?",
"answer": "This skill provides ready-to-use patterns for common React scenarios including stores, hooks, providers, and async flows."
}
]
},
"file_structure": [
{
"name": "SKILL.md",
"type": "file",
"path": "SKILL.md",
"lines": 501
}
]
}
Related skills
FAQ
How do I reset a Zustand store between tests?
Use setState(initialState, true) in beforeEach to replace rather than merge state.
Does it cover React Query?
Yes, it shows wrapping components in a test QueryClientProvider with retry disabled.