brackt/TESTING.md

238 lines
4.5 KiB
Markdown
Raw Normal View History

# Testing Guide
This document explains how to run and write tests for Brackt.com.
## Overview
We use two testing frameworks:
- **Vitest + React Testing Library** - Unit and component tests
- **Cypress** - End-to-end integration tests
## Running Tests
### Unit Tests
```bash
# Run tests in watch mode (interactive)
npm test
# Run tests once (CI mode)
npm run test:run
# Run tests with UI
npm run test:ui
# Run tests with coverage
npm run test:coverage
```
### E2E Tests
```bash
# Open Cypress interactive mode
npm run test:e2e
# Run Cypress headless (CI mode)
npm run test:e2e:headless
# Run all tests (unit + E2E)
npm run test:all
```
## Writing Tests
### Unit Tests
Unit tests go in `__tests__` directories next to the code they test:
```
app/
lib/
utils.ts
__tests__/
utils.test.ts
models/
league.ts
__tests__/
league.test.ts
```
Example unit test:
```typescript
import { describe, it, expect } from 'vitest';
import { myFunction } from '../myFunction';
describe('myFunction', () => {
it('should do something', () => {
const result = myFunction('input');
expect(result).toBe('expected output');
});
});
```
### Component Tests
Component tests also go in `__tests__` directories:
```
app/
components/
DraftGrid.tsx
__tests__/
DraftGrid.test.tsx
```
Example component test:
```typescript
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { MyComponent } from '../MyComponent';
describe('MyComponent', () => {
it('should render correctly', () => {
render(<MyComponent title="Test" />);
expect(screen.getByText('Test')).toBeInTheDocument();
});
});
```
### E2E Tests
E2E tests go in the `cypress/e2e` directory:
```
cypress/
e2e/
league-creation.cy.ts
league-settings.cy.ts
draft-room.cy.ts
```
Example E2E test:
```typescript
describe('Feature Name', () => {
it('should do something', () => {
cy.visit('/some-page');
cy.get('button').click();
cy.findByText('Expected Text').should('exist');
});
});
```
## Test Fixtures
Reusable test data is stored in `app/test/fixtures/`:
```typescript
// app/test/fixtures/league.ts
export const mockLeague = {
id: 'league-1',
name: 'Test League',
// ...
};
```
Import and use in tests:
```typescript
import { mockLeague } from '~/test/fixtures/league';
```
## CI/CD Integration
Tests run automatically on:
- Every push to `main` or `develop`
- Every pull request
### GitHub Actions Workflow
1. **Test Job** - Runs unit tests with PostgreSQL service
2. **Typecheck Job** - Runs TypeScript type checking
3. **Build Job** - Builds Docker image (only on main branch)
4. **Deploy Job** - Deploys to server (only after all tests pass)
**Tests must pass before deployment!**
## Coverage
Coverage reports are generated automatically:
- HTML report: `coverage/index.html`
- JSON report: `coverage/coverage-final.json`
View coverage locally:
```bash
npm run test:coverage
open coverage/index.html
```
## Best Practices
### Unit Tests
- Test one thing per test
- Use descriptive test names
- Mock external dependencies
- Aim for 80%+ coverage
### Component Tests
- Test user interactions, not implementation
- Use `screen.getByRole()` when possible
- Test accessibility
- Keep tests focused
### E2E Tests
- Test critical user flows
- Use `data-testid` sparingly
- Prefer semantic queries
- Keep tests independent
## Debugging Tests
### Vitest
```bash
# Run specific test file
npm test -- path/to/test.test.ts
# Run tests matching pattern
npm test -- --grep "pattern"
# Debug in VS Code
# Add breakpoint and use "Debug Test" in test file
```
### Cypress
```bash
# Open Cypress UI for debugging
npm run test:e2e
# Run specific test file
npx cypress run --spec "cypress/e2e/specific-test.cy.ts"
```
## Common Issues
### Tests fail locally but pass in CI
- Check Node version matches CI (v20)
- Ensure database is running locally
- Check environment variables
### Cypress tests timeout
- Increase timeout in `cypress.config.ts`
- Check if app is running on correct port
- Verify selectors are correct
### Coverage not generating
- Ensure `@vitest/coverage-v8` is installed
- Check `vitest.config.ts` coverage settings
- Run with `npm run test:coverage`
## Additional Resources
- [Vitest Documentation](https://vitest.dev/)
- [React Testing Library](https://testing-library.com/react)
- [Cypress Documentation](https://docs.cypress.io/)
- [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)