task-master-neo-sdlc
Version:
Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.
137 lines (114 loc) • 6.34 kB
JavaScript
import { RequirementsValidatorAgent } from '../requirements-validator';
import { KnowledgeGraph } from '../../knowledge-graph'; // Adjust path
import { AgentWorkflowSystem } from '../../agent-workflow'; // Adjust path
// Mocks
const mockKnowledgeGraph = {
addNode: jest.fn(),
findNodes: jest.fn(),
findEdges: jest.fn()
};
const mockWorkflow = {};
describe('RequirementsValidatorAgent', () => {
let agent;
beforeEach(() => {
jest.clearAllMocks();
agent = new RequirementsValidatorAgent(mockKnowledgeGraph, mockWorkflow);
jest.spyOn(console, 'log').mockImplementation(() => {});
});
afterEach(() => {
console.log.mockRestore();
});
it('should validate against specific requirements and find compliance', async () => {
const targetId = 'component:login-button';
const reqId1 = 'req:auth-001';
const reqId2 = 'req:ui-005';
const mockTargetNode = { id: targetId, data: { label: 'Login', usesOAuth: true } };
const mockReqNode1 = { id: reqId1, data: { id: reqId1, summary: 'Use OAuth', criteria: { keyword: 'OAuth' } } };
const mockReqNode2 = { id: reqId2, data: { id: reqId2, summary: 'Label must exist', criteria: { requiredProperty: 'label' } } };
mockKnowledgeGraph.findNodes
.mockImplementationOnce(async ({ id }) => id === targetId ? [mockTargetNode] : []) // Find target
.mockImplementationOnce(async ({ ids }) => { // Find requirements by ID
const nodes = [];
if (ids.includes(reqId1)) nodes.push(mockReqNode1);
if (ids.includes(reqId2)) nodes.push(mockReqNode2);
return nodes;
});
mockKnowledgeGraph.addNode.mockResolvedValue(undefined);
const report = await agent.validateAgainstRequirements(targetId, [reqId1, reqId2]);
expect(report).toBeDefined();
expect(report.status).toBe('compliant');
expect(report.violations).toEqual([]);
expect(report.requirementsChecked).toEqual([reqId1, reqId2]);
expect(mockKnowledgeGraph.findNodes).toHaveBeenCalledWith({ id: targetId });
expect(mockKnowledgeGraph.findNodes).toHaveBeenCalledWith({ ids: [reqId1, reqId2], type: 'requirement' });
expect(mockKnowledgeGraph.addNode).toHaveBeenCalledWith(expect.objectContaining({
type: 'requirements_validation_report',
data: expect.objectContaining({ status: 'compliant' })
}));
});
it('should validate against associated requirements found via KG edges', async () => {
const targetId = 'api_endpoint:POST:_api_users';
const reqId = 'req:data-010';
const mockTargetNode = { id: targetId, data: { usesEncryption: true } };
const mockReqNode = { id: reqId, data: { id: reqId, summary: 'Must use encryption', criteria: { keyword: 'Encryption' } } };
const mockEdge = { source: reqId, target: targetId, relationship: 'implements' };
mockKnowledgeGraph.findNodes
.mockImplementationOnce(async ({ id }) => id === targetId ? [mockTargetNode] : []) // Find target
.mockImplementationOnce(async ({ ids }) => ids.includes(reqId) ? [mockReqNode] : []); // Find requirements by ID from edge
mockKnowledgeGraph.findEdges.mockResolvedValue([mockEdge]); // Find edge linking requirement
mockKnowledgeGraph.addNode.mockResolvedValue(undefined);
const report = await agent.validateAgainstRequirements(targetId); // No specific IDs passed
expect(report.status).toBe('compliant');
expect(report.violations).toEqual([]);
expect(report.requirementsChecked).toEqual([reqId]);
expect(mockKnowledgeGraph.findEdges).toHaveBeenCalledWith({ target: targetId, relationship: 'implements' });
expect(mockKnowledgeGraph.findNodes).toHaveBeenCalledWith({ ids: [reqId], type: 'requirement' });
expect(mockKnowledgeGraph.addNode).toHaveBeenCalled();
});
it('should report violations when requirements are not met', async () => {
const targetId = 'component:profile-form';
const reqId1 = 'req:ux-001'; // Missing property
const reqId2 = 'req:sec-002'; // Missing keyword
const mockTargetNode = { id: targetId, data: { fields: ['name'], usesTLS: false } }; // Missing 'email', no 'TLS' keyword
const mockReqNode1 = { id: reqId1, data: { id: reqId1, criteria: { requiredProperty: 'email' } } };
const mockReqNode2 = { id: reqId2, data: { id: reqId2, criteria: { keyword: 'TLS' } } };
mockKnowledgeGraph.findNodes
.mockResolvedValueOnce([mockTargetNode])
.mockResolvedValueOnce([mockReqNode1, mockReqNode2]);
mockKnowledgeGraph.addNode.mockResolvedValue(undefined);
const report = await agent.validateAgainstRequirements(targetId, [reqId1, reqId2]);
expect(report.status).toBe('non-compliant');
expect(report.violations).toHaveLength(2);
expect(report.violations).toContainEqual({
requirementId: reqId1,
details: 'Missing required property: email'
});
expect(report.violations).toContainEqual({
requirementId: reqId2,
details: 'Implementation may not meet criteria keyword: TLS'
});
expect(mockKnowledgeGraph.addNode).toHaveBeenCalledWith(expect.objectContaining({
data: expect.objectContaining({ status: 'non-compliant' })
}));
});
it('should skip validation if no requirements are found or provided', async () => {
const targetId = 'component:orphan';
const mockTargetNode = { id: targetId, data: {} };
mockKnowledgeGraph.findNodes.mockResolvedValueOnce([mockTargetNode]);
mockKnowledgeGraph.findEdges.mockResolvedValue([]); // No edges linking requirements
const report = await agent.validateAgainstRequirements(targetId);
expect(report.status).toBe('skipped');
expect(report.violations).toEqual([]);
expect(report.requirementsChecked).toEqual([]);
expect(mockKnowledgeGraph.findEdges).toHaveBeenCalledWith({ target: targetId, relationship: 'implements' });
expect(mockKnowledgeGraph.addNode).not.toHaveBeenCalled(); // No report added if skipped
});
it('should throw error if target entity is not found', async () => {
const targetId = 'nonexistent:entity';
mockKnowledgeGraph.findNodes.mockResolvedValue([]); // Target not found
await expect(agent.validateAgainstRequirements(targetId)).rejects.toThrow(
`Target entity ${targetId} not found for validation.`
);
expect(mockKnowledgeGraph.addNode).not.toHaveBeenCalled();
});
});