mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2e8642030b
🎯 Test Suite Stabilization - 94.2% Pass Rate Achieved! This release represents a major quality milestone with systematic test stabilization that increased the unit test pass rate from 71.1% (619/870) to 94.2% (903/959), exceeding the 90% goal set in GitHub issue #33. Major Changes: - Fixed all TypeScript compilation errors blocking release - Created batched integration test script to prevent OOM crashes - Documented integration test memory leak root cause (issue #35) - Enhanced mock infrastructure for better test reliability - Updated release verification policies in CLAUDE.md TypeScript Fixes: - Fixed TestGeneratorAgent AgentCapability structure (4 errors) - Rewrote Database mock with proper type casting (36 methods) - Rewrote LearningEngine mock with proper type casting - Excluded __mocks__ from TypeScript compilation Test Infrastructure: - Created scripts/test-integration-batched.sh for safe execution - Batches 46 integration tests (5 files at a time) - Prevents workspace crashes in constrained environments - Updated package.json test:integration to use batched script Memory Leak Investigation: - Root cause: MemoryManager setInterval leak (138 timers) - Missing cleanup in 31 of 46 integration tests - Database connection pool exhaustion (23 instances) - Documented in GitHub issue #35 for v1.4.4 fix Release Verification: - aqe init: 19 agents, 34 skills, 8 commands ✅ - Databases: memory.db (221KB), patterns.db (155KB) ✅ - MCP interface: 54 tools functional ✅ - Fleet startup: 5 agents running successfully ✅ Files Changed: - Modified: 40 files (tests, mocks, core agents) - New: 2 files (batched script, LearningEngine mock) - Version: 1.4.2 → 1.4.3 Closes #33 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
676 lines
23 KiB
TypeScript
676 lines
23 KiB
TypeScript
/**
|
|
* Phase 2 End-to-End Workflow Integration Tests
|
|
*
|
|
* Tests complete workflows spanning multiple Phase 2 components:
|
|
* - Pattern-based test generation workflow
|
|
* - Continuous improvement loop workflow
|
|
* - ML flaky detection → fix → validation workflow
|
|
* - Cross-project pattern sharing workflow
|
|
*
|
|
* @module tests/integration/phase2/phase2-e2e-workflows
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
import { QEReasoningBank } from '@reasoning/QEReasoningBank';
|
|
import { LearningEngine } from '@learning/LearningEngine';
|
|
import { PatternExtractor } from '@reasoning/PatternExtractor';
|
|
import { FlakyTestDetector } from '@learning/FlakyTestDetector';
|
|
import { ImprovementLoop } from '@learning/ImprovementLoop';
|
|
import { PerformanceTracker } from '@learning/PerformanceTracker';
|
|
import { SwarmMemoryManager } from '@core/memory/SwarmMemoryManager';
|
|
import * as fs from 'fs-extra';
|
|
import * as path from 'path';
|
|
|
|
const TEST_OUTPUT_DIR = path.join(__dirname, '../../.tmp/phase2-e2e');
|
|
|
|
describe('Phase 2 End-to-End Workflow Tests', () => {
|
|
let reasoningBank: QEReasoningBank;
|
|
let learningEngine: LearningEngine;
|
|
let patternExtractor: PatternExtractor;
|
|
let flakyDetector: FlakyTestDetector;
|
|
let improvementLoop: ImprovementLoop;
|
|
let performanceTracker: PerformanceTracker;
|
|
let memoryManager: SwarmMemoryManager;
|
|
|
|
beforeEach(async () => {
|
|
await fs.ensureDir(TEST_OUTPUT_DIR);
|
|
|
|
memoryManager = new SwarmMemoryManager();
|
|
await memoryManager.initialize();
|
|
reasoningBank = new QEReasoningBank();
|
|
learningEngine = new LearningEngine();
|
|
patternExtractor = new PatternExtractor();
|
|
flakyDetector = new FlakyTestDetector();
|
|
performanceTracker = new PerformanceTracker();
|
|
improvementLoop = new ImprovementLoop(learningEngine, performanceTracker, memoryManager);
|
|
|
|
await memoryManager.clear('coordination');
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await memoryManager.clear('coordination');
|
|
await memoryManager.close();
|
|
learningEngine.clear();
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Workflow 1: Pattern-Based Test Generation
|
|
// ===========================================================================
|
|
|
|
describe('Workflow 1: Pattern-Based Test Generation', () => {
|
|
it('should complete pattern-based test generation workflow', async () => {
|
|
const workflowMetrics = {
|
|
startTime: performance.now(),
|
|
steps: [] as Array<{ step: string; duration: number; success: boolean }>
|
|
};
|
|
|
|
// Step 1: Extract patterns from existing tests
|
|
let stepStart = performance.now();
|
|
const existingTest = `
|
|
describe('UserService', () => {
|
|
beforeEach(() => {
|
|
service = new UserService();
|
|
});
|
|
|
|
it('should create user with valid data', async () => {
|
|
const user = await service.createUser({ name: 'John', email: 'john@example.com' });
|
|
expect(user.id).toBeDefined();
|
|
expect(user.email).toBe('john@example.com');
|
|
});
|
|
|
|
it('should throw on duplicate email', async () => {
|
|
await service.createUser({ name: 'John', email: 'test@example.com' });
|
|
await expect(service.createUser({ name: 'Jane', email: 'test@example.com' }))
|
|
.rejects.toThrow('Email already exists');
|
|
});
|
|
});
|
|
`;
|
|
|
|
const extractedPatterns = await patternExtractor.extractPatterns(existingTest, {
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
filePath: 'UserService.test.ts'
|
|
});
|
|
|
|
workflowMetrics.steps.push({
|
|
step: 'pattern-extraction',
|
|
duration: performance.now() - stepStart,
|
|
success: extractedPatterns.length > 0
|
|
});
|
|
|
|
expect(extractedPatterns.length).toBeGreaterThan(0);
|
|
|
|
// Step 2: Store patterns in ReasoningBank
|
|
stepStart = performance.now();
|
|
const storedPatternIds: string[] = [];
|
|
|
|
for (const pattern of extractedPatterns) {
|
|
const patternId = await reasoningBank.storePattern({
|
|
id: `e2e-pattern-${Date.now()}-${Math.random()}`,
|
|
name: pattern.name,
|
|
category: pattern.category,
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
description: pattern.description,
|
|
template: pattern.template || '',
|
|
applicability: {
|
|
complexity: pattern.complexity || 'medium',
|
|
context: pattern.context || [],
|
|
constraints: pattern.constraints || []
|
|
},
|
|
metrics: {
|
|
successRate: 0.85,
|
|
usageCount: 0,
|
|
averageQuality: 0,
|
|
lastUsed: new Date()
|
|
},
|
|
tags: pattern.tags || ['user', 'crud'],
|
|
metadata: { source: 'e2e-workflow', version: '1.0.0' }
|
|
});
|
|
|
|
storedPatternIds.push(patternId);
|
|
}
|
|
|
|
workflowMetrics.steps.push({
|
|
step: 'pattern-storage',
|
|
duration: performance.now() - stepStart,
|
|
success: storedPatternIds.length === extractedPatterns.length
|
|
});
|
|
|
|
expect(storedPatternIds.length).toBe(extractedPatterns.length);
|
|
|
|
// Step 3: Find matching patterns for new module
|
|
stepStart = performance.now();
|
|
const matches = await reasoningBank.findMatchingPatterns({
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
keywords: ['user', 'service'],
|
|
limit: 5
|
|
});
|
|
|
|
workflowMetrics.steps.push({
|
|
step: 'pattern-matching',
|
|
duration: performance.now() - stepStart,
|
|
success: matches.length > 0
|
|
});
|
|
|
|
expect(matches.length).toBeGreaterThan(0);
|
|
expect(matches[0].pattern.framework).toBe('jest');
|
|
|
|
// Step 4: Generate tests using matched patterns
|
|
stepStart = performance.now();
|
|
const generatedTests: string[] = [];
|
|
|
|
for (const match of matches.slice(0, 3)) {
|
|
const testCode = match.pattern.template
|
|
.replace(/\{\{moduleName\}\}/g, 'OrderService')
|
|
.replace(/\{\{entityName\}\}/g, 'Order');
|
|
|
|
generatedTests.push(testCode);
|
|
|
|
// Record pattern usage
|
|
await reasoningBank.updateMetrics(match.pattern.id, true, 0.92);
|
|
}
|
|
|
|
workflowMetrics.steps.push({
|
|
step: 'test-generation',
|
|
duration: performance.now() - stepStart,
|
|
success: generatedTests.length > 0
|
|
});
|
|
|
|
expect(generatedTests.length).toBeGreaterThan(0);
|
|
|
|
// Step 5: Learn from generation outcomes
|
|
stepStart = performance.now();
|
|
for (let i = 0; i < generatedTests.length; i++) {
|
|
await learningEngine.recordOutcome({
|
|
id: `gen-outcome-${i}`,
|
|
timestamp: new Date(),
|
|
testId: `generated-test-${i}`,
|
|
testName: `Generated test ${i}`,
|
|
outcome: 'success',
|
|
executionTime: 120,
|
|
coverage: 0.92,
|
|
edgeCasesCaught: 7,
|
|
feedback: {
|
|
quality: 0.92,
|
|
relevance: 0.95
|
|
},
|
|
metadata: {
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
complexity: 3,
|
|
linesOfCode: 150,
|
|
patternId: matches[i].pattern.id
|
|
}
|
|
});
|
|
}
|
|
|
|
workflowMetrics.steps.push({
|
|
step: 'learning-record',
|
|
duration: performance.now() - stepStart,
|
|
success: true
|
|
});
|
|
|
|
// Print workflow metrics
|
|
console.log('\n━━━ Pattern-Based Test Generation Workflow ━━━');
|
|
console.log(`Total Duration: ${(performance.now() - workflowMetrics.startTime).toFixed(2)}ms`);
|
|
console.log('\nSteps:');
|
|
workflowMetrics.steps.forEach(s => {
|
|
console.log(` ${s.step}: ${s.duration.toFixed(2)}ms [${s.success ? '✓' : '✗'}]`);
|
|
});
|
|
|
|
// Verify workflow success
|
|
expect(workflowMetrics.steps.every(s => s.success)).toBe(true);
|
|
expect(performance.now() - workflowMetrics.startTime).toBeLessThan(10000); // <10s total
|
|
}, 30000);
|
|
|
|
it('should reuse patterns across multiple projects', async () => {
|
|
// Project 1: Create and store patterns
|
|
const project1Patterns = await patternExtractor.extractPatterns(`
|
|
describe('AuthService', () => {
|
|
it('authenticates user', async () => {
|
|
const token = await authService.login('user@example.com', 'password');
|
|
expect(token).toBeDefined();
|
|
});
|
|
});
|
|
`, { framework: 'jest', language: 'typescript' });
|
|
|
|
for (const pattern of project1Patterns) {
|
|
await reasoningBank.storePattern({
|
|
id: `project1-${Date.now()}-${Math.random()}`,
|
|
name: pattern.name,
|
|
category: pattern.category,
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
description: pattern.description,
|
|
template: pattern.template || '',
|
|
applicability: { complexity: 'medium', context: [], constraints: [] },
|
|
metrics: { successRate: 0.88, usageCount: 0, averageQuality: 0, lastUsed: new Date() },
|
|
tags: ['auth', 'authentication'],
|
|
metadata: { project: 'project-1' }
|
|
});
|
|
}
|
|
|
|
// Project 2: Retrieve and reuse patterns
|
|
const matches = await reasoningBank.findMatchingPatterns({
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
tags: ['auth'],
|
|
limit: 10
|
|
});
|
|
|
|
expect(matches.length).toBeGreaterThan(0);
|
|
|
|
// Verify cross-project reuse
|
|
const authPattern = matches.find(m => m.pattern.tags.includes('auth'));
|
|
expect(authPattern).toBeDefined();
|
|
expect(authPattern!.pattern.metadata.project).toBe('project-1');
|
|
|
|
// Update metrics for reuse
|
|
await reasoningBank.updateMetrics(authPattern!.pattern.id, true, 0.93);
|
|
|
|
const updatedPattern = await reasoningBank.getPattern(authPattern!.pattern.id);
|
|
expect(updatedPattern!.metrics.usageCount).toBe(1);
|
|
}, 20000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Workflow 2: Continuous Improvement Loop
|
|
// ===========================================================================
|
|
|
|
describe('Workflow 2: Continuous Improvement Loop (20% Target)', () => {
|
|
it('should achieve 20% improvement over multiple cycles', async () => {
|
|
const targetImprovement = 0.20; // 20%
|
|
const maxCycles = 10;
|
|
const cycles: Array<{ cycle: number; improvement: number; quality: number }> = [];
|
|
|
|
// Set baseline performance
|
|
await performanceTracker.recordBaseline({
|
|
quality: 0.75,
|
|
coverage: 0.80,
|
|
executionTime: 150
|
|
});
|
|
|
|
// Run improvement cycles
|
|
for (let cycle = 0; cycle < maxCycles; cycle++) {
|
|
// Simulate improving performance each cycle
|
|
const improvementFactor = cycle / maxCycles;
|
|
const currentQuality = 0.75 + (0.25 * improvementFactor); // Up to 100%
|
|
|
|
// Record outcomes
|
|
for (let i = 0; i < 5; i++) {
|
|
await learningEngine.recordOutcome({
|
|
id: `improvement-${cycle}-${i}`,
|
|
timestamp: new Date(),
|
|
testId: `test-${cycle}-${i}`,
|
|
testName: `Test Cycle ${cycle} #${i}`,
|
|
outcome: 'success',
|
|
executionTime: Math.max(50, 150 - cycle * 10),
|
|
coverage: Math.min(0.95, 0.80 + cycle * 0.015),
|
|
edgeCasesCaught: 5 + cycle,
|
|
feedback: {
|
|
quality: currentQuality,
|
|
relevance: 0.9
|
|
},
|
|
metadata: {
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
complexity: 3,
|
|
linesOfCode: 150
|
|
}
|
|
});
|
|
}
|
|
|
|
// Run improvement cycle
|
|
const cycleResult = await improvementLoop.runImprovementCycle();
|
|
|
|
cycles.push({
|
|
cycle: cycle + 1,
|
|
improvement: cycleResult.improvementRate,
|
|
quality: cycleResult.currentQuality
|
|
});
|
|
|
|
// Check if target reached
|
|
const status = await performanceTracker.checkImprovementTarget(targetImprovement);
|
|
if (status.targetReached) {
|
|
console.log(`\n✓ Target reached at cycle ${cycle + 1}`);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Print improvement progression
|
|
console.log('\n━━━ Continuous Improvement Progression ━━━');
|
|
console.log('Cycle | Improvement | Quality');
|
|
console.log('------|-------------|--------');
|
|
cycles.forEach(c => {
|
|
console.log(` ${c.cycle.toString().padStart(2)} | ${(c.improvement * 100).toFixed(1).padStart(5)}% | ${(c.quality * 100).toFixed(1).padStart(5)}%`);
|
|
});
|
|
|
|
const finalStatus = await performanceTracker.checkImprovementTarget(targetImprovement);
|
|
|
|
expect(finalStatus.targetReached).toBe(true);
|
|
expect(finalStatus.improvementRate).toBeGreaterThanOrEqual(targetImprovement);
|
|
expect(cycles.length).toBeLessThanOrEqual(maxCycles);
|
|
}, 40000);
|
|
|
|
it('should store and retrieve improvement insights via memory', async () => {
|
|
// Run a few improvement cycles
|
|
for (let i = 0; i < 5; i++) {
|
|
await learningEngine.recordOutcome({
|
|
id: `insight-${i}`,
|
|
timestamp: new Date(),
|
|
testId: `test-${i}`,
|
|
testName: `Test ${i}`,
|
|
outcome: 'success',
|
|
executionTime: 100 - i * 5,
|
|
coverage: 0.80 + i * 0.03,
|
|
edgeCasesCaught: 5 + i,
|
|
feedback: { quality: 0.80 + i * 0.04, relevance: 0.9 },
|
|
metadata: {
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
complexity: 2,
|
|
linesOfCode: 100
|
|
}
|
|
});
|
|
}
|
|
|
|
const insights = await learningEngine.analyzeTrends();
|
|
|
|
// Store insights in memory
|
|
await memoryManager.store('aqe/improvement/insights', {
|
|
timestamp: new Date(),
|
|
insights,
|
|
trends: insights.trends,
|
|
recommendations: insights.recommendations
|
|
}, { partition: 'coordination' });
|
|
|
|
// Retrieve insights
|
|
const storedInsights = await memoryManager.retrieve('aqe/improvement/insights', {
|
|
partition: 'coordination'
|
|
});
|
|
|
|
expect(storedInsights).toBeDefined();
|
|
expect(storedInsights.insights).toBeDefined();
|
|
expect(storedInsights.trends).toBeDefined();
|
|
}, 20000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Workflow 3: ML Flaky Detection → Fix → Validation
|
|
// ===========================================================================
|
|
|
|
describe('Workflow 3: ML Flaky Detection → Fix → Validation', () => {
|
|
it('should complete flaky test remediation workflow', async () => {
|
|
const workflow = {
|
|
steps: [] as Array<{ step: string; duration: number; result: any }>
|
|
};
|
|
|
|
// Step 1: Detect flaky tests using ML
|
|
let stepStart = performance.now();
|
|
|
|
const testHistory = Array.from({ length: 20 }, (_, i) => ({
|
|
name: 'api.test.ts:fetchUser',
|
|
passed: i % 4 !== 0, // 75% pass rate (flaky)
|
|
duration: i % 4 === 0 ? 5200 : 150,
|
|
timestamp: Date.now() - (20 - i) * 60000,
|
|
error: i % 4 === 0 ? 'Request timeout' : undefined
|
|
}));
|
|
|
|
const flakyTests = await flakyDetector.detectFlakyTests(testHistory);
|
|
|
|
workflow.steps.push({
|
|
step: 'ml-detection',
|
|
duration: performance.now() - stepStart,
|
|
result: {
|
|
detected: flakyTests.length,
|
|
accuracy: flakyTests.length > 0 ? 1.0 : 0,
|
|
falsePositiveRate: 0.0
|
|
}
|
|
});
|
|
|
|
expect(flakyTests.length).toBeGreaterThan(0);
|
|
expect(flakyTests[0].confidence).toBeGreaterThan(0.9);
|
|
|
|
// Step 2: Analyze root cause with ML features
|
|
stepStart = performance.now();
|
|
|
|
const flakyTest = flakyTests[0];
|
|
const rootCause = flakyTest.recommendation;
|
|
|
|
workflow.steps.push({
|
|
step: 'root-cause-analysis',
|
|
duration: performance.now() - stepStart,
|
|
result: {
|
|
pattern: flakyTest.failurePattern,
|
|
confidence: flakyTest.confidence,
|
|
recommendation: rootCause.recommendation
|
|
}
|
|
});
|
|
|
|
expect(flakyTest.failurePattern).toBeDefined();
|
|
expect(rootCause.recommendation).toBeDefined();
|
|
|
|
// Step 3: Apply recommended fix
|
|
stepStart = performance.now();
|
|
|
|
const fixApplied = {
|
|
testName: flakyTest.name,
|
|
fix: rootCause.recommendation,
|
|
codeExample: rootCause.codeExample || 'await waitFor(() => condition, { timeout: 5000 });',
|
|
applied: true
|
|
};
|
|
|
|
workflow.steps.push({
|
|
step: 'fix-application',
|
|
duration: performance.now() - stepStart,
|
|
result: fixApplied
|
|
});
|
|
|
|
// Step 4: Validate fix effectiveness
|
|
stepStart = performance.now();
|
|
|
|
// Simulate test runs after fix (should be stable now)
|
|
const postFixHistory = Array.from({ length: 20 }, (_, i) => ({
|
|
name: 'api.test.ts:fetchUser',
|
|
passed: true, // All passing after fix
|
|
duration: 160,
|
|
timestamp: Date.now() + i * 60000
|
|
}));
|
|
|
|
const postFixFlaky = await flakyDetector.detectFlakyTests(postFixHistory);
|
|
|
|
workflow.steps.push({
|
|
step: 'fix-validation',
|
|
duration: performance.now() - stepStart,
|
|
result: {
|
|
flakyTestsAfterFix: postFixFlaky.length,
|
|
fixEffective: postFixFlaky.length === 0,
|
|
newPassRate: 1.0
|
|
}
|
|
});
|
|
|
|
expect(postFixFlaky.length).toBe(0); // No more flaky tests
|
|
|
|
// Step 5: Store fix pattern in ReasoningBank for future reuse
|
|
stepStart = performance.now();
|
|
|
|
const fixPatternId = await reasoningBank.storePattern({
|
|
id: `fix-pattern-${Date.now()}`,
|
|
name: 'Timeout Fix Pattern',
|
|
category: 'stabilization',
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
description: 'Pattern for fixing timeout-related flaky tests',
|
|
template: fixApplied.codeExample,
|
|
applicability: {
|
|
complexity: 'medium',
|
|
context: ['timeout', 'async', 'network'],
|
|
constraints: []
|
|
},
|
|
metrics: {
|
|
successRate: 1.0, // Fix was successful
|
|
usageCount: 1,
|
|
averageQuality: 1.0,
|
|
lastUsed: new Date()
|
|
},
|
|
tags: ['flaky-fix', 'timeout', 'stabilization'],
|
|
metadata: {
|
|
originalIssue: flakyTest.failurePattern,
|
|
fixEffectiveness: 1.0
|
|
}
|
|
});
|
|
|
|
workflow.steps.push({
|
|
step: 'pattern-storage',
|
|
duration: performance.now() - stepStart,
|
|
result: { patternId: fixPatternId }
|
|
});
|
|
|
|
// Print workflow results
|
|
console.log('\n━━━ Flaky Test Remediation Workflow ━━━');
|
|
workflow.steps.forEach(s => {
|
|
console.log(`${s.step}:`);
|
|
console.log(` Duration: ${s.duration.toFixed(2)}ms`);
|
|
console.log(` Result:`, JSON.stringify(s.result, null, 2));
|
|
});
|
|
|
|
// Verify workflow success
|
|
expect(workflow.steps.every(s => s.result)).toBeDefined();
|
|
expect(workflow.steps[workflow.steps.length - 1].result.patternId).toBeDefined();
|
|
}, 30000);
|
|
|
|
it('should share flaky fix patterns across projects', async () => {
|
|
// Project A: Detect and fix flaky test, store pattern
|
|
const flakyTestA = {
|
|
name: 'payment.test.ts:processPayment',
|
|
failurePattern: 'timing' as const,
|
|
recommendation: {
|
|
recommendation: 'Add explicit wait for payment processing',
|
|
codeExample: 'await waitFor(() => payment.status === "completed", { timeout: 5000 });'
|
|
}
|
|
};
|
|
|
|
const patternAId = await reasoningBank.storePattern({
|
|
id: `fix-pattern-project-a`,
|
|
name: 'Payment Timeout Fix',
|
|
category: 'stabilization',
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
description: 'Fix for payment processing timeout',
|
|
template: flakyTestA.recommendation.codeExample,
|
|
applicability: {
|
|
complexity: 'medium',
|
|
context: ['payment', 'async', 'timeout'],
|
|
constraints: []
|
|
},
|
|
metrics: {
|
|
successRate: 1.0,
|
|
usageCount: 1,
|
|
averageQuality: 1.0,
|
|
lastUsed: new Date()
|
|
},
|
|
tags: ['flaky-fix', 'payment', 'timeout'],
|
|
metadata: { project: 'project-a' }
|
|
});
|
|
|
|
// Project B: Find and reuse fix pattern
|
|
const matches = await reasoningBank.findMatchingPatterns({
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
tags: ['flaky-fix', 'timeout'],
|
|
limit: 10
|
|
});
|
|
|
|
expect(matches.length).toBeGreaterThan(0);
|
|
|
|
const paymentFix = matches.find(m => m.pattern.tags.includes('payment'));
|
|
expect(paymentFix).toBeDefined();
|
|
expect(paymentFix!.pattern.id).toBe(patternAId);
|
|
|
|
// Apply pattern in Project B
|
|
await reasoningBank.updateMetrics(patternAId, true, 1.0);
|
|
|
|
const updatedPattern = await reasoningBank.getPattern(patternAId);
|
|
expect(updatedPattern!.metrics.usageCount).toBe(2); // Used in both projects
|
|
}, 20000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Performance Validation
|
|
// ===========================================================================
|
|
|
|
describe('Workflow Performance Validation', () => {
|
|
it('should complete workflows within performance targets', async () => {
|
|
const workflows = [
|
|
{
|
|
name: 'Pattern Extraction + Storage',
|
|
target: 2000, // <2s
|
|
execute: async () => {
|
|
const patterns = await patternExtractor.extractPatterns(`
|
|
describe('Test', () => {
|
|
it('works', () => { expect(true).toBe(true); });
|
|
});
|
|
`, { framework: 'jest', language: 'typescript' });
|
|
|
|
for (const pattern of patterns) {
|
|
await reasoningBank.storePattern({
|
|
id: `perf-${Date.now()}`,
|
|
name: pattern.name,
|
|
category: pattern.category,
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
description: pattern.description,
|
|
template: pattern.template || '',
|
|
applicability: { complexity: 'low', context: [], constraints: [] },
|
|
metrics: { successRate: 0.85, usageCount: 0, averageQuality: 0, lastUsed: new Date() },
|
|
tags: [],
|
|
metadata: {}
|
|
});
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'Learning Record + Analysis',
|
|
target: 1000, // <1s
|
|
execute: async () => {
|
|
for (let i = 0; i < 10; i++) {
|
|
await learningEngine.recordOutcome({
|
|
id: `perf-${i}`,
|
|
timestamp: new Date(),
|
|
testId: `test-${i}`,
|
|
testName: `Test ${i}`,
|
|
outcome: 'success',
|
|
executionTime: 100,
|
|
coverage: 0.85,
|
|
edgeCasesCaught: 6,
|
|
feedback: { quality: 0.85, relevance: 0.9 },
|
|
metadata: {
|
|
framework: 'jest',
|
|
language: 'typescript',
|
|
complexity: 2,
|
|
linesOfCode: 100
|
|
}
|
|
});
|
|
}
|
|
|
|
await learningEngine.analyzeTrends();
|
|
}
|
|
}
|
|
];
|
|
|
|
console.log('\n━━━ Workflow Performance Metrics ━━━');
|
|
|
|
for (const workflow of workflows) {
|
|
const start = performance.now();
|
|
await workflow.execute();
|
|
const elapsed = performance.now() - start;
|
|
|
|
console.log(`${workflow.name}: ${elapsed.toFixed(2)}ms (target: <${workflow.target}ms)`);
|
|
expect(elapsed).toBeLessThan(workflow.target);
|
|
}
|
|
}, 30000);
|
|
});
|
|
});
|