# 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('') 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.