Ralph Khreish 3fee7515f3
fix: fix mcp tool call in extension (#1070)
* fix: fix mcp tool call in extension

- fix console.log directly being used in scope-adjutment.js breaking mcp

* chore: run format and fix tests

* chore: format
2025-08-02 21:59:02 +02:00

346 lines
8.3 KiB
JavaScript

/**
* Tests for scope-adjustment.js module
*/
import { jest } from '@jest/globals';
// Mock dependencies using unstable_mockModule for ES modules
jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
log: jest.fn(),
readJSON: jest.fn(),
writeJSON: jest.fn(),
getCurrentTag: jest.fn(() => 'master'),
readComplexityReport: jest.fn(),
findTaskInComplexityReport: jest.fn(),
findProjectRoot: jest.fn()
}));
jest.unstable_mockModule(
'../../../../../scripts/modules/ai-services-unified.js',
() => ({
generateObjectService: jest.fn(),
generateTextService: jest.fn()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager.js',
() => ({
findTaskById: jest.fn(),
taskExists: jest.fn()
})
);
jest.unstable_mockModule(
'../../../../../scripts/modules/task-manager/analyze-task-complexity.js',
() => ({
default: jest.fn()
})
);
jest.unstable_mockModule('../../../../../src/utils/path-utils.js', () => ({
findComplexityReportPath: jest.fn()
}));
// Import modules after mocking
const {
log,
readJSON,
writeJSON,
readComplexityReport,
findTaskInComplexityReport
} = await import('../../../../../scripts/modules/utils.js');
const { generateObjectService } = await import(
'../../../../../scripts/modules/ai-services-unified.js'
);
const { findTaskById, taskExists } = await import(
'../../../../../scripts/modules/task-manager.js'
);
const { scopeUpTask, scopeDownTask, validateStrength } = await import(
'../../../../../scripts/modules/task-manager/scope-adjustment.js'
);
describe('Scope Adjustment Commands', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('scopeUpTask', () => {
it('should increase task complexity with regular strength', async () => {
// Mock existing task data
const mockTasksData = {
tasks: [
{
id: 1,
title: 'Simple Task',
description: 'Basic description',
details: 'Basic implementation details',
status: 'pending'
}
]
};
const mockTask = {
id: 1,
title: 'Simple Task',
description: 'Basic description',
details: 'Basic implementation details',
status: 'pending'
};
readJSON.mockReturnValue(mockTasksData);
taskExists.mockReturnValue(true);
findTaskById.mockReturnValue({ task: mockTask });
generateObjectService.mockResolvedValue({
mainResult: {
title: 'Complex Task with Advanced Features',
description: 'Enhanced description with more requirements',
details:
'Detailed implementation with error handling, validation, and advanced features',
testStrategy:
'Comprehensive testing including unit, integration, and edge cases'
},
telemetryData: { tokens: 100, cost: 0.01 }
});
const context = {
projectRoot: '/test/project',
tag: 'master',
commandName: 'scope-up',
outputType: 'cli'
};
const result = await scopeUpTask(
'/test/tasks.json',
[1],
'regular',
null, // no custom prompt
context,
'text'
);
expect(result).toBeDefined();
expect(result.updatedTasks).toHaveLength(1);
expect(result.telemetryData).toBeDefined();
expect(writeJSON).toHaveBeenCalledWith(
'/test/tasks.json',
expect.objectContaining({
tasks: expect.arrayContaining([
expect.objectContaining({
id: 1,
title: 'Complex Task with Advanced Features'
})
])
}),
'/test/project',
'master'
);
});
it('should handle custom prompts for targeted scope adjustments', async () => {
const mockTasksData = {
tasks: [
{
id: 1,
title: 'Simple Task',
description: 'Basic description',
details: 'Basic implementation details',
status: 'pending'
}
]
};
const mockTask = {
id: 1,
title: 'Simple Task',
description: 'Basic description',
details: 'Basic implementation details',
status: 'pending'
};
readJSON.mockReturnValue(mockTasksData);
taskExists.mockReturnValue(true);
findTaskById.mockReturnValue({ task: mockTask });
generateObjectService.mockResolvedValue({
mainResult: {
title: 'Task with Enhanced Security',
description: 'Description with security considerations',
details: 'Implementation with security validation and encryption',
testStrategy: 'Security-focused testing strategy'
},
telemetryData: { tokens: 120, cost: 0.012 }
});
const context = {
projectRoot: '/test/project',
tag: 'master',
commandName: 'scope-up',
outputType: 'cli'
};
const customPrompt = 'Focus on adding security features and validation';
const result = await scopeUpTask(
'/test/tasks.json',
[1],
'heavy',
customPrompt,
context,
'text'
);
expect(result).toBeDefined();
expect(generateObjectService).toHaveBeenCalledWith(
expect.objectContaining({
prompt: expect.stringContaining(
'Focus on adding security features and validation'
)
})
);
});
});
describe('scopeDownTask', () => {
it('should decrease task complexity with regular strength', async () => {
const mockTasksData = {
tasks: [
{
id: 1,
title: 'Complex Task with Many Features',
description: 'Comprehensive description with multiple requirements',
details:
'Detailed implementation with advanced features, error handling, validation',
status: 'pending'
}
]
};
const mockTask = {
id: 1,
title: 'Complex Task with Many Features',
description: 'Comprehensive description with multiple requirements',
details:
'Detailed implementation with advanced features, error handling, validation',
status: 'pending'
};
readJSON.mockReturnValue(mockTasksData);
taskExists.mockReturnValue(true);
findTaskById.mockReturnValue({ task: mockTask });
generateObjectService.mockResolvedValue({
mainResult: {
title: 'Simple Task',
description: 'Basic description',
details: 'Basic implementation focusing on core functionality',
testStrategy: 'Simple unit tests for core functionality'
},
telemetryData: { tokens: 80, cost: 0.008 }
});
const context = {
projectRoot: '/test/project',
tag: 'master',
commandName: 'scope-down',
outputType: 'cli'
};
const result = await scopeDownTask(
'/test/tasks.json',
[1],
'regular',
null,
context,
'text'
);
expect(result).toBeDefined();
expect(result.updatedTasks).toHaveLength(1);
expect(writeJSON).toHaveBeenCalled();
});
});
describe('strength level validation', () => {
it('should validate strength parameter correctly', () => {
expect(validateStrength('light')).toBe(true);
expect(validateStrength('regular')).toBe(true);
expect(validateStrength('heavy')).toBe(true);
expect(validateStrength('invalid')).toBe(false);
expect(validateStrength('')).toBe(false);
expect(validateStrength(null)).toBe(false);
});
});
describe('multiple task IDs handling', () => {
it('should handle comma-separated task IDs', async () => {
const mockTasksData = {
tasks: [
{
id: 1,
title: 'Task 1',
description: 'Desc 1',
details: 'Details 1',
status: 'pending'
},
{
id: 2,
title: 'Task 2',
description: 'Desc 2',
details: 'Details 2',
status: 'pending'
}
]
};
readJSON.mockReturnValue(mockTasksData);
taskExists.mockReturnValue(true);
findTaskById
.mockReturnValueOnce({
task: {
id: 1,
title: 'Task 1',
description: 'Desc 1',
details: 'Details 1',
status: 'pending'
}
})
.mockReturnValueOnce({
task: {
id: 2,
title: 'Task 2',
description: 'Desc 2',
details: 'Details 2',
status: 'pending'
}
});
generateObjectService.mockResolvedValue({
mainResult: {
title: 'Enhanced Task',
description: 'Enhanced description',
details: 'Enhanced details',
testStrategy: 'Enhanced testing'
},
telemetryData: { tokens: 100, cost: 0.01 }
});
const context = {
projectRoot: '/test/project',
tag: 'master',
commandName: 'scope-up',
outputType: 'cli'
};
const result = await scopeUpTask(
'/test/tasks.json',
[1, 2],
'regular',
null,
context,
'text'
);
expect(result.updatedTasks).toHaveLength(2);
expect(generateObjectService).toHaveBeenCalledTimes(2);
});
});
});