import { describe, it, expect } from 'vitest'; import { parseTaskLine, parseTasksFromSpec } from '@automaker/prompts'; describe('Task Parsing', () => { describe('parseTaskLine', () => { it('should parse task with file path', () => { const line = '- [ ] T001: Create user model | File: src/models/user.ts'; const result = parseTaskLine(line); expect(result).toEqual({ id: 'T001', description: 'Create user model', filePath: 'src/models/user.ts', phase: undefined, status: 'pending', }); }); it('should parse task without file path', () => { const line = '- [ ] T002: Setup database connection'; const result = parseTaskLine(line); expect(result).toEqual({ id: 'T002', description: 'Setup database connection', phase: undefined, status: 'pending', }); }); it('should include phase when provided', () => { const line = '- [ ] T003: Write tests | File: tests/user.test.ts'; const result = parseTaskLine(line, 'Phase 1: Foundation'); expect(result?.phase).toBe('Phase 1: Foundation'); }); it('should return null for invalid line', () => { expect(parseTaskLine('- [ ] Invalid format')).toBeNull(); expect(parseTaskLine('Not a task line')).toBeNull(); expect(parseTaskLine('')).toBeNull(); }); it('should handle multi-word descriptions', () => { const line = '- [ ] T004: Implement user authentication with JWT tokens | File: src/auth.ts'; const result = parseTaskLine(line); expect(result?.description).toBe('Implement user authentication with JWT tokens'); }); it('should trim whitespace from description and file path', () => { const line = '- [ ] T005: Create API endpoint | File: src/routes/api.ts '; const result = parseTaskLine(line); expect(result?.description).toBe('Create API endpoint'); expect(result?.filePath).toBe('src/routes/api.ts'); }); }); describe('parseTasksFromSpec', () => { it('should parse tasks from a tasks code block', () => { const specContent = ` ## Specification Some description here. \`\`\`tasks - [ ] T001: Create user model | File: src/models/user.ts - [ ] T002: Add API endpoint | File: src/routes/users.ts - [ ] T003: Write unit tests | File: tests/user.test.ts \`\`\` ## Notes Some notes here. `; const tasks = parseTasksFromSpec(specContent); expect(tasks).toHaveLength(3); expect(tasks[0].id).toBe('T001'); expect(tasks[1].id).toBe('T002'); expect(tasks[2].id).toBe('T003'); }); it('should parse tasks with phases', () => { const specContent = ` \`\`\`tasks ## Phase 1: Foundation - [ ] T001: Initialize project | File: package.json - [ ] T002: Configure TypeScript | File: tsconfig.json ## Phase 2: Implementation - [ ] T003: Create main module | File: src/index.ts - [ ] T004: Add utility functions | File: src/utils.ts ## Phase 3: Testing - [ ] T005: Write tests | File: tests/index.test.ts \`\`\` `; const tasks = parseTasksFromSpec(specContent); expect(tasks).toHaveLength(5); expect(tasks[0].phase).toBe('Phase 1: Foundation'); expect(tasks[1].phase).toBe('Phase 1: Foundation'); expect(tasks[2].phase).toBe('Phase 2: Implementation'); expect(tasks[3].phase).toBe('Phase 2: Implementation'); expect(tasks[4].phase).toBe('Phase 3: Testing'); }); it('should return empty array for content without tasks', () => { const specContent = 'Just some text without any tasks'; const tasks = parseTasksFromSpec(specContent); expect(tasks).toEqual([]); }); it('should fallback to finding task lines outside code block', () => { const specContent = ` ## Implementation Plan - [ ] T001: First task | File: src/first.ts - [ ] T002: Second task | File: src/second.ts `; const tasks = parseTasksFromSpec(specContent); expect(tasks).toHaveLength(2); expect(tasks[0].id).toBe('T001'); expect(tasks[1].id).toBe('T002'); }); it('should handle empty tasks block', () => { const specContent = ` \`\`\`tasks \`\`\` `; const tasks = parseTasksFromSpec(specContent); expect(tasks).toEqual([]); }); it('should handle mixed valid and invalid lines', () => { const specContent = ` \`\`\`tasks - [ ] T001: Valid task | File: src/valid.ts - Invalid line Some other text - [ ] T002: Another valid task \`\`\` `; const tasks = parseTasksFromSpec(specContent); expect(tasks).toHaveLength(2); }); it('should preserve task order', () => { const specContent = ` \`\`\`tasks - [ ] T003: Third - [ ] T001: First - [ ] T002: Second \`\`\` `; const tasks = parseTasksFromSpec(specContent); expect(tasks[0].id).toBe('T003'); expect(tasks[1].id).toBe('T001'); expect(tasks[2].id).toBe('T002'); }); it('should handle task IDs with different numbers', () => { const specContent = ` \`\`\`tasks - [ ] T001: First - [ ] T010: Tenth - [ ] T100: Hundredth \`\`\` `; const tasks = parseTasksFromSpec(specContent); expect(tasks).toHaveLength(3); expect(tasks[0].id).toBe('T001'); expect(tasks[1].id).toBe('T010'); expect(tasks[2].id).toBe('T100'); }); }); describe('spec content generation patterns', () => { it('should match the expected lite mode output format', () => { const liteModeOutput = ` 1. **Goal**: Implement user registration 2. **Approach**: Create form component, add validation, connect to API 3. **Files to Touch**: src/components/Register.tsx, src/api/auth.ts 4. **Tasks**: 1. Create registration form 2. Add form validation 3. Connect to backend API 5. **Risks**: Form state management complexity [PLAN_GENERATED] Planning outline complete. `; expect(liteModeOutput).toContain('[PLAN_GENERATED]'); expect(liteModeOutput).toContain('Goal'); expect(liteModeOutput).toContain('Approach'); }); it('should match the expected spec mode output format', () => { const specModeOutput = ` 1. **Problem**: Users cannot register for accounts 2. **Solution**: Implement registration form with email/password validation 3. **Acceptance Criteria**: - GIVEN a new user, WHEN they fill in valid details, THEN account is created 4. **Files to Modify**: | File | Purpose | Action | |------|---------|--------| | src/Register.tsx | Registration form | create | 5. **Implementation Tasks**: \`\`\`tasks - [ ] T001: Create registration component | File: src/Register.tsx - [ ] T002: Add form validation | File: src/Register.tsx \`\`\` 6. **Verification**: Manual testing of registration flow [SPEC_GENERATED] Please review the specification above. `; expect(specModeOutput).toContain('[SPEC_GENERATED]'); expect(specModeOutput).toContain('```tasks'); expect(specModeOutput).toContain('T001'); }); it('should match the expected full mode output format', () => { const fullModeOutput = ` 1. **Problem Statement**: Users need ability to create accounts 2. **User Story**: As a new user, I want to register, so that I can access the app 3. **Acceptance Criteria**: - **Happy Path**: GIVEN valid email, WHEN registering, THEN account created - **Edge Cases**: GIVEN existing email, WHEN registering, THEN error shown 4. **Technical Context**: | Aspect | Value | |--------|-------| | Affected Files | src/Register.tsx | 5. **Non-Goals**: Social login, password recovery 6. **Implementation Tasks**: \`\`\`tasks ## Phase 1: Foundation - [ ] T001: Setup component structure | File: src/Register.tsx ## Phase 2: Core Implementation - [ ] T002: Add form logic | File: src/Register.tsx ## Phase 3: Integration & Testing - [ ] T003: Connect to API | File: src/api/auth.ts \`\`\` [SPEC_GENERATED] Please review the comprehensive specification above. `; expect(fullModeOutput).toContain('Phase 1'); expect(fullModeOutput).toContain('Phase 2'); expect(fullModeOutput).toContain('Phase 3'); expect(fullModeOutput).toContain('[SPEC_GENERATED]'); }); }); });