Generate comprehensive Vitest and React Testing Library tests for frontend components, hooks, and utilities. Covers test structure, incremental workflow, async patterns, mocking strategies, and coverage goals. Use when writing or reviewing frontend tests, improving coverage, or setting up testing infrastructure for React projects.
Generate high-quality, comprehensive frontend tests following established conventions and best practices.
Apply this skill when:
Do NOT apply when:
| Tool | Purpose |
|---|
| Vitest | Test runner |
| React Testing Library | Component testing |
| jsdom | Test environment |
| nock | HTTP mocking |
| TypeScript | Type safety |
# Run all tests
npm test # or: pnpm test / yarn test
# Watch mode
npm run test:watch
# Run specific file
npx vitest path/to/file.spec.tsx
# Generate coverage report
npx vitest --coverage
ComponentName.spec.tsx (same directory as component)__tests__/ directoryimport { render, screen, fireEvent, waitFor } from '@testing-library/react'
import Component from './index'
// Mock external dependencies only
vi.mock('@/service/api')
vi.mock('next/navigation', () => ({
useRouter: () => ({ push: vi.fn() }),
usePathname: () => '/test',
}))
describe('ComponentName', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// Rendering tests (REQUIRED)
describe('Rendering', () => {
it('should render without crashing', () => {
render(<Component title="Test" />)
expect(screen.getByText('Test')).toBeInTheDocument()
})
})
// Props tests (REQUIRED)
describe('Props', () => {
it('should apply custom className', () => {
render(<Component className="custom" />)
expect(screen.getByRole('button')).toHaveClass('custom')
})
})
// User Interactions
describe('User Interactions', () => {
it('should handle click events', () => {
const handleClick = vi.fn()
render(<Component onClick={handleClick} />)
fireEvent.click(screen.getByRole('button'))
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
// Edge Cases (REQUIRED)
describe('Edge Cases', () => {
it('should handle null data', () => {
render(<Component data={null} />)
expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle empty array', () => {
render(<Component items={[]} />)
expect(screen.getByText(/empty/i)).toBeInTheDocument()
})
})
})
NEVER generate all test files at once. For complex components or multi-file directories:
For each file:
1. Write test
2. Run: npx vitest <file>.spec.tsx
3. PASS? -> Mark complete, next file
FAIL? -> Fix first, then continue
Process in this order for multi-file testing:
Prefer integration testing when writing tests for a directory:
next/navigation, complex context providersButton, Input, Loading, etc.)When assigned to test a directory/path, test ALL content within that path:
Every test should clearly separate:
getByRole, getByLabelText)// Prefer role-based queries
expect(screen.getByRole('status')).toBeInTheDocument()
// Prefer pattern matching
expect(screen.getByText(/loading/i)).toBeInTheDocument()
Each test verifies ONE user-observable behavior:
// Good: One behavior
it('should disable button when loading', () => {
render(<Button loading />)
expect(screen.getByRole('button')).toBeDisabled()
})
// Bad: Multiple behaviors
it('should handle loading state', () => {
render(<Button loading />)
expect(screen.getByRole('button')).toBeDisabled()
expect(screen.getByText('Loading...')).toBeInTheDocument()
expect(screen.getByRole('button')).toHaveClass('loading')
})
Use should <behavior> when <condition>:
it('should show error message when validation fails')
it('should call onSubmit when form is valid')
it('should disable input when isReadOnly is true')
| Feature | Test Focus |
|---|---|
useState | Initial state, transitions, cleanup |
useEffect | Execution, dependencies, cleanup |
| Event handlers | All onClick, onChange, onSubmit, keyboard |
| API calls | Loading, success, error states |
| Routing | Navigation, params, query strings |
useCallback/useMemo | Referential equality |
| Context | Provider values, consumer behavior |
| Forms | Validation, submission, error display |
references/async-testing.md - Async operations, fake timers, and API testing patternsreferences/checklist.md - Test generation checklist and validation stepsreferences/common-patterns.md - Query priority, event handling, forms, modals, listsreferences/mocking.md - Mock patterns, Zustand stores, factory functionsreferences/workflow.md - Incremental testing workflow for multi-file directoriesassets/component-test.template.tsx - Component test templateassets/hook-test.template.ts - Hook test templateassets/utility-test.template.ts - Utility function test template