task-master-neo-sdlc
Version:
Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.
169 lines (145 loc) • 6.35 kB
JavaScript
import { TechnicalDebtManagerAgent } from '../technical-debt-manager';
import { KnowledgeGraph } from '../../knowledge-graph'; // Adjust path
import { AgentWorkflowSystem } from '../../agent-workflow'; // Adjust path
// Mocks
const mockKnowledgeGraph = {
addNode: jest.fn(),
findNodes: jest.fn(),
updateContext: jest.fn()
};
const mockWorkflow = {
createTask: jest.fn() // Mock if used
};
describe('TechnicalDebtManagerAgent', () => {
let agent;
beforeEach(() => {
jest.clearAllMocks();
agent = new TechnicalDebtManagerAgent(mockKnowledgeGraph, mockWorkflow);
jest.spyOn(console, 'log').mockImplementation(() => {});
});
afterEach(() => {
console.log.mockRestore();
});
it('should identify technical debt (placeholder)', async () => {
const scope = { files: ['some/file.js'] };
mockKnowledgeGraph.addNode.mockResolvedValue(undefined);
// Mock KG findNodes if querying for debt indicators
const debtItems = await agent.identifyTechnicalDebt(scope);
expect(debtItems).toBeDefined();
expect(debtItems.length).toBe(1); // Based on placeholder logic
const item = debtItems[0];
expect(item.id).toMatch(/^techDebt_/);
expect(item.status).toBe('identified');
expect(mockKnowledgeGraph.addNode).toHaveBeenCalledWith({
id: `technicalDebt:${item.id}`,
type: 'technical_debt_item',
data: item
});
});
it('should prioritize technical debt by severity', async () => {
const mockDebtNodes = [
{ id: 'td:1', data: { id: '1', severity: 'low' } },
{ id: 'td:2', data: { id: '2', severity: 'high' } },
{ id: 'td:3', data: { id: '3', severity: 'medium' } }
];
mockKnowledgeGraph.findNodes.mockResolvedValue(mockDebtNodes);
const prioritized = await agent.prioritizeDebt();
expect(prioritized).toBeDefined();
expect(prioritized.length).toBe(3);
expect(prioritized[0].severity).toBe('high');
expect(prioritized[1].severity).toBe('medium');
expect(prioritized[2].severity).toBe('low');
expect(mockKnowledgeGraph.findNodes).toHaveBeenCalledWith({ type: 'technical_debt_item' });
});
it('should prioritize a subset of technical debt items', async () => {
const itemIdsToPrioritize = ['itemA', 'itemC'];
const mockDebtNodes = [
{ id: 'technicalDebt:itemA', data: { id: 'itemA', severity: 'medium' } },
{ id: 'technicalDebt:itemB', data: { id: 'itemB', severity: 'high' } }, // Should be filtered out
{ id: 'technicalDebt:itemC', data: { id: 'itemC', severity: 'low' } },
];
mockKnowledgeGraph.findNodes.mockResolvedValue(mockDebtNodes);
const prioritized = await agent.prioritizeDebt(itemIdsToPrioritize);
expect(prioritized).toBeDefined();
expect(prioritized.length).toBe(2);
expect(prioritized[0].id).toBe('itemA'); // Medium
expect(prioritized[1].id).toBe('itemC'); // Low
expect(mockKnowledgeGraph.findNodes).toHaveBeenCalledWith({ type: 'technical_debt_item' });
});
it('should plan debt resolution and create a task', async () => {
const debtItemId = 'debt_xyz';
const mockDebtNode = {
id: `technicalDebt:${debtItemId}`,
type: 'technical_debt_item',
data: {
id: debtItemId,
description: 'Complex function',
location: { file: 'utils.js' },
status: 'identified'
}
};
mockKnowledgeGraph.findNodes.mockResolvedValue([mockDebtNode]);
mockKnowledgeGraph.updateContext.mockResolvedValue(undefined);
mockKnowledgeGraph.addNode.mockResolvedValue(undefined);
const task = await agent.planDebtResolution(debtItemId);
expect(task).toBeDefined();
expect(task.id).toMatch(/^refactorTask_/);
expect(task.title).toContain(debtItemId);
expect(task.relatedDebt).toBe(debtItemId);
expect(task.status).toBe('pending');
expect(mockKnowledgeGraph.findNodes).toHaveBeenCalledWith({ id: `technicalDebt:${debtItemId}` });
// Check debt item status update
expect(mockKnowledgeGraph.updateContext).toHaveBeenCalledWith({
id: mockDebtNode.id,
data: expect.objectContaining({ status: 'planned' })
});
// Check task creation in KG
expect(mockKnowledgeGraph.addNode).toHaveBeenCalledWith({
id: `task:${task.id}`,
type: 'refactoring_task',
data: task,
edges: [{ target: mockDebtNode.id, relationship: 'addresses' }]
});
// Optionally check workflow task creation
// expect(mockWorkflow.createTask).toHaveBeenCalled();
});
it('should throw error if debt item not found during planning', async () => {
mockKnowledgeGraph.findNodes.mockResolvedValue([]); // Simulate not found
await expect(agent.planDebtResolution('nonexistent_debt')).rejects.toThrow(
'Technical debt item nonexistent_debt not found.'
);
});
it('should update debt status', async () => {
const debtItemId = 'debt_abc';
const newStatus = 'resolved';
const mockDebtNode = {
id: `technicalDebt:${debtItemId}`,
type: 'technical_debt_item',
data: { id: debtItemId, status: 'in_progress' }
};
mockKnowledgeGraph.findNodes.mockResolvedValue([mockDebtNode]);
mockKnowledgeGraph.updateContext.mockResolvedValue(undefined);
await agent.updateDebtStatus(debtItemId, newStatus);
expect(mockKnowledgeGraph.findNodes).toHaveBeenCalledWith({ id: `technicalDebt:${debtItemId}` });
expect(mockKnowledgeGraph.updateContext).toHaveBeenCalledWith({
id: mockDebtNode.id,
data: expect.objectContaining({ status: newStatus })
});
});
it('should throw error for invalid status update', async () => {
const debtItemId = 'debt_123';
const invalidStatus = 'invalid_status';
const mockDebtNode = { id: `technicalDebt:${debtItemId}`, data: {} };
mockKnowledgeGraph.findNodes.mockResolvedValue([mockDebtNode]);
await expect(agent.updateDebtStatus(debtItemId, invalidStatus)).rejects.toThrow(
`Invalid status: ${invalidStatus}`
);
expect(mockKnowledgeGraph.updateContext).not.toHaveBeenCalled();
});
it('should throw error if debt item not found during status update', async () => {
mockKnowledgeGraph.findNodes.mockResolvedValue([]);
await expect(agent.updateDebtStatus('not_found_debt', 'resolved')).rejects.toThrow(
'Technical debt item not_found_debt not found.'
);
});
});