UNPKG

task-master-neo-sdlc

Version:

Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.

171 lines (140 loc) 7.62 kB
import { ArchitectureValidatorAgent } from '../architecture-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(), updateContext: jest.fn() }; const mockWorkflow = {}; // Spy on the actual rule methods to verify they are called let checkNoDirectDbFromFrontendSpy; let checkApiUsageSpy; describe('ArchitectureValidatorAgent', () => { let agent; beforeEach(() => { jest.clearAllMocks(); agent = new ArchitectureValidatorAgent(mockKnowledgeGraph, mockWorkflow); jest.spyOn(console, 'log').mockImplementation(() => {}); jest.spyOn(console, 'error').mockImplementation(() => {}); // Spy on rule methods *after* agent instantiation checkNoDirectDbFromFrontendSpy = jest.spyOn(agent, 'checkNoDirectDbFromFrontend'); checkApiUsageSpy = jest.spyOn(agent, 'checkApiUsage'); }); afterEach(() => { console.log.mockRestore(); console.error.mockRestore(); checkNoDirectDbFromFrontendSpy.mockRestore(); checkApiUsageSpy.mockRestore(); }); it('should validate architecture against all rules by default', async () => { checkNoDirectDbFromFrontendSpy.mockResolvedValue([]); // Rule passes checkApiUsageSpy.mockResolvedValue([]); // Rule passes mockKnowledgeGraph.addNode.mockResolvedValue(undefined); const report = await agent.validateArchitecture(); expect(report).toBeDefined(); expect(report.isCompliant).toBe(true); expect(report.violations).toEqual([]); expect(report.passedChecks).toEqual(['rule-no-direct-db-from-frontend', 'rule-api-gateway-pattern']); expect(report.rulesChecked).toEqual(['rule-no-direct-db-from-frontend', 'rule-api-gateway-pattern']); expect(checkNoDirectDbFromFrontendSpy).toHaveBeenCalledTimes(1); expect(checkApiUsageSpy).toHaveBeenCalledTimes(1); expect(mockKnowledgeGraph.addNode).toHaveBeenCalledWith({ id: expect.stringMatching(/^architectureValidation:/), type: 'architecture_validation_report', data: report }); }); it('should only validate specified rules', async () => { checkNoDirectDbFromFrontendSpy.mockResolvedValue([]); // Rule passes // checkApiUsageSpy is NOT mocked to return, so it won't be called mockKnowledgeGraph.addNode.mockResolvedValue(undefined); const report = await agent.validateArchitecture(['rule-no-direct-db-from-frontend']); expect(report.isCompliant).toBe(true); expect(report.violations).toEqual([]); expect(report.passedChecks).toEqual(['rule-no-direct-db-from-frontend']); expect(report.rulesChecked).toEqual(['rule-no-direct-db-from-frontend']); expect(checkNoDirectDbFromFrontendSpy).toHaveBeenCalledTimes(1); expect(checkApiUsageSpy).not.toHaveBeenCalled(); expect(mockKnowledgeGraph.addNode).toHaveBeenCalled(); }); it('should report violations from rules', async () => { const violationDetail = 'Frontend component component:button depends on DB schema db_schema:users'; checkNoDirectDbFromFrontendSpy.mockResolvedValue([violationDetail]); // Rule fails checkApiUsageSpy.mockResolvedValue([]); // Rule passes mockKnowledgeGraph.addNode.mockResolvedValue(undefined); const report = await agent.validateArchitecture(); expect(report.isCompliant).toBe(false); expect(report.passedChecks).toEqual(['rule-api-gateway-pattern']); expect(report.violations).toHaveLength(1); expect(report.violations[0]).toEqual({ ruleId: 'rule-no-direct-db-from-frontend', description: 'Frontend components should not directly depend on DB schemas.', details: violationDetail }); expect(checkNoDirectDbFromFrontendSpy).toHaveBeenCalledTimes(1); expect(checkApiUsageSpy).toHaveBeenCalledTimes(1); expect(mockKnowledgeGraph.addNode).toHaveBeenCalled(); }); it('should handle errors during rule execution', async () => { const error = new Error('KG query failed'); checkNoDirectDbFromFrontendSpy.mockRejectedValue(error); // Rule throws error checkApiUsageSpy.mockResolvedValue([]); // Rule passes mockKnowledgeGraph.addNode.mockResolvedValue(undefined); const report = await agent.validateArchitecture(); expect(report.isCompliant).toBe(false); expect(report.passedChecks).toEqual(['rule-api-gateway-pattern']); expect(report.violations).toHaveLength(1); expect(report.violations[0]).toEqual({ ruleId: 'rule-no-direct-db-from-frontend', description: 'Frontend components should not directly depend on DB schemas.', details: `Error during check: ${error.message}` }); expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Error executing rule rule-no-direct-db-from-frontend'), error); expect(checkNoDirectDbFromFrontendSpy).toHaveBeenCalledTimes(1); expect(checkApiUsageSpy).toHaveBeenCalledTimes(1); expect(mockKnowledgeGraph.addNode).toHaveBeenCalled(); }); // --- Tests for specific rule logic --- describe('checkNoDirectDbFromFrontend rule logic', () => { // Test the rule method directly, mocking KG calls it makes it('should find no violations when no direct dependencies exist', async () => { const mockComponents = [{ id: 'component:A', data: { dependencies: ['component:B'] } }]; const mockDbSchemas = [{ id: 'db_schema:users' }]; const mockEdges = [{ source: 'component:A', target: 'component:B', relationship: 'depends_on' }]; mockKnowledgeGraph.findNodes .mockImplementationOnce(async ({ type }) => type === 'design-component' ? mockComponents : []) .mockImplementationOnce(async ({ type }) => type === 'db_schema' ? mockDbSchemas : []); mockKnowledgeGraph.findEdges.mockResolvedValue(mockEdges); const violations = await agent.checkNoDirectDbFromFrontend(); expect(violations).toEqual([]); }); it('should detect violation via direct edge', async () => { const mockComponents = [{ id: 'component:C', data: {} }]; const mockDbSchemas = [{ id: 'db_schema:products' }]; const mockEdges = [{ source: 'component:C', target: 'db_schema:products', relationship: 'depends_on' }]; mockKnowledgeGraph.findNodes .mockResolvedValueOnce(mockComponents) .mockResolvedValueOnce(mockDbSchemas); mockKnowledgeGraph.findEdges.mockResolvedValue(mockEdges); const violations = await agent.checkNoDirectDbFromFrontend(); expect(violations).toHaveLength(1); expect(violations[0]).toContain('component:C directly depends on DB schema db_schema:products'); }); it('should detect violation via dependency array in data', async () => { const mockComponents = [{ id: 'component:D', data: { dependencies: ['db_schema:orders'] } }]; const mockDbSchemas = [{ id: 'db_schema:orders' }]; mockKnowledgeGraph.findNodes .mockResolvedValueOnce(mockComponents) .mockResolvedValueOnce(mockDbSchemas); mockKnowledgeGraph.findEdges.mockResolvedValue([]); // No direct edge const violations = await agent.checkNoDirectDbFromFrontend(); expect(violations).toHaveLength(1); expect(violations[0]).toContain('component:D lists direct dependency on DB schema db_schema:orders'); }); }); // Add tests for checkApiUsage rule logic similarly... // describe('checkApiUsage rule logic', () => { ... }); });