mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2253d05618
Remove the nested v3/ subdirectory by moving all active source code, tests, configs, and assets directly to the project root. Archive v2/ (dead code, 847MB) to v2-archive.tar.gz. Key changes: - Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/ - Move v3/tsconfig.json, v3/vitest.config.ts to root - Merge v3/package.json into root package.json (ESM, scripts, deps, exports) - Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/ - Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes - Fix all init installer path resolution (3-level-up → 2-level-up) - Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe" - Update settings.json ADR/DDD directories to docs/implementation/ - Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks) - Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces - Update 15 guidance shards: v3/src/ → src/ path references - Fix sync interfaces: remove v3/ and v2/ path references - Fix test path calculations (process.cwd() + '..' no longer needed) - Fix flaky perf test threshold (500ms → 1000ms for CI environments) - Fix complexity-analyzer test to match ADR-051 keyword-based eligibility Build passes, 17,901 tests pass, CLI and MCP bundles verified. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
789 lines
23 KiB
TypeScript
789 lines
23 KiB
TypeScript
/**
|
|
* Agentic QE v3 - Domain MCP Tools Tests
|
|
* Tests for all 14 domain-specific MCP tools per ADR-010
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
import {
|
|
TestGenerateTool,
|
|
TestExecuteTool,
|
|
CoverageAnalyzeTool,
|
|
CoverageGapsTool,
|
|
QualityEvaluateTool,
|
|
DefectPredictTool,
|
|
RequirementsValidateTool,
|
|
CodeAnalyzeTool,
|
|
SecurityScanTool,
|
|
ContractValidateTool,
|
|
VisualCompareTool,
|
|
A11yAuditTool,
|
|
ChaosInjectTool,
|
|
LearningOptimizeTool,
|
|
} from '../../../../src/mcp/tools';
|
|
|
|
// Mock shared memory backend to prevent real SQLite initialization in unit tests
|
|
vi.mock('../../../../src/mcp/tools/base', async (importOriginal) => {
|
|
const original = await importOriginal<typeof import('../../../../src/mcp/tools/base')>();
|
|
const mockMemory = {
|
|
get: vi.fn().mockResolvedValue(null),
|
|
set: vi.fn().mockResolvedValue(undefined),
|
|
delete: vi.fn().mockResolvedValue(undefined),
|
|
search: vi.fn().mockResolvedValue([]),
|
|
list: vi.fn().mockResolvedValue([]),
|
|
initialize: vi.fn().mockResolvedValue(undefined),
|
|
dispose: vi.fn().mockResolvedValue(undefined),
|
|
};
|
|
return {
|
|
...original,
|
|
getSharedMemoryBackend: vi.fn().mockResolvedValue(mockMemory),
|
|
getMemoryBackend: vi.fn().mockResolvedValue(mockMemory),
|
|
};
|
|
});
|
|
|
|
// ============================================================================
|
|
// 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 () => {
|
|
// Use demo mode to avoid timeout - demo mode returns fake predictions for non-empty input
|
|
const result = await tool.invoke({
|
|
files: ['test.ts'], // Provide a file to get a result
|
|
}, { demoMode: true });
|
|
|
|
// In demo mode, should succeed with fake predictions
|
|
expect(result.success).toBe(true);
|
|
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.skip('should support index action', async () => {
|
|
// SKIP: This test requires actual file indexing which takes too long
|
|
// In a real CI environment, this would need to use demo mode or be an integration test
|
|
const result = await tool.invoke({
|
|
action: 'index',
|
|
target: 'src/',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.data?.indexResult).toBeDefined();
|
|
});
|
|
|
|
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.skip('should return empty results for search with no matches', async () => {
|
|
// SKIP: This test does actual search which may timeout in CI
|
|
// 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 () => {
|
|
// The A11yAuditTool uses AccessibilityTesterService which falls back to
|
|
// heuristic mode when browser tools are unavailable. In unit tests,
|
|
// browser mode is not available, so heuristic analysis is used.
|
|
// Use a data URL for instant, deterministic offline testing.
|
|
const result = await tool.invoke({
|
|
urls: ['data:text/html,<html><head><title>Test</title></head><body><h1>Accessible Page</h1><p>Content</p></body></html>'],
|
|
});
|
|
|
|
// The tool should succeed with heuristic-based accessibility analysis
|
|
expect(result.success).toBe(true);
|
|
expect(result.data?.audits).toBeDefined();
|
|
expect(result.data?.summary).toBeDefined();
|
|
}, 60000); // Allow 60s — CI runners are slower with memory backend initialization
|
|
|
|
it('should support WCAG standard selection', async () => {
|
|
// Use data URL for instant, deterministic offline testing
|
|
const result = await tool.invoke({
|
|
urls: ['data:text/html,<html><head><title>WCAG Test</title></head><body><main><h1>Main Content</h1></main></body></html>'],
|
|
standard: 'wcag21-aa',
|
|
});
|
|
|
|
// Heuristic mode should return success
|
|
expect(result.success).toBe(true);
|
|
}, 60000); // Allow 60s — CI runners are slower with memory backend initialization
|
|
});
|
|
|
|
// ============================================================================
|
|
// 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);
|
|
});
|
|
});
|