generated from coulomb/repo-seed
add: comprehensive TDD test infrastructure
- Add Vitest + jsdom testing framework - Create unit tests for engine.js and generator.js - Add integration tests for end-to-end workflows - Include test utilities and setup helpers - Document testing approach in TESTING.md - Document all dependencies in DEPENDS.md - Add Makefile with test targets and dev workflow 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
245
TESTING.md
Normal file
245
TESTING.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# Timeline SVG - Test Infrastructure
|
||||
|
||||
This document describes the test-driven development (TDD) infrastructure for the Timeline SVG Generator project.
|
||||
|
||||
## Test Framework Setup
|
||||
|
||||
The project uses **Vitest** with **jsdom** for testing browser-based JavaScript code.
|
||||
|
||||
### Dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"@vitest/ui": "^2.1.0",
|
||||
"@vitest/coverage-v8": "^2.1.0",
|
||||
"jsdom": "^25.0.0",
|
||||
"vitest": "^2.1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests once
|
||||
npm test
|
||||
|
||||
# Run tests in watch mode (for TDD)
|
||||
npm run test:watch
|
||||
|
||||
# Run with coverage report
|
||||
npm run test:coverage
|
||||
|
||||
# Open test UI (browser-based test runner)
|
||||
npm run test:ui
|
||||
```
|
||||
|
||||
## Test Structure
|
||||
|
||||
### Unit Tests
|
||||
|
||||
- **`test/engine.test.js`** - Tests for timeline data processing
|
||||
- CSV parsing and validation
|
||||
- Date parsing (multiple formats)
|
||||
- Project configuration loading
|
||||
- DOM integration
|
||||
|
||||
- **`test/generator.test.js`** - Tests for SVG generation
|
||||
- SVG template processing
|
||||
- Month grid generation
|
||||
- Lane and item positioning
|
||||
- XML escaping
|
||||
|
||||
### Integration Tests
|
||||
|
||||
- **`test/integration.test.js`** - End-to-end workflow tests
|
||||
- Complete timeline generation pipeline
|
||||
- File upload simulation
|
||||
- DOM event handling
|
||||
- Export functionality
|
||||
|
||||
### Test Utilities
|
||||
|
||||
- **`test/setup.js`** - Global test setup and mocks
|
||||
- **`test/testHelpers.js`** - Common test data and utilities
|
||||
|
||||
## TDD Workflow
|
||||
|
||||
### 1. Red Phase - Write Failing Test
|
||||
|
||||
```bash
|
||||
# Start test watcher
|
||||
npm run test:watch
|
||||
|
||||
# Create test for new feature
|
||||
touch test/newFeature.test.js
|
||||
```
|
||||
|
||||
Example test:
|
||||
```javascript
|
||||
describe('New Feature', () => {
|
||||
it('should do something specific', () => {
|
||||
const result = myNewFunction('input')
|
||||
expect(result).toBe('expected output')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### 2. Green Phase - Make Test Pass
|
||||
|
||||
Implement minimal code to make the test pass:
|
||||
|
||||
```javascript
|
||||
// In the appropriate source file
|
||||
function myNewFunction(input) {
|
||||
return 'expected output' // Minimal implementation
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Refactor Phase - Improve Code
|
||||
|
||||
```bash
|
||||
# Ensure tests still pass after refactoring
|
||||
npm test
|
||||
```
|
||||
|
||||
## Key Testing Patterns
|
||||
|
||||
### Mocking Browser APIs
|
||||
|
||||
```javascript
|
||||
// In test/setup.js
|
||||
global.fetch = vi.fn()
|
||||
global.Papa = { parse: vi.fn() }
|
||||
|
||||
// In tests
|
||||
mockFetch(sampleData)
|
||||
```
|
||||
|
||||
### DOM Testing
|
||||
|
||||
```javascript
|
||||
// Setup DOM elements
|
||||
setupBasicDOM()
|
||||
|
||||
// Test DOM manipulation
|
||||
await timelineEngine.loadProjectConfigObject(config)
|
||||
expectElementToHaveText('#projectName', 'Test Project')
|
||||
```
|
||||
|
||||
### Testing Vanilla JS Modules
|
||||
|
||||
Since the project uses global objects, tests load modules by evaluating the source:
|
||||
|
||||
```javascript
|
||||
const fs = await import('fs/promises')
|
||||
const engineCode = await fs.readFile('./engine.js', 'utf-8')
|
||||
eval(engineCode)
|
||||
const timelineEngine = global.window.timelineEngine
|
||||
```
|
||||
|
||||
## Coverage Goals
|
||||
|
||||
- **Statements**: >90%
|
||||
- **Branches**: >85%
|
||||
- **Functions**: >90%
|
||||
- **Lines**: >90%
|
||||
|
||||
View detailed coverage:
|
||||
```bash
|
||||
npm run test:coverage
|
||||
open coverage/index.html
|
||||
```
|
||||
|
||||
## Common Test Scenarios
|
||||
|
||||
### Testing Date Parsing
|
||||
|
||||
```javascript
|
||||
it('should parse various date formats', () => {
|
||||
expect(parseDate('2025-12-15')).toEqual(new Date(2025, 11, 15))
|
||||
expect(parseDate('15.12.2025')).toEqual(new Date(2025, 11, 15))
|
||||
expect(parseDate('invalid')).toBeNull()
|
||||
})
|
||||
```
|
||||
|
||||
### Testing SVG Generation
|
||||
|
||||
```javascript
|
||||
it('should generate valid SVG with timeline items', () => {
|
||||
const result = timelineGenerator.generate(items, config, template)
|
||||
expect(result).toContain('<svg xmlns="http://www.w3.org/2000/svg">')
|
||||
expect(result).toContain('Task Title')
|
||||
})
|
||||
```
|
||||
|
||||
### Testing Error Handling
|
||||
|
||||
```javascript
|
||||
it('should handle missing configuration gracefully', () => {
|
||||
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
timelineEngine.processCsv('data', null)
|
||||
expect(consoleSpy).toHaveBeenCalledWith('No config or fieldMapping found.')
|
||||
})
|
||||
```
|
||||
|
||||
## Debugging Tests
|
||||
|
||||
### Using Test UI
|
||||
|
||||
```bash
|
||||
npm run test:ui
|
||||
```
|
||||
|
||||
Opens browser interface with:
|
||||
- Test results visualization
|
||||
- Coverage reports
|
||||
- Test file exploration
|
||||
- Real-time test watching
|
||||
|
||||
### Console Debugging
|
||||
|
||||
```javascript
|
||||
it('should debug test data', () => {
|
||||
console.log('Debug data:', testData)
|
||||
// Test continues...
|
||||
})
|
||||
```
|
||||
|
||||
## Adding New Tests
|
||||
|
||||
1. **Create test file** in `test/` directory
|
||||
2. **Import helpers** from `test/testHelpers.js`
|
||||
3. **Follow naming convention**: `*.test.js`
|
||||
4. **Group related tests** with `describe()` blocks
|
||||
5. **Use descriptive test names** with `it('should ...')`
|
||||
|
||||
## CI Integration
|
||||
|
||||
Tests can be easily integrated into CI pipelines:
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
- name: Upload coverage
|
||||
run: npm run test:coverage
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Test behavior, not implementation**
|
||||
2. **Use descriptive test names**
|
||||
3. **Keep tests focused and small**
|
||||
4. **Mock external dependencies**
|
||||
5. **Test both success and error cases**
|
||||
6. **Maintain test data helpers**
|
||||
7. **Run tests frequently during development**
|
||||
|
||||
This test infrastructure enables confident refactoring and feature development while maintaining code quality and preventing regressions.
|
||||
Reference in New Issue
Block a user