This document provides guidelines and instructions for writing and running tests in the Involved Talent v2 project.
- Vitest: Unit and integration tests
- Playwright: End-to-end (E2E) tests
- React Testing Library: Component tests
# Run all tests once
npm test
# Run tests in watch mode (for development)
npm run test:watch
# Run tests with UI
npm run test:ui
# Generate coverage report
npm run test:coverage# Run all E2E tests
npm run test:e2e
# Run E2E tests with UI
npm run test:e2e:ui
# Debug E2E tests
npm run test:e2e:debugsrc/
__tests__/
setup.ts # Global test setup
utils/
test-helpers.ts # Reusable test utilities
fixtures/
users.ts # Test data fixtures
clients.ts
mocks/
next-router.ts # Mock implementations
lib/
utils/
__tests__/
*.test.ts # Unit tests
components/
__tests__/
*.test.tsx # Component tests
e2e/
auth/
signin.spec.ts # E2E tests
dashboard/
clients.spec.ts
Unit tests should test individual functions and utilities in isolation.
Example:
import { describe, it, expect } from 'vitest'
import { validateHexColor } from '@/lib/utils/color-validation'
describe('validateHexColor', () => {
it('should validate correct hex colors', () => {
expect(validateHexColor('#2D2E30')).toBe(true)
expect(validateHexColor('#FFBA00')).toBe(true)
})
it('should reject invalid hex colors', () => {
expect(validateHexColor('invalid')).toBe(false)
expect(validateHexColor('#GGG')).toBe(false)
})
})Component tests should test user interactions and component behavior.
Example:
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { Button } from '@/components/ui/button'
describe('Button', () => {
it('should render correctly', () => {
render(<Button>Click me</Button>)
expect(screen.getByText('Click me')).toBeInTheDocument()
})
})E2E tests should test complete user flows across the application.
Example:
import { test, expect } from '@playwright/test'
test('user can sign in', async ({ page }) => {
await page.goto('/auth/login')
await page.fill('input[name="email"]', 'test@example.com')
await page.fill('input[name="password"]', 'password123')
await page.click('button[type="submit"]')
await expect(page).toHaveURL('/dashboard')
})Use fixtures for consistent test data:
import { mockUser } from '@/__tests__/fixtures/users'
// Use in tests
const user = mockUserUse test helpers for common operations:
import { renderWithProviders } from '@/__tests__/utils/test-helpers'
// Render component with providers
renderWithProviders(<MyComponent />)- Unit tests: 80%+ code coverage
- Feature tests: All critical user flows covered
- Component tests: All public components tested
Tests run automatically on:
- Pull requests to
mainordevelop - Pushes to
mainordevelop
The CI pipeline includes:
- Unit and integration tests
- E2E tests
- Coverage reporting
- Test behavior, not implementation: Focus on what the code does, not how it does it
- Use descriptive test names: Test names should clearly describe what is being tested
- Keep tests isolated: Each test should be independent and not rely on other tests
- Use fixtures for test data: Don't hardcode test data in tests
- Mock external dependencies: Mock Supabase, API calls, etc.
- Clean up after tests: Use
afterEachto clean up test data - Test edge cases: Don't just test the happy path
Make sure path aliases are configured correctly in vitest.config.ts and match tsconfig.json.
Increase timeout in playwright.config.ts or use test.setTimeout() in individual tests.
Make sure @vitest/coverage-v8 is installed and coverage is enabled in vitest.config.ts.