Expand unit, E2E, and utility tests for full coverage. Co-authored-by: Moheeb Zara <1184415+virgilvox@users.noreply.github.com>
5.5 KiB
Testing Documentation
This project uses Vitest for unit/integration tests and Playwright for end-to-end testing.
Quick Start
# Install Playwright browsers (first time only)
npx playwright install
# Run unit tests (watch mode)
pnpm test
# Run unit tests with UI
pnpm test:ui
# Run E2E tests
pnpm test:e2e
# Run E2E tests with UI
pnpm test:e2e:ui
Test Coverage
| Category | Tests | Coverage |
|---|---|---|
| Actions | 50+ | Auth, Tasks, Projects, Members, Payments, Contacts, KB, Secrets |
| Components | 30+ | Badges, Tabs, Cards, Status, Toast, Empty, Loading |
| Utilities | 40+ | Date, String, Number, Array, Validation, URL |
| E2E Flows | 50+ | Auth, Dashboard, Tasks, Ops, Members, Payments, Projects |
Unit Tests (Vitest)
Unit tests are located in __tests__/ directory.
Test Structure
-
__tests__/actions.test.ts- Server actions and business logic (50+ tests)- Authentication (signIn, signOut, getUser)
- Member status validation (current, unverified, late)
- Task CRUD and filtering
- Project management
- Member management (role-based access)
- Payment management (treasurer access)
- Contact management
- Knowledge base operations
- Secrets management
- Activity logging
- RLS policy validation
-
__tests__/components.test.tsx- React components (30+ tests)- TaskBadge (count display, overflow)
- TabButton (active states, click handlers)
- TaskCard (claim, complete, delete actions)
- StatusBadge (color coding by status)
- Toast notifications
- Empty states
- Loading spinners
- Task filtering logic
-
__tests__/utils.test.ts- Utility functions (40+ tests)- Date formatting and comparison
- String manipulation (initials, codes, truncation)
- Number formatting (currency)
- Array operations (groupBy, sortBy, unique)
- Validation (email, phone, required fields)
- URL utilities
- Status and role checks
Writing Tests
import { describe, it, expect, beforeEach, vi } from 'vitest'
describe('Feature', () => {
beforeEach(() => {
// Setup before each test
})
it('should do something', () => {
expect(result).toBe(expected)
})
})
Key Testing Patterns
Mocking Supabase:
const mockSupabase = {
from: vi.fn().mockReturnThis(),
select: vi.fn().mockReturnThis(),
eq: vi.fn().mockReturnThis(),
single: vi.fn().mockResolvedValue({ data: { ...} }),
}
Testing Async Functions:
it('should fetch data', async () => {
const result = await myAsyncFunction()
expect(result).toBeDefined()
})
E2E Tests (Playwright)
E2E tests are located in e2e/ directory and test complete user flows.
Test Structure
-
e2e/critical-flows.spec.ts- Critical user journeys (40+ tests)- Landing & authentication
- Dashboard loading and navigation
- Tasks management (tabs, filtering, creation)
- Operations & knowledge base
- Members management
- Payments management
- Projects management
- Contacts management
- Communications
- Settings
- Mobile navigation
- Error handling
- Performance (load time checks)
- Accessibility (headings, alt text, focus)
-
e2e/auth.spec.ts- Authentication flows (15+ tests)- Login form display and validation
- Signup flow
- Session management
- Protected route access
- Password reset
- OAuth (if configured)
Writing E2E Tests
import { test, expect } from '@playwright/test'
test.describe('Feature', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/path')
})
test('should do something', async ({ page }) => {
await page.click('button')
await expect(page.locator('text=Success')).toBeVisible()
})
})
Common E2E Patterns
Navigation:
await page.goto('/tasks', { waitUntil: 'networkidle' })
Interaction:
await page.click('button:has-text("Add")')
await page.fill('input[name="title"]', 'New Task')
Assertions:
await expect(page.locator('text=Task created')).toBeVisible()
expect(page.url()).toContain('/tasks')
Coverage
Run tests with coverage:
npm test -- --coverage
Coverage reports are generated in coverage/ directory.
CI/CD Integration
Tests are configured to run in CI environments. Key CI-specific behaviors:
- E2E tests retry 2x on failure
- Screenshots/videos saved for failed tests
- Full parallelization in CI
Debugging
Vitest:
npm test -- --inspect-brk
Playwright:
npm run test:e2e -- --debug
Best Practices
- Test Behavior, Not Implementation - Test what the user sees, not how code works
- Keep Tests Isolated - Each test should be independent
- Use Meaningful Names - Test names should describe what's being tested
- Mock External Dependencies - Mock Supabase, APIs, etc.
- Test Happy & Sad Paths - Test both success and failure scenarios
Adding New Tests
When adding features:
- Add unit tests in
__tests__/for business logic - Add E2E tests in
e2e/for user flows - Run
npm testto verify - Check coverage with
npm test -- --coverage
Troubleshooting
Tests timing out:
- Increase timeout:
test('...', async () => {...}, { timeout: 10000 })
Playwright can't find elements:
- Use
--debugto step through:npm run test:e2e -- --debug - Check selectors with:
await page.pause()
Vitest isolation issues:
- Clear mocks:
vi.clearAllMocks()inbeforeEach - Reset modules:
vi.resetModules()