/** * Agentic QE v3 - Domain MCP Tools Tests * Tests for all 14 domain-specific MCP tools per ADR-010 */ import { describe, it, expect, beforeEach } from 'vitest'; import { TestGenerateTool, TestExecuteTool, CoverageAnalyzeTool, CoverageGapsTool, QualityEvaluateTool, DefectPredictTool, RequirementsValidateTool, CodeAnalyzeTool, SecurityScanTool, ContractValidateTool, VisualCompareTool, A11yAuditTool, ChaosInjectTool, LearningOptimizeTool, } from '../../../../src/mcp/tools'; // ============================================================================ // Test Generation Tool // ============================================================================ describe('TestGenerateTool', () => { let tool: TestGenerateTool; beforeEach(() => { tool = new TestGenerateTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/tests/generate'); }); it('should belong to test-generation domain', () => { expect(tool.domain).toBe('test-generation'); }); it('should have required parameters', () => { const schema = tool.getSchema(); expect(schema.required).toContain('sourceFiles'); }); it('should generate tests for source files', async () => { const result = await tool.invoke({ sourceFiles: ['src/service.ts'], testType: 'unit', framework: 'vitest', }); expect(result.success).toBe(true); expect(result.data?.tests).toBeDefined(); expect(result.data?.tests.length).toBeGreaterThan(0); }); it('should support streaming', () => { expect(tool.supportsStreaming).toBe(true); }); }); // ============================================================================ // Test Execution Tool // ============================================================================ describe('TestExecuteTool', () => { let tool: TestExecuteTool; beforeEach(() => { tool = new TestExecuteTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/tests/execute'); }); it('should belong to test-execution domain', () => { expect(tool.domain).toBe('test-execution'); }); it('should execute tests', async () => { const result = await tool.invoke({ pattern: '**/*.test.ts', }); // Tool may report success=false if tests fail, but should return data expect(result.data?.summary).toBeDefined(); expect(result.data?.summary.total).toBeGreaterThanOrEqual(0); }); it('should support parallel execution', async () => { const result = await tool.invoke({ testFiles: ['test1.test.ts'], parallel: true, parallelism: 4, }); // Tool returns data even if some tests fail expect(result.data?.summary).toBeDefined(); }); it('should return flaky tests when detected', async () => { const result = await tool.invoke({ testFiles: ['test1.test.ts', 'test2.test.ts', 'test3.test.ts'], retryCount: 3, }); // flakyTests is only present when flaky tests are detected // Since detection is probabilistic in the mock, just verify data is returned expect(result.data?.summary).toBeDefined(); }); }); // ============================================================================ // Coverage Analysis Tool // ============================================================================ describe('CoverageAnalyzeTool', () => { let tool: CoverageAnalyzeTool; beforeEach(() => { tool = new CoverageAnalyzeTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/coverage/analyze'); }); it('should belong to coverage-analysis domain', () => { expect(tool.domain).toBe('coverage-analysis'); }); it('should analyze coverage (with demo mode for unit test)', async () => { // Use demoMode to test output format without requiring real coverage data const result = await tool.invoke({ target: 'src/', dryRun: true, // explicit demo mode }); expect(result.success).toBe(true); expect(result.data?.summary).toBeDefined(); expect(result.data?.summary.lines).toBeDefined(); }); it('should return error when no coverage data found', async () => { // Without demo mode, should return error when no real coverage data const result = await tool.invoke({ target: 'nonexistent-path/', }); expect(result.success).toBe(false); expect(result.error).toContain('No coverage data found'); }); it('should include risk scoring (with demo mode)', async () => { const result = await tool.invoke({ target: 'src/', includeRiskScoring: true, dryRun: true, // explicit demo mode }); expect(result.success).toBe(true); }); }); // ============================================================================ // Coverage Gaps Tool // ============================================================================ describe('CoverageGapsTool', () => { let tool: CoverageGapsTool; beforeEach(() => { tool = new CoverageGapsTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/coverage/gaps'); }); it('should detect coverage gaps (with demo mode)', async () => { // Use demoMode to test output format without requiring real coverage data const result = await tool.invoke({ target: 'src/', maxLineCoverage: 60, }, { demoMode: true }); expect(result.success).toBe(true); expect(result.data?.gaps).toBeDefined(); expect(Array.isArray(result.data?.gaps)).toBe(true); }); it('should return error when no coverage data found', async () => { // Without demo mode, should return error when no real coverage data const result = await tool.invoke({ target: 'nonexistent-path/', }); expect(result.success).toBe(false); expect(result.error).toContain('No coverage data found'); }); it('should filter by risk score (with demo mode)', async () => { const result = await tool.invoke({ target: 'src/', minRiskScore: 0.7, }, { demoMode: true }); expect(result.success).toBe(true); }); it('should suggest tests for gaps (with demo mode)', async () => { const result = await tool.invoke({ target: 'src/', suggestTests: true, }, { demoMode: true }); expect(result.success).toBe(true); }); }); // ============================================================================ // Quality Evaluate Tool // ============================================================================ describe('QualityEvaluateTool', () => { let tool: QualityEvaluateTool; beforeEach(() => { tool = new QualityEvaluateTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/quality/evaluate'); }); it('should belong to quality-assessment domain', () => { expect(tool.domain).toBe('quality-assessment'); }); it('should evaluate quality gates', async () => { const result = await tool.invoke({ gateName: 'default', }); expect(result.success).toBe(true); expect(result.data?.passed).toBeDefined(); expect(result.data?.checks).toBeDefined(); }); it('should include deployment advice', async () => { const result = await tool.invoke({ gateName: 'production', includeDeploymentAdvice: true, }); expect(result.success).toBe(true); expect(result.data?.deploymentAdvice).toBeDefined(); }); }); // ============================================================================ // Defect Predict Tool // ============================================================================ describe('DefectPredictTool', () => { let tool: DefectPredictTool; beforeEach(() => { tool = new DefectPredictTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/defects/predict'); }); it('should belong to defect-intelligence domain', () => { expect(tool.domain).toBe('defect-intelligence'); }); it('should predict defects (with demo mode)', async () => { // Use demoMode to test output format without requiring real prediction service const result = await tool.invoke({ target: 'src/', }, { demoMode: true }); expect(result.success).toBe(true); expect(result.data?.predictions).toBeDefined(); expect(Array.isArray(result.data?.predictions)).toBe(true); }); it('should return error when prediction service fails', async () => { // Without demo mode, service failure returns error (not fake data) const result = await tool.invoke({ files: ['nonexistent-file.ts'], }); // Should either succeed with real data or fail with error // Won't return fake data as fallback expect(result.metadata).toBeDefined(); }); it('should include risk factors (with demo mode)', async () => { const result = await tool.invoke({ target: 'src/', includeFactors: true, }, { demoMode: true }); expect(result.success).toBe(true); }); }); // ============================================================================ // Requirements Validate Tool // ============================================================================ describe('RequirementsValidateTool', () => { let tool: RequirementsValidateTool; beforeEach(() => { tool = new RequirementsValidateTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/requirements/validate'); }); it('should belong to requirements-validation domain', () => { expect(tool.domain).toBe('requirements-validation'); }); it('should validate requirements', async () => { const result = await tool.invoke({ requirements: [ { id: 'REQ-001', title: 'User Login', description: 'User should be able to log in with valid credentials and see the dashboard after authentication.', acceptanceCriteria: ['Login form displays', 'Valid credentials accepted'], }, ], }); expect(result.success).toBe(true); expect(result.data?.validationResults).toBeDefined(); }); it('should generate BDD scenarios', async () => { const result = await tool.invoke({ requirements: [ { id: 'REQ-001', title: 'User Login', description: 'User should be able to log in with valid credentials and see the dashboard after authentication.', acceptanceCriteria: ['Login form displays', 'Valid credentials accepted'], }, ], generateBDD: true, }); expect(result.success).toBe(true); expect(result.data?.bddScenarios).toBeDefined(); }); }); // ============================================================================ // Code Analyze Tool // ============================================================================ describe('CodeAnalyzeTool', () => { let tool: CodeAnalyzeTool; beforeEach(() => { tool = new CodeAnalyzeTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/code/analyze'); }); it('should belong to code-intelligence domain', () => { expect(tool.domain).toBe('code-intelligence'); }); it('should support index action', async () => { const result = await tool.invoke({ action: 'index', target: 'src/', }); expect(result.success).toBe(true); expect(result.data?.indexResult).toBeDefined(); }, 30000); // Extended timeout for file indexing it('should support search action (with demo mode)', async () => { // Use demoMode to test output format const result = await tool.invoke({ action: 'search', query: 'UserService', }, { demoMode: true }); expect(result.success).toBe(true); expect(result.data?.searchResult).toBeDefined(); }); it('should return empty results for search with no matches', async () => { // Without demo mode, no matches returns empty (not fake data) const result = await tool.invoke({ action: 'search', query: 'NonexistentClass12345', }); expect(result.success).toBe(true); expect(result.data?.searchResult?.results).toEqual([]); }); it('should support impact action (with demo mode)', async () => { // Use demoMode to test output format const result = await tool.invoke({ action: 'impact', changedFiles: ['src/service.ts'], }, { demoMode: true }); expect(result.success).toBe(true); expect(result.data?.impactResult).toBeDefined(); }); it('should support dependencies action', async () => { const result = await tool.invoke({ action: 'dependencies', target: 'src/service.ts', }); expect(result.success).toBe(true); expect(result.data?.dependencyResult).toBeDefined(); }); }); // ============================================================================ // Security Scan Tool // ============================================================================ describe('SecurityScanTool', () => { let tool: SecurityScanTool; beforeEach(() => { tool = new SecurityScanTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/security/scan'); }); it('should belong to security-compliance domain', () => { expect(tool.domain).toBe('security-compliance'); }); it('should run security scan', async () => { const result = await tool.invoke({ target: 'src/', }); expect(result.success).toBe(true); expect(result.data?.summary).toBeDefined(); expect(result.data?.vulnerabilities).toBeDefined(); }); it('should support SAST scan', async () => { const result = await tool.invoke({ target: 'src/', scanTypes: { sast: true }, }); expect(result.success).toBe(true); }); it('should check compliance', async () => { const result = await tool.invoke({ target: 'src/', compliance: ['owasp', 'gdpr'], }); expect(result.success).toBe(true); expect(result.data?.complianceResults).toBeDefined(); }); }); // ============================================================================ // Contract Validate Tool // ============================================================================ describe('ContractValidateTool', () => { let tool: ContractValidateTool; beforeEach(() => { tool = new ContractValidateTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/contracts/validate'); }); it('should belong to contract-testing domain', () => { expect(tool.domain).toBe('contract-testing'); }); it('should validate contract', async () => { const result = await tool.invoke({ contractContent: '{"openapi": "3.0.0"}', format: 'openapi', }); expect(result.success).toBe(true); expect(result.data?.isValid).toBeDefined(); expect(result.data?.validationErrors).toBeDefined(); }); it('should detect breaking changes', async () => { const result = await tool.invoke({ contractContent: '{}', baselineVersion: '1.0.0', checkBreakingChanges: true, }); expect(result.success).toBe(true); expect(result.data?.breakingChanges).toBeDefined(); }); }); // ============================================================================ // Visual Compare Tool // ============================================================================ describe('VisualCompareTool', () => { let tool: VisualCompareTool; beforeEach(() => { tool = new VisualCompareTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/visual/compare'); }); it('should belong to visual-accessibility domain', () => { expect(tool.domain).toBe('visual-accessibility'); }); it('should compare visual snapshots', async () => { const result = await tool.invoke({ urls: ['https://example.com'], }); expect(result.success).toBe(true); expect(result.data?.comparisons).toBeDefined(); expect(result.data?.summary).toBeDefined(); }); it('should apply threshold', async () => { const result = await tool.invoke({ urls: ['https://example.com'], threshold: 0.05, }); expect(result.success).toBe(true); }); }); // ============================================================================ // A11y Audit Tool // ============================================================================ describe('A11yAuditTool', () => { let tool: A11yAuditTool; beforeEach(() => { tool = new A11yAuditTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/a11y/audit'); }); it('should belong to visual-accessibility domain', () => { expect(tool.domain).toBe('visual-accessibility'); }); it('should audit accessibility', async () => { const result = await tool.invoke({ urls: ['https://example.com'], }); expect(result.success).toBe(true); expect(result.data?.audits).toBeDefined(); expect(result.data?.summary).toBeDefined(); }); it('should support WCAG standard selection', async () => { const result = await tool.invoke({ urls: ['https://example.com'], standard: 'wcag21-aa', }); expect(result.success).toBe(true); }); }); // ============================================================================ // Chaos Inject Tool // ============================================================================ describe('ChaosInjectTool', () => { let tool: ChaosInjectTool; beforeEach(() => { tool = new ChaosInjectTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/chaos/inject'); }); it('should belong to chaos-resilience domain', () => { expect(tool.domain).toBe('chaos-resilience'); }); it('should have required parameters', () => { const schema = tool.getSchema(); expect(schema.required).toContain('faultType'); expect(schema.required).toContain('target'); }); it('should inject fault in dry run mode', async () => { const result = await tool.invoke({ faultType: 'latency', target: 'api-service', dryRun: true, }); expect(result.success).toBe(true); expect(result.data?.status).toBeDefined(); expect(result.data?.faultInjected).toBe(false); // dry run }); it('should validate hypothesis', async () => { const result = await tool.invoke({ faultType: 'error', target: 'api-service', dryRun: true, hypothesis: 'System should recover within 30s', }); expect(result.success).toBe(true); expect(result.data?.hypothesisValidated).toBeDefined(); }); }); // ============================================================================ // Learning Optimize Tool // ============================================================================ describe('LearningOptimizeTool', () => { let tool: LearningOptimizeTool; beforeEach(() => { tool = new LearningOptimizeTool(); }); it('should have correct name', () => { expect(tool.name).toBe('qe/learning/optimize'); }); it('should belong to learning-optimization domain', () => { expect(tool.domain).toBe('learning-optimization'); }); it('should have required parameters', () => { const schema = tool.getSchema(); expect(schema.required).toContain('action'); }); it('should support learn action (with demo mode)', async () => { // Use demoMode to test output format with demo data const result = await tool.invoke({ action: 'learn', domain: 'test-generation', }, { demoMode: true }); expect(result.success).toBe(true); expect(result.data?.learnResult).toBeDefined(); expect(result.data?.learnResult?.patternsLearned).toBeGreaterThan(0); }); it('should return empty patterns when no learning data', async () => { // Without demo mode, no learning data returns empty results (not fake data) const result = await tool.invoke({ action: 'learn', domain: 'test-generation', }); expect(result.success).toBe(true); expect(result.data?.learnResult).toBeDefined(); // Returns empty patterns, not fake data expect(result.data?.learnResult?.patternsLearned).toBe(0); }); it('should support optimize action', async () => { const result = await tool.invoke({ action: 'optimize', objective: { metric: 'coverage', direction: 'maximize' }, }); expect(result.success).toBe(true); expect(result.data?.optimizeResult).toBeDefined(); }); it('should support transfer action', async () => { const result = await tool.invoke({ action: 'transfer', domain: 'test-generation', targetDomain: 'coverage-analysis', }); expect(result.success).toBe(true); expect(result.data?.transferResult).toBeDefined(); }); it('should support patterns action', async () => { const result = await tool.invoke({ action: 'patterns', }); expect(result.success).toBe(true); expect(result.data?.patternResult).toBeDefined(); }); it('should support dashboard action', async () => { const result = await tool.invoke({ action: 'dashboard', }); expect(result.success).toBe(true); expect(result.data?.dashboardResult).toBeDefined(); }); it('should reject unknown action', async () => { const result = await tool.invoke({ action: 'unknown' as any, }); expect(result.success).toBe(false); expect(result.error).toBeDefined(); // Validation may catch it before execute expect(result.error).toMatch(/unknown|Validation/i); }); });