feat: Complete generateObject migration with JSON mode support
This commit is contained in:
committed by
Ralph Khreish
parent
604b94baa9
commit
b16023ab2f
434
tests/integration/commands/all-commands.test.js
Normal file
434
tests/integration/commands/all-commands.test.js
Normal file
@@ -0,0 +1,434 @@
|
||||
/**
|
||||
* Comprehensive integration test suite for all generateObject-migrated commands
|
||||
* Tests end-to-end command execution with real AI service calls
|
||||
*/
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
// Import all commands
|
||||
import analyzeTaskComplexity from '../../../scripts/modules/task-manager/analyze-task-complexity.js';
|
||||
import updateTaskById from '../../../scripts/modules/task-manager/update-task-by-id.js';
|
||||
import expandTask from '../../../scripts/modules/task-manager/expand-task.js';
|
||||
import updateTasks from '../../../scripts/modules/task-manager/update-tasks.js';
|
||||
import addTask from '../../../scripts/modules/task-manager/add-task.js';
|
||||
import parsePRD from '../../../scripts/modules/task-manager/parse-prd.js';
|
||||
|
||||
describe('GenerateObject Migration - Comprehensive Integration Tests', () => {
|
||||
const testDir = path.join(process.cwd(), 'test-integration-output');
|
||||
const testTasksFile = path.join(testDir, 'test-tasks.json');
|
||||
const testPrdFile = path.join(testDir, 'test-prd.md');
|
||||
|
||||
beforeAll(() => {
|
||||
// Create test directory
|
||||
if (!fs.existsSync(testDir)) {
|
||||
fs.mkdirSync(testDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Create initial test data
|
||||
const initialTasks = {
|
||||
master: {
|
||||
tasks: [
|
||||
{
|
||||
id: 1,
|
||||
title: "Setup project infrastructure",
|
||||
description: "Initialize the project with proper structure and dependencies",
|
||||
status: "done",
|
||||
dependencies: [],
|
||||
priority: "high",
|
||||
details: "Created project structure with src, tests, and docs folders",
|
||||
testStrategy: "Manual verification of folder structure",
|
||||
subtasks: []
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Implement authentication system",
|
||||
description: "Add user authentication with JWT tokens and OAuth2 support",
|
||||
status: "in-progress",
|
||||
dependencies: [1],
|
||||
priority: "high",
|
||||
details: "Need to support both OAuth2 and traditional email/password login",
|
||||
testStrategy: "Unit tests for auth logic, integration tests for endpoints",
|
||||
subtasks: [
|
||||
{
|
||||
id: 1,
|
||||
title: "Design authentication flow",
|
||||
description: "Create detailed flow diagrams for auth process",
|
||||
status: "done",
|
||||
dependencies: []
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Implement JWT token generation",
|
||||
description: "Create secure JWT token generation and validation",
|
||||
status: "pending",
|
||||
dependencies: []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Build RESTful API",
|
||||
description: "Create comprehensive REST API endpoints",
|
||||
status: "pending",
|
||||
dependencies: [2],
|
||||
priority: "medium",
|
||||
details: "Use Express.js with proper middleware and error handling",
|
||||
testStrategy: null,
|
||||
subtasks: []
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
created: new Date().toISOString(),
|
||||
updated: new Date().toISOString(),
|
||||
description: "Test project tasks"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fs.writeFileSync(testTasksFile, JSON.stringify(initialTasks, null, 2));
|
||||
|
||||
// Create test PRD file
|
||||
const testPrd = `# Product Requirements Document
|
||||
|
||||
## Overview
|
||||
We need to build a modern task management system with real-time collaboration features.
|
||||
|
||||
## Key Features
|
||||
1. User authentication and authorization
|
||||
2. Task creation and management
|
||||
3. Real-time updates via WebSockets
|
||||
4. File attachments and comments
|
||||
5. Advanced search and filtering
|
||||
|
||||
## Technical Requirements
|
||||
- Node.js backend with Express
|
||||
- PostgreSQL database
|
||||
- Redis for caching
|
||||
- WebSocket support
|
||||
- RESTful API design
|
||||
|
||||
## Success Criteria
|
||||
- Support 10,000+ concurrent users
|
||||
- Sub-100ms API response times
|
||||
- 99.9% uptime SLA`;
|
||||
|
||||
fs.writeFileSync(testPrdFile, testPrd);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up test files
|
||||
if (fs.existsSync(testTasksFile)) {
|
||||
fs.unlinkSync(testTasksFile);
|
||||
}
|
||||
if (fs.existsSync(testPrdFile)) {
|
||||
fs.unlinkSync(testPrdFile);
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// Clean up test directory
|
||||
if (fs.existsSync(testDir)) {
|
||||
fs.rmSync(testDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe('analyze-complexity command', () => {
|
||||
test('should analyze task complexity with structured output', async () => {
|
||||
const result = await analyzeTaskComplexity(
|
||||
testTasksFile,
|
||||
2, // Analyze task ID 2
|
||||
false, // Don't use research mode
|
||||
{
|
||||
projectRoot: process.cwd(),
|
||||
tag: 'master'
|
||||
},
|
||||
'json' // JSON output format
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.complexityAnalysis).toBeDefined();
|
||||
expect(result.complexityAnalysis.overallComplexity).toMatch(/low|medium|high|very high/i);
|
||||
expect(result.complexityAnalysis.factors).toBeDefined();
|
||||
expect(Array.isArray(result.complexityAnalysis.factors)).toBe(true);
|
||||
expect(result.complexityAnalysis.timeEstimate).toBeDefined();
|
||||
expect(result.complexityAnalysis.riskAssessment).toBeDefined();
|
||||
expect(result.telemetryData).toBeDefined();
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe('add-task command', () => {
|
||||
test('should add a new task with structured output', async () => {
|
||||
const result = await addTask(
|
||||
testTasksFile,
|
||||
'Implement caching layer with Redis for improved performance',
|
||||
[2], // Depends on task 2
|
||||
'medium',
|
||||
{
|
||||
projectRoot: process.cwd(),
|
||||
tag: 'master'
|
||||
},
|
||||
'json',
|
||||
null, // No manual task data
|
||||
false // Don't use research mode
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.newTaskId).toBe(4); // Should be the next ID
|
||||
expect(result.telemetryData).toBeDefined();
|
||||
|
||||
// Verify task was added
|
||||
const updatedData = JSON.parse(fs.readFileSync(testTasksFile, 'utf8'));
|
||||
const newTask = updatedData.master.tasks.find(t => t.id === 4);
|
||||
expect(newTask).toBeDefined();
|
||||
expect(newTask.title).toContain('caching');
|
||||
expect(newTask.priority).toBe('medium');
|
||||
expect(newTask.dependencies).toContain(2);
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe('expand-task command', () => {
|
||||
test('should expand task into subtasks with structured output', async () => {
|
||||
const result = await expandTask(
|
||||
testTasksFile,
|
||||
3, // Expand task ID 3
|
||||
5, // Generate 5 subtasks
|
||||
false, // Don't use research mode
|
||||
{
|
||||
projectRoot: process.cwd(),
|
||||
tag: 'master'
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.expandedTask).toBeDefined();
|
||||
expect(result.generatedSubtasks).toBeDefined();
|
||||
expect(Array.isArray(result.generatedSubtasks)).toBe(true);
|
||||
expect(result.generatedSubtasks.length).toBeGreaterThan(0);
|
||||
expect(result.generatedSubtasks.length).toBeLessThanOrEqual(5);
|
||||
|
||||
// Verify subtasks were added
|
||||
const updatedData = JSON.parse(fs.readFileSync(testTasksFile, 'utf8'));
|
||||
const task3 = updatedData.master.tasks.find(t => t.id === 3);
|
||||
expect(task3.subtasks).toBeDefined();
|
||||
expect(task3.subtasks.length).toBeGreaterThan(0);
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe('update-task-by-id command', () => {
|
||||
test('should update task with structured output (full update mode)', async () => {
|
||||
const result = await updateTaskById(
|
||||
testTasksFile,
|
||||
3, // Update task ID 3
|
||||
'Add GraphQL support alongside REST API for more flexible queries',
|
||||
false, // Append mode off (full update)
|
||||
false, // Don't use research mode
|
||||
{
|
||||
projectRoot: process.cwd(),
|
||||
tag: 'master'
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.updatedTask).toBeDefined();
|
||||
expect(result.updatedTask.id).toBe(3);
|
||||
expect(result.updatedTask.description.toLowerCase()).toContain('graphql');
|
||||
expect(result.telemetryData).toBeDefined();
|
||||
}, 30000);
|
||||
|
||||
test('should append to task details (append mode)', async () => {
|
||||
const result = await updateTaskById(
|
||||
testTasksFile,
|
||||
2, // Update task ID 2
|
||||
'Add support for multi-factor authentication',
|
||||
true, // Append mode on
|
||||
false, // Don't use research mode
|
||||
{
|
||||
projectRoot: process.cwd(),
|
||||
tag: 'master'
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.updatedTask).toBeDefined();
|
||||
expect(result.updatedTask.details).toContain('multi-factor authentication');
|
||||
expect(result.telemetryData).toBeDefined();
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe('update-tasks command', () => {
|
||||
test('should update multiple tasks with structured output', async () => {
|
||||
const result = await updateTasks(
|
||||
testTasksFile,
|
||||
2, // Update from task ID 2 onwards
|
||||
'Migrate to microservices architecture for better scalability',
|
||||
false, // Don't use research mode
|
||||
{
|
||||
projectRoot: process.cwd(),
|
||||
tag: 'master'
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.updatedTasks).toBeDefined();
|
||||
expect(Array.isArray(result.updatedTasks)).toBe(true);
|
||||
expect(result.updatedTasks.length).toBeGreaterThan(0);
|
||||
|
||||
// Tasks 2 and 3 should be updated (not done)
|
||||
const task2 = result.updatedTasks.find(t => t.id === 2);
|
||||
const task3 = result.updatedTasks.find(t => t.id === 3);
|
||||
expect(task2).toBeDefined();
|
||||
expect(task3).toBeDefined();
|
||||
expect(task2.description.toLowerCase()).toMatch(/microservice|scalability/);
|
||||
expect(task3.description.toLowerCase()).toMatch(/microservice|scalability/);
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe('parse-prd command', () => {
|
||||
test('should parse PRD and generate tasks with structured output', async () => {
|
||||
// Use a new file for PRD output to avoid conflicts
|
||||
const prdTasksFile = path.join(testDir, 'prd-tasks.json');
|
||||
|
||||
const result = await parsePRD(
|
||||
testPrdFile,
|
||||
prdTasksFile,
|
||||
5, // Generate 5 tasks
|
||||
{
|
||||
projectRoot: process.cwd(),
|
||||
force: true,
|
||||
append: false,
|
||||
research: false,
|
||||
tag: 'master'
|
||||
}
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.tasksPath).toBe(prdTasksFile);
|
||||
expect(result.telemetryData).toBeDefined();
|
||||
|
||||
// Verify tasks were generated
|
||||
const generatedData = JSON.parse(fs.readFileSync(prdTasksFile, 'utf8'));
|
||||
expect(generatedData.master).toBeDefined();
|
||||
expect(generatedData.master.tasks).toBeDefined();
|
||||
expect(generatedData.master.tasks.length).toBeGreaterThan(0);
|
||||
expect(generatedData.master.tasks.length).toBeLessThanOrEqual(5);
|
||||
|
||||
// Verify task quality
|
||||
const firstTask = generatedData.master.tasks[0];
|
||||
expect(firstTask.title).toBeTruthy();
|
||||
expect(firstTask.description).toBeTruthy();
|
||||
expect(firstTask.status).toBe('pending');
|
||||
expect(firstTask.priority).toMatch(/low|medium|high/);
|
||||
|
||||
// Clean up
|
||||
fs.unlinkSync(prdTasksFile);
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe('Command Integration Flow', () => {
|
||||
test('should handle a complete workflow with multiple commands', async () => {
|
||||
// 1. Add a new task
|
||||
const addResult = await addTask(
|
||||
testTasksFile,
|
||||
'Implement comprehensive logging system',
|
||||
[1],
|
||||
'high',
|
||||
{ projectRoot: process.cwd(), tag: 'master' },
|
||||
'json'
|
||||
);
|
||||
const newTaskId = addResult.newTaskId;
|
||||
|
||||
// 2. Analyze its complexity
|
||||
const complexityResult = await analyzeTaskComplexity(
|
||||
testTasksFile,
|
||||
newTaskId,
|
||||
false,
|
||||
{ projectRoot: process.cwd(), tag: 'master' },
|
||||
'json'
|
||||
);
|
||||
expect(complexityResult.complexityAnalysis).toBeDefined();
|
||||
|
||||
// 3. Expand it into subtasks
|
||||
const expandResult = await expandTask(
|
||||
testTasksFile,
|
||||
newTaskId,
|
||||
3,
|
||||
false,
|
||||
{ projectRoot: process.cwd(), tag: 'master' },
|
||||
'json'
|
||||
);
|
||||
expect(expandResult.generatedSubtasks.length).toBeGreaterThan(0);
|
||||
|
||||
// 4. Update the task with additional context
|
||||
const updateResult = await updateTaskById(
|
||||
testTasksFile,
|
||||
newTaskId,
|
||||
'Include structured logging with JSON format and log aggregation support',
|
||||
false,
|
||||
false,
|
||||
{ projectRoot: process.cwd(), tag: 'master' },
|
||||
'json'
|
||||
);
|
||||
expect(updateResult.updatedTask.description).toContain('JSON format');
|
||||
|
||||
// 5. Verify final state
|
||||
const finalData = JSON.parse(fs.readFileSync(testTasksFile, 'utf8'));
|
||||
const finalTask = finalData.master.tasks.find(t => t.id === newTaskId);
|
||||
expect(finalTask).toBeDefined();
|
||||
expect(finalTask.subtasks.length).toBeGreaterThan(0);
|
||||
expect(finalTask.description).toContain('JSON format');
|
||||
}, 60000); // Longer timeout for multiple operations
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
test('should handle invalid task IDs gracefully', async () => {
|
||||
await expect(
|
||||
analyzeTaskComplexity(
|
||||
testTasksFile,
|
||||
999, // Non-existent task ID
|
||||
false,
|
||||
{ projectRoot: process.cwd(), tag: 'master' },
|
||||
'json'
|
||||
)
|
||||
).rejects.toThrow('Task with ID 999 not found');
|
||||
});
|
||||
|
||||
test('should handle empty prompts', async () => {
|
||||
await expect(
|
||||
addTask(
|
||||
testTasksFile,
|
||||
'', // Empty prompt
|
||||
[],
|
||||
'medium',
|
||||
{ projectRoot: process.cwd(), tag: 'master' },
|
||||
'json'
|
||||
)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should handle invalid dependencies', async () => {
|
||||
const result = await addTask(
|
||||
testTasksFile,
|
||||
'New task with invalid dependency',
|
||||
[999], // Non-existent dependency
|
||||
'medium',
|
||||
{ projectRoot: process.cwd(), tag: 'master' },
|
||||
'json'
|
||||
);
|
||||
|
||||
// Should succeed but filter out invalid dependency
|
||||
expect(result.newTaskId).toBeDefined();
|
||||
const data = JSON.parse(fs.readFileSync(testTasksFile, 'utf8'));
|
||||
const newTask = data.master.tasks.find(t => t.id === result.newTaskId);
|
||||
expect(newTask.dependencies).not.toContain(999);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user