import expandTask from '../../../scripts/modules/task-manager/expand-task.js'; import { readJSON, writeJSON } from '../../../scripts/modules/utils.js'; import fs from 'fs'; import path from 'path'; describe('expand-task with generateObject', () => { const testTasksFile = path.join(process.cwd(), 'test-tasks.json'); beforeEach(() => { // Create a test tasks file const testTasks = { projectName: "Test Project", tasks: [ { id: 1, title: "Setup project structure", description: "Initialize the project with proper folder structure", status: "done", dependencies: [], priority: "high", details: "Create folders for src, tests, docs", testStrategy: "Manual verification", subtasks: [] }, { id: 2, title: "Implement authentication", description: "Add user authentication with JWT tokens", status: "pending", dependencies: [1], priority: "high", details: "Need to support OAuth2 and traditional login", testStrategy: null, subtasks: [] }, { id: 3, title: "Build API endpoints", description: "Create RESTful API endpoints", status: "pending", dependencies: [2], priority: "medium", details: null, testStrategy: null, subtasks: [ { id: 1, title: "Design API schema", description: "Create OpenAPI specification", dependencies: [], details: "Use OpenAPI 3.0 specification", status: "done" } ] } ] }; fs.writeFileSync(testTasksFile, JSON.stringify(testTasks, null, 2)); }); afterEach(() => { // Clean up test files if (fs.existsSync(testTasksFile)) { fs.unlinkSync(testTasksFile); } }); test('should expand task with structured subtasks', async () => { const result = await expandTask( testTasksFile, '2', // taskId as string 3, // numSubtasks false, // force 'Break down authentication into implementation steps' // additionalContext ); expect(result).toHaveProperty('task'); expect(result).toHaveProperty('telemetryData'); const { task } = result; // Verify task was expanded expect(task.id).toBe(2); expect(task.subtasks).toBeDefined(); expect(Array.isArray(task.subtasks)).toBe(true); expect(task.subtasks.length).toBeGreaterThan(0); // Verify subtask structure const subtask = task.subtasks[0]; expect(subtask).toHaveProperty('id'); expect(subtask).toHaveProperty('title'); expect(subtask).toHaveProperty('description'); expect(subtask).toHaveProperty('dependencies'); expect(subtask).toHaveProperty('details'); expect(subtask).toHaveProperty('status', 'pending'); // Verify task was written back to file const savedData = JSON.parse(fs.readFileSync(testTasksFile, 'utf8')); const savedTask = savedData.tasks.find(t => t.id === 2); expect(savedTask.subtasks.length).toBe(task.subtasks.length); }, 30000); // Increase timeout for AI call test('should append subtasks when force=false', async () => { // First expansion await expandTask(testTasksFile, '3', 2, false); const dataAfterFirst = JSON.parse(fs.readFileSync(testTasksFile, 'utf8')); const taskAfterFirst = dataAfterFirst.tasks.find(t => t.id === 3); const initialSubtaskCount = taskAfterFirst.subtasks.length; // Second expansion (append) await expandTask(testTasksFile, '3', 2, false, 'Add more implementation details'); const dataAfterSecond = JSON.parse(fs.readFileSync(testTasksFile, 'utf8')); const taskAfterSecond = dataAfterSecond.tasks.find(t => t.id === 3); // Should have more subtasks than before expect(taskAfterSecond.subtasks.length).toBeGreaterThan(initialSubtaskCount); }, 60000); test('should replace subtasks when force=true', async () => { // First expansion await expandTask(testTasksFile, '3', 2, false); // Second expansion with force=true const result = await expandTask(testTasksFile, '3', 3, true, 'Complete redesign needed'); const savedData = JSON.parse(fs.readFileSync(testTasksFile, 'utf8')); const savedTask = savedData.tasks.find(t => t.id === 3); // Should have exactly 3 subtasks (replaced, not appended) expect(savedTask.subtasks.length).toBe(3); }, 60000); });