|
| 1 | +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; |
| 2 | +import { DevlogManager } from '../devlog-manager-v2'; |
| 3 | +import { CreateDevlogRequest } from '@devlog/types'; |
| 4 | +import * as path from 'path'; |
| 5 | +import * as fs from 'fs/promises'; |
| 6 | +import * as os from 'os'; |
| 7 | + |
| 8 | +describe('DevlogManager V2 (Modular Architecture)', () => { |
| 9 | + let manager: DevlogManager; |
| 10 | + let testDir: string; |
| 11 | + |
| 12 | + beforeEach(async () => { |
| 13 | + // Create a temporary directory for testing |
| 14 | + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'devlog-test-')); |
| 15 | + manager = new DevlogManager({ |
| 16 | + workspaceRoot: testDir |
| 17 | + }); |
| 18 | + }); |
| 19 | + |
| 20 | + afterEach(async () => { |
| 21 | + // Clean up test directory |
| 22 | + await fs.rm(testDir, { recursive: true, force: true }); |
| 23 | + }); |
| 24 | + |
| 25 | + it('should create and retrieve devlog entries', async () => { |
| 26 | + const request: CreateDevlogRequest = { |
| 27 | + title: 'Test Feature', |
| 28 | + type: 'feature', |
| 29 | + description: 'Testing the new modular architecture', |
| 30 | + priority: 'medium' |
| 31 | + }; |
| 32 | + |
| 33 | + // Create devlog |
| 34 | + const entry = await manager.createDevlog(request); |
| 35 | + expect(entry.title).toBe(request.title); |
| 36 | + expect(entry.type).toBe(request.type); |
| 37 | + expect(entry.description).toBe(request.description); |
| 38 | + expect(entry.priority).toBe(request.priority); |
| 39 | + expect(entry.status).toBe('todo'); |
| 40 | + |
| 41 | + // Retrieve devlog |
| 42 | + const retrieved = await manager.getDevlog(entry.id); |
| 43 | + expect(retrieved).toEqual(entry); |
| 44 | + }); |
| 45 | + |
| 46 | + it('should list and filter devlog entries', async () => { |
| 47 | + // Create multiple entries |
| 48 | + const requests: CreateDevlogRequest[] = [ |
| 49 | + { title: 'Feature 1', type: 'feature', description: 'First feature', priority: 'high' }, |
| 50 | + { title: 'Bug 1', type: 'bugfix', description: 'First bug', priority: 'critical' }, |
| 51 | + { title: 'Task 1', type: 'task', description: 'First task', priority: 'low' } |
| 52 | + ]; |
| 53 | + |
| 54 | + for (const request of requests) { |
| 55 | + await manager.createDevlog(request); |
| 56 | + } |
| 57 | + |
| 58 | + // List all entries |
| 59 | + const allEntries = await manager.listDevlogs(); |
| 60 | + expect(allEntries).toHaveLength(3); |
| 61 | + |
| 62 | + // Filter by type |
| 63 | + const features = await manager.listDevlogs({ type: ['feature'] }); |
| 64 | + expect(features).toHaveLength(1); |
| 65 | + expect(features[0].type).toBe('feature'); |
| 66 | + |
| 67 | + // Filter by priority |
| 68 | + const highPriority = await manager.listDevlogs({ priority: ['high', 'critical'] }); |
| 69 | + expect(highPriority).toHaveLength(2); |
| 70 | + }); |
| 71 | + |
| 72 | + it('should search devlog entries', async () => { |
| 73 | + const request: CreateDevlogRequest = { |
| 74 | + title: 'Searchable Feature', |
| 75 | + type: 'feature', |
| 76 | + description: 'This is a unique searchable description', |
| 77 | + priority: 'medium' |
| 78 | + }; |
| 79 | + |
| 80 | + await manager.createDevlog(request); |
| 81 | + |
| 82 | + // Search by title |
| 83 | + const titleResults = await manager.searchDevlogs('Searchable'); |
| 84 | + expect(titleResults).toHaveLength(1); |
| 85 | + |
| 86 | + // Search by description |
| 87 | + const descResults = await manager.searchDevlogs('unique searchable'); |
| 88 | + expect(descResults).toHaveLength(1); |
| 89 | + |
| 90 | + // Search for non-existent term |
| 91 | + const noResults = await manager.searchDevlogs('nonexistent'); |
| 92 | + expect(noResults).toHaveLength(0); |
| 93 | + }); |
| 94 | + |
| 95 | + it('should add notes to devlog entries', async () => { |
| 96 | + const request: CreateDevlogRequest = { |
| 97 | + title: 'Note Test Feature', |
| 98 | + type: 'feature', |
| 99 | + description: 'Testing note functionality', |
| 100 | + priority: 'medium' |
| 101 | + }; |
| 102 | + |
| 103 | + const entry = await manager.createDevlog(request); |
| 104 | + |
| 105 | + // Add a note |
| 106 | + const updatedEntry = await manager.addNote(entry.id, { |
| 107 | + category: 'progress', |
| 108 | + content: 'This is a test note' |
| 109 | + }); |
| 110 | + |
| 111 | + expect(updatedEntry.notes).toHaveLength(1); |
| 112 | + expect(updatedEntry.notes[0].content).toBe('This is a test note'); |
| 113 | + expect(updatedEntry.notes[0].category).toBe('progress'); |
| 114 | + }); |
| 115 | + |
| 116 | + it('should update AI context', async () => { |
| 117 | + const request: CreateDevlogRequest = { |
| 118 | + title: 'AI Context Test', |
| 119 | + type: 'feature', |
| 120 | + description: 'Testing AI context updates', |
| 121 | + priority: 'medium' |
| 122 | + }; |
| 123 | + |
| 124 | + const entry = await manager.createDevlog(request); |
| 125 | + |
| 126 | + // Update AI context |
| 127 | + const updatedEntry = await manager.updateAIContext({ |
| 128 | + id: entry.id, |
| 129 | + summary: 'Updated AI summary', |
| 130 | + insights: ['New insight 1', 'New insight 2'], |
| 131 | + questions: ['Question 1?', 'Question 2?'], |
| 132 | + nextSteps: ['Step 1', 'Step 2'] |
| 133 | + }); |
| 134 | + |
| 135 | + expect(updatedEntry.aiContext.currentSummary).toBe('Updated AI summary'); |
| 136 | + expect(updatedEntry.aiContext.keyInsights).toContain('New insight 1'); |
| 137 | + expect(updatedEntry.aiContext.keyInsights).toContain('New insight 2'); |
| 138 | + expect(updatedEntry.aiContext.openQuestions).toEqual(['Question 1?', 'Question 2?']); |
| 139 | + expect(updatedEntry.aiContext.suggestedNextSteps).toEqual(['Step 1', 'Step 2']); |
| 140 | + }); |
| 141 | + |
| 142 | + it('should complete devlog entries', async () => { |
| 143 | + const request: CreateDevlogRequest = { |
| 144 | + title: 'Completion Test', |
| 145 | + type: 'task', |
| 146 | + description: 'Testing completion functionality', |
| 147 | + priority: 'medium' |
| 148 | + }; |
| 149 | + |
| 150 | + const entry = await manager.createDevlog(request); |
| 151 | + |
| 152 | + // Complete the devlog |
| 153 | + const completedEntry = await manager.completeDevlog(entry.id, 'Task completed successfully'); |
| 154 | + |
| 155 | + expect(completedEntry.status).toBe('done'); |
| 156 | + expect(completedEntry.notes).toHaveLength(1); |
| 157 | + expect(completedEntry.notes[0].content).toBe('Completed: Task completed successfully'); |
| 158 | + }); |
| 159 | + |
| 160 | + it('should prevent duplicate entries with findOrCreateDevlog', async () => { |
| 161 | + const request: CreateDevlogRequest = { |
| 162 | + title: 'Duplicate Test', |
| 163 | + type: 'feature', |
| 164 | + description: 'Testing duplicate prevention', |
| 165 | + priority: 'medium' |
| 166 | + }; |
| 167 | + |
| 168 | + // Create first entry |
| 169 | + const result1 = await manager.findOrCreateDevlog(request); |
| 170 | + expect(result1.created).toBe(true); |
| 171 | + |
| 172 | + // Try to create the same entry again |
| 173 | + const result2 = await manager.findOrCreateDevlog(request); |
| 174 | + expect(result2.created).toBe(false); |
| 175 | + expect(result2.entry.id).toBe(result1.entry.id); |
| 176 | + }); |
| 177 | + |
| 178 | + it('should get statistics', async () => { |
| 179 | + const requests: CreateDevlogRequest[] = [ |
| 180 | + { title: 'Feature 1', type: 'feature', description: 'Feature', priority: 'high' }, |
| 181 | + { title: 'Feature 2', type: 'feature', description: 'Feature', priority: 'medium' }, |
| 182 | + { title: 'Bug 1', type: 'bugfix', description: 'Bug', priority: 'critical' } |
| 183 | + ]; |
| 184 | + |
| 185 | + for (const request of requests) { |
| 186 | + await manager.createDevlog(request); |
| 187 | + } |
| 188 | + |
| 189 | + const stats = await manager.getStats(); |
| 190 | + expect(stats.totalEntries).toBe(3); |
| 191 | + expect(stats.byType.feature).toBe(2); |
| 192 | + expect(stats.byType.bugfix).toBe(1); |
| 193 | + expect(stats.byPriority.high).toBe(1); |
| 194 | + expect(stats.byPriority.medium).toBe(1); |
| 195 | + expect(stats.byPriority.critical).toBe(1); |
| 196 | + }); |
| 197 | +}); |
0 commit comments