2.4 KiB
2.4 KiB
Testing Guide
Overview
This project uses Vitest and React Testing Library for testing.
Running Tests
# Run tests in watch mode
npm run test
# Run tests once
npm run test:run
# Run tests with UI
npm run test:ui
# Run tests with coverage
npm run test:coverage
Test Structure
src/
├── components/
│ ├── __tests__/
│ │ └── ProtectedRoute.test.tsx
│ └── ProtectedRoute.tsx
├── lib/
│ ├── __tests__/
│ │ └── utils.test.ts
│ └── utils.ts
├── pages/
│ └── login/
│ ├── __tests__/
│ │ └── index.test.tsx
│ └── index.tsx
└── test/
├── setup.ts # Test setup
└── test-utils.tsx # Custom render with providers
Writing Tests
Component Tests
import { describe, it, expect } from 'vitest'
import { render, screen } from '@/test/test-utils'
import MyComponent from '../MyComponent'
describe('MyComponent', () => {
it('should render correctly', () => {
render(<MyComponent />)
expect(screen.getByText('Hello')).toBeInTheDocument()
})
})
Testing with User Interactions
import userEvent from '@testing-library/user-event'
it('should handle click', async () => {
const user = userEvent.setup()
render(<Button>Click me</Button>)
await user.click(screen.getByRole('button'))
expect(screen.getByText('Clicked')).toBeInTheDocument()
})
Testing API Calls
import { vi } from 'vitest'
import { adminApiHelpers } from '@/lib/api-client'
vi.mock('@/lib/api-client', () => ({
adminApiHelpers: {
getUsers: vi.fn(),
},
}))
it('should fetch users', async () => {
const mockGetUsers = vi.mocked(adminApiHelpers.getUsers)
mockGetUsers.mockResolvedValue({ data: [] })
// Test component that calls getUsers
})
Coverage Goals
- Statements: 80%+
- Branches: 75%+
- Functions: 80%+
- Lines: 80%+
Best Practices
- Test behavior, not implementation
- Use semantic queries (getByRole, getByLabelText)
- Avoid testing implementation details
- Mock external dependencies
- Keep tests simple and focused
- Use descriptive test names
CI Integration
Tests run automatically on:
- Every push to main/develop
- Every pull request
- Before deployment
See .github/workflows/ci.yml for details.