UNPKG

@boundless-oss/atlas

Version:

Atlas - MCP Server for comprehensive startup project management

256 lines (226 loc) 7.96 kB
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { AgileManager } from '../manager.js'; import { ConfigManager } from '../../../config/config-manager.js'; import { Story, AcceptanceCriterion } from '../types.js'; vi.mock('../../../config/config-manager.js'); vi.mock('fs', () => ({ promises: { readFile: vi.fn().mockResolvedValue('[]'), writeFile: vi.fn().mockResolvedValue(undefined), mkdir: vi.fn().mockResolvedValue(undefined), access: vi.fn().mockRejectedValue(new Error('ENOENT')), }, })); describe('Agile Enhanced Features Tests', () => { let agileManager: AgileManager; let mockConfigManager: vi.Mocked<ConfigManager>; beforeEach(async () => { vi.clearAllMocks(); mockConfigManager = new ConfigManager() as vi.Mocked<ConfigManager>; vi.mocked(mockConfigManager.getDataPath).mockReturnValue('/mock/data/path'); agileManager = new AgileManager(mockConfigManager); await agileManager.initialize(); }); describe('Structured Acceptance Criteria', () => { it('should create story with structured acceptance criteria', async () => { const story = await agileManager.addStory({ title: 'User authentication', description: 'Implement user login', storyPoints: 5, priority: 'high', acceptanceCriteria: [ { id: 'ac-1', description: 'User can login with email and password', status: 'pending' }, { id: 'ac-2', description: 'Invalid credentials show error message', status: 'pending' } ] as AcceptanceCriterion[] }); expect(story.acceptanceCriteria).toHaveLength(2); expect(story.acceptanceCriteria[0]).toHaveProperty('status', 'pending'); }); it('should convert legacy string criteria to structured format', async () => { const story = await agileManager.addStory({ title: 'Legacy story', description: 'Story with string criteria', storyPoints: 3, priority: 'medium', acceptanceCriteria: [ 'Criterion 1', 'Criterion 2' ] }); expect(story.acceptanceCriteria).toHaveLength(2); expect(story.acceptanceCriteria[0]).toHaveProperty('description', 'Criterion 1'); expect(story.acceptanceCriteria[0]).toHaveProperty('status', 'pending'); expect(story.acceptanceCriteriaLegacy).toEqual(['Criterion 1', 'Criterion 2']); }); it('should update acceptance criteria status', async () => { const story = await agileManager.addStory({ title: 'Story', description: 'Test', storyPoints: 2, priority: 'low', acceptanceCriteria: [ { id: 'ac-1', description: 'Test criterion', status: 'pending' } ] as AcceptanceCriterion[] }); const updated = await agileManager.updateStoryStatus(story.id, { acceptanceCriteria: [ { id: 'ac-1', description: 'Test criterion', status: 'completed', verifiedBy: 'qa-tester', verifiedAt: new Date() } ] as AcceptanceCriterion[] }); expect(updated.acceptanceCriteria[0].status).toBe('completed'); expect(updated.acceptanceCriteria[0].verifiedBy).toBe('qa-tester'); }); }); describe('Story Dependencies', () => { it('should create story with dependencies', async () => { const blocker = await agileManager.addStory({ title: 'Database setup', description: 'Setup database', storyPoints: 3, priority: 'high', acceptanceCriteria: [] }); const dependent = await agileManager.addStory({ title: 'API implementation', description: 'Build API', storyPoints: 5, priority: 'medium', acceptanceCriteria: [], dependencies: [ { taskId: blocker.id, type: 'depends_on' } ] }); expect(dependent.dependencies).toHaveLength(1); expect(dependent.dependencies![0].taskId).toBe(blocker.id); }); }); describe('Time Tracking', () => { it('should create story with time estimate', async () => { const story = await agileManager.addStory({ title: 'Feature', description: 'New feature', storyPoints: 8, priority: 'high', acceptanceCriteria: [], timeEstimate: 16 }); expect(story.timeTracking).toBeDefined(); expect(story.timeTracking!.estimated).toBe(16); }); it('should update time tracking', async () => { const story = await agileManager.addStory({ title: 'Task', description: 'Task desc', storyPoints: 3, priority: 'medium', acceptanceCriteria: [], timeEstimate: 6 }); const updated = await agileManager.updateStoryStatus(story.id, { timeTracking: { estimated: 6, spent: 4, logs: [{ date: new Date(), hours: 4, description: 'Initial implementation' }] } }); expect(updated.timeTracking!.spent).toBe(4); // hoursSpent is updated separately with the hoursSpent field, not timeTracking }); }); describe('Tags and Watchers', () => { it('should create story with tags', async () => { const story = await agileManager.addStory({ title: 'Tagged story', description: 'Story with tags', storyPoints: 5, priority: 'medium', acceptanceCriteria: [], tags: ['backend', 'api', 'security'] }); expect(story.tags).toEqual(['backend', 'api', 'security']); }); it('should add watchers to story', async () => { const story = await agileManager.addStory({ title: 'Watched story', description: 'Story being watched', storyPoints: 3, priority: 'low', acceptanceCriteria: [], watchers: ['pm@example.com', 'dev@example.com'] }); expect(story.watchers).toEqual(['pm@example.com', 'dev@example.com']); }); }); describe('Enhanced Property Updates', () => { it('should update multiple enhanced properties', async () => { const story = await agileManager.addStory({ title: 'Original title', description: 'Original desc', storyPoints: 5, priority: 'medium', acceptanceCriteria: ['Original criterion'] }); const updated = await agileManager.updateStoryStatus(story.id, { title: 'Updated title', description: 'Updated description', priority: 'high', storyPoints: 8, tags: ['urgent', 'customer-request'], acceptanceCriteria: [ { id: 'ac-new', description: 'New criterion', status: 'pending' } ] as AcceptanceCriterion[] }); expect(updated.title).toBe('Updated title'); expect(updated.description).toBe('Updated description'); expect(updated.priority).toBe('high'); expect(updated.storyPoints).toBe(8); expect(updated.tags).toEqual(['urgent', 'customer-request']); expect(updated.acceptanceCriteria).toHaveLength(1); expect(updated.acceptanceCriteria[0].description).toBe('New criterion'); }); }); describe('Comments and Attachments', () => { it('should initialize with empty comments and attachments', async () => { const story = await agileManager.addStory({ title: 'Story', description: 'Description', storyPoints: 3, priority: 'medium', acceptanceCriteria: [] }); expect(story.comments).toEqual([]); expect(story.attachments).toEqual([]); expect(story.customFields).toEqual([]); expect(story.subtasks).toEqual([]); }); }); });