238 lines
4.5 KiB
Markdown
238 lines
4.5 KiB
Markdown
|
|
# 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)
|