Adds a test for parse-prd.
This commit is contained in:
44
tests/fixtures/sample-claude-response.js
vendored
Normal file
44
tests/fixtures/sample-claude-response.js
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Sample Claude API response for testing
|
||||
*/
|
||||
|
||||
export const sampleClaudeResponse = {
|
||||
tasks: [
|
||||
{
|
||||
id: 1,
|
||||
title: "Setup Task Data Structure",
|
||||
description: "Implement the core task data structure and file operations",
|
||||
status: "pending",
|
||||
dependencies: [],
|
||||
priority: "high",
|
||||
details: "Create the tasks.json file structure with support for task properties including ID, title, description, status, dependencies, priority, details, and test strategy. Implement file system operations for reading and writing task data.",
|
||||
testStrategy: "Verify tasks.json is created with the correct structure and that task data can be read from and written to the file."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Implement CLI Foundation",
|
||||
description: "Create the command-line interface foundation with basic commands",
|
||||
status: "pending",
|
||||
dependencies: [1],
|
||||
priority: "high",
|
||||
details: "Set up Commander.js for handling CLI commands. Implement the basic command structure including help documentation. Create the foundational command parsing logic.",
|
||||
testStrategy: "Test each command to ensure it properly parses arguments and options. Verify help documentation is displayed correctly."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Develop Task Management Operations",
|
||||
description: "Implement core operations for creating, reading, updating, and deleting tasks",
|
||||
status: "pending",
|
||||
dependencies: [1],
|
||||
priority: "medium",
|
||||
details: "Implement functions for listing tasks, adding new tasks, updating task status, and removing tasks. Include support for filtering tasks by status and other properties.",
|
||||
testStrategy: "Create unit tests for each CRUD operation to verify they correctly modify the task data."
|
||||
}
|
||||
],
|
||||
metadata: {
|
||||
projectName: "Task Management CLI",
|
||||
totalTasks: 3,
|
||||
sourceFile: "tests/fixtures/sample-prd.txt",
|
||||
generatedAt: "2023-12-15"
|
||||
}
|
||||
};
|
||||
42
tests/fixtures/sample-prd.txt
vendored
Normal file
42
tests/fixtures/sample-prd.txt
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# Sample PRD for Testing
|
||||
|
||||
<PRD>
|
||||
# Technical Architecture
|
||||
|
||||
## System Components
|
||||
1. **Task Management Core**
|
||||
- Tasks.json file structure
|
||||
- Task model with dependencies
|
||||
- Task state management
|
||||
|
||||
2. **Command Line Interface**
|
||||
- Command parsing and execution
|
||||
- Display utilities
|
||||
|
||||
## Data Models
|
||||
|
||||
### Task Model
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Task Title",
|
||||
"description": "Brief task description",
|
||||
"status": "pending|done|deferred",
|
||||
"dependencies": [0],
|
||||
"priority": "high|medium|low",
|
||||
"details": "Implementation instructions",
|
||||
"testStrategy": "Verification approach"
|
||||
}
|
||||
```
|
||||
|
||||
# Development Roadmap
|
||||
|
||||
## Phase 1: Core Task Management System
|
||||
1. **Task Data Structure**
|
||||
- Implement the tasks.json structure
|
||||
- Create file system interactions
|
||||
|
||||
2. **Command Line Interface Foundation**
|
||||
- Implement command parsing
|
||||
- Create help documentation
|
||||
</PRD>
|
||||
@@ -3,17 +3,63 @@
|
||||
*/
|
||||
|
||||
import { jest } from '@jest/globals';
|
||||
import { findNextTask } from '../../scripts/modules/task-manager.js';
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock('fs');
|
||||
jest.mock('path');
|
||||
jest.mock('@anthropic-ai/sdk');
|
||||
jest.mock('cli-table3');
|
||||
jest.mock('../../scripts/modules/ui.js');
|
||||
jest.mock('../../scripts/modules/ai-services.js');
|
||||
jest.mock('../../scripts/modules/dependency-manager.js');
|
||||
jest.mock('../../scripts/modules/utils.js');
|
||||
// Mock implementations
|
||||
const mockReadFileSync = jest.fn();
|
||||
const mockExistsSync = jest.fn();
|
||||
const mockMkdirSync = jest.fn();
|
||||
const mockDirname = jest.fn();
|
||||
const mockCallClaude = jest.fn();
|
||||
const mockWriteJSON = jest.fn();
|
||||
const mockGenerateTaskFiles = jest.fn();
|
||||
|
||||
// Mock fs module
|
||||
jest.mock('fs', () => ({
|
||||
readFileSync: mockReadFileSync,
|
||||
existsSync: mockExistsSync,
|
||||
mkdirSync: mockMkdirSync
|
||||
}));
|
||||
|
||||
// Mock path module
|
||||
jest.mock('path', () => ({
|
||||
dirname: mockDirname
|
||||
}));
|
||||
|
||||
// Mock AI services
|
||||
jest.mock('../../scripts/modules/ai-services.js', () => ({
|
||||
callClaude: mockCallClaude
|
||||
}));
|
||||
|
||||
// Mock utils
|
||||
jest.mock('../../scripts/modules/utils.js', () => ({
|
||||
writeJSON: mockWriteJSON,
|
||||
log: jest.fn()
|
||||
}));
|
||||
|
||||
// Create a simplified version of parsePRD for testing
|
||||
const testParsePRD = async (prdPath, outputPath, numTasks) => {
|
||||
try {
|
||||
const prdContent = mockReadFileSync(prdPath, 'utf8');
|
||||
const tasks = await mockCallClaude(prdContent, prdPath, numTasks);
|
||||
const dir = mockDirname(outputPath);
|
||||
|
||||
if (!mockExistsSync(dir)) {
|
||||
mockMkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
mockWriteJSON(outputPath, tasks);
|
||||
await mockGenerateTaskFiles(outputPath, dir);
|
||||
|
||||
return tasks;
|
||||
} catch (error) {
|
||||
console.error(`Error parsing PRD: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Import after mocks
|
||||
import { findNextTask } from '../../scripts/modules/task-manager.js';
|
||||
import { sampleClaudeResponse } from '../fixtures/sample-claude-response.js';
|
||||
|
||||
describe('Task Manager Module', () => {
|
||||
beforeEach(() => {
|
||||
@@ -182,4 +228,81 @@ describe('Task Manager Module', () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parsePRD function', () => {
|
||||
// Mock the sample PRD content
|
||||
const samplePRDContent = '# Sample PRD for Testing';
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset all mocks
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Set up mocks for fs, path and other modules
|
||||
mockReadFileSync.mockReturnValue(samplePRDContent);
|
||||
mockExistsSync.mockReturnValue(true);
|
||||
mockDirname.mockReturnValue('tasks');
|
||||
mockCallClaude.mockResolvedValue(sampleClaudeResponse);
|
||||
mockGenerateTaskFiles.mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
test('should parse a PRD file and generate tasks', async () => {
|
||||
// Call the test version of parsePRD
|
||||
await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
|
||||
|
||||
// Verify fs.readFileSync was called with the correct arguments
|
||||
expect(mockReadFileSync).toHaveBeenCalledWith('path/to/prd.txt', 'utf8');
|
||||
|
||||
// Verify callClaude was called with the correct arguments
|
||||
expect(mockCallClaude).toHaveBeenCalledWith(samplePRDContent, 'path/to/prd.txt', 3);
|
||||
|
||||
// Verify directory check
|
||||
expect(mockExistsSync).toHaveBeenCalledWith('tasks');
|
||||
|
||||
// Verify writeJSON was called with the correct arguments
|
||||
expect(mockWriteJSON).toHaveBeenCalledWith('tasks/tasks.json', sampleClaudeResponse);
|
||||
|
||||
// Verify generateTaskFiles was called
|
||||
expect(mockGenerateTaskFiles).toHaveBeenCalledWith('tasks/tasks.json', 'tasks');
|
||||
});
|
||||
|
||||
test('should create the tasks directory if it does not exist', async () => {
|
||||
// Mock existsSync to return false to simulate directory doesn't exist
|
||||
mockExistsSync.mockReturnValueOnce(false);
|
||||
|
||||
// Call the function
|
||||
await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
|
||||
|
||||
// Verify mkdir was called
|
||||
expect(mockMkdirSync).toHaveBeenCalledWith('tasks', { recursive: true });
|
||||
});
|
||||
|
||||
test('should handle errors in the PRD parsing process', async () => {
|
||||
// Mock an error in callClaude
|
||||
const testError = new Error('Test error in Claude API call');
|
||||
mockCallClaude.mockRejectedValueOnce(testError);
|
||||
|
||||
// Mock console.error and process.exit
|
||||
const mockConsoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const mockProcessExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
||||
|
||||
// Call the function
|
||||
await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
|
||||
|
||||
// Verify error handling
|
||||
expect(mockConsoleError).toHaveBeenCalled();
|
||||
expect(mockProcessExit).toHaveBeenCalledWith(1);
|
||||
|
||||
// Restore mocks
|
||||
mockConsoleError.mockRestore();
|
||||
mockProcessExit.mockRestore();
|
||||
});
|
||||
|
||||
test('should generate individual task files after creating tasks.json', async () => {
|
||||
// Call the function
|
||||
await testParsePRD('path/to/prd.txt', 'tasks/tasks.json', 3);
|
||||
|
||||
// Verify generateTaskFiles was called
|
||||
expect(mockGenerateTaskFiles).toHaveBeenCalledWith('tasks/tasks.json', 'tasks');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user