# 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.