Files
claude-task-master/tests/integration/commands/all-commands.test.js
2025-10-02 11:54:29 +02:00

449 lines
13 KiB
JavaScript

/**
* 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);
});
});
});