mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
c3b342a03a
## Summary Successfully fixed all initialization issues and completed Phase 2 integration: - Fixed agent template discovery and copying (18 agents now copy correctly) - Added comprehensive logging throughout init process - Fixed undefined config property serialization bug - All databases initialize correctly (memory.db, patterns.db) - Phase 2 features (learning, patterns, improvement) fully functional ## Bug Fixes 1. **Agent Copy Bug**: Changed from directory copy to individual file copy - Fixed: "Copied 0 agent definitions" → Now copies all 18 agents - Issue: fs.copy with filter wasn't working, changed to per-file copy 2. **Missing Agent**: Created qe-quality-analyzer.md - Was the only missing agent out of 17 required QE agents - Added complete agent definition with AQE hooks integration 3. **Incomplete Fallback**: Updated fallback from 6 to all 17 agents - Ensures all agents are created even if templates not found - Maintains feature parity in all scenarios 4. **Serialization Bug**: Added sanitizeConfig() helper - Fixed: "Cannot read properties of undefined (reading 'replace')" - Issue: jsonfile couldn't serialize config with undefined properties - Solution: Recursive sanitization removes undefined values before write 5. **Config Path Bug**: Fixed target vs source file list confusion - Was passing source files to createMissingAgents instead of target - Now correctly identifies which agents are missing in target ## Improvements - Added detailed path discovery logging with ✓/✗ checkmarks - Show agent template counts and copy progress - Log each config file write with file paths - Added stack traces to all error handlers (removed verbose-only check) - Created sanitizeConfig for robust JSON serialization ## Testing Verified in test project `/tmp/aqe-test-final`: ✅ All 17 QE agents created ✅ memory.db created (221KB, 12 tables) ✅ patterns.db created (155KB, 4 tables + FTS) ✅ All Phase 2 configs written successfully ✅ Complete initialization with no errors ## Phase 2 Features Confirmed Working - Learning System: Q-learning (lr=0.1, γ=0.95, 20% target) - Pattern Bank: 85% confidence, extraction enabled - Improvement Loop: 1hr cycles, A/B testing, manual approval ## Files Changed - .claude/agents/qe-quality-analyzer.md (NEW) - src/cli/commands/init.ts (MAJOR FIXES) - copyAgentTemplates(): Individual file copy, better logging - createBasicAgents(): All 17 agents - createMissingAgents(): Fixed file list bug - writeFleetConfig(): Added sanitization - sanitizeConfig(): NEW helper for undefined removal - src/learning/* (NEW - 9 files) - src/reasoning/* (NEW - 8 files) - tests/* (NEW - 30+ test files) - docs/* (NEW - 60+ documentation files) ## Breaking Changes None - all changes are internal improvements ## Migration No migration needed - initialization now works correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
311 lines
11 KiB
TypeScript
311 lines
11 KiB
TypeScript
/**
|
|
* Phase 2 CLI Integration Tests
|
|
*
|
|
* Tests that Phase 2 CLI commands work correctly:
|
|
* - aqe learn commands (status, enable, disable, train)
|
|
* - aqe patterns commands (list, extract, find, stats)
|
|
* - aqe improve commands (status, analyze, optimize)
|
|
*
|
|
* @module tests/integration/phase2/phase2-cli-integration
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
import { exec } from 'child_process';
|
|
import { promisify } from 'util';
|
|
import * as fs from 'fs-extra';
|
|
import * as path from 'path';
|
|
|
|
const execAsync = promisify(exec);
|
|
const TEST_OUTPUT_DIR = path.join(__dirname, '../../.tmp/cli-test-output');
|
|
|
|
// Helper to execute CLI commands
|
|
async function execCommand(cmd: string): Promise<{ stdout: string; stderr: string }> {
|
|
try {
|
|
return await execAsync(cmd, {
|
|
cwd: path.join(__dirname, '../../..'),
|
|
env: { ...process.env, NODE_ENV: 'test' }
|
|
});
|
|
} catch (error: any) {
|
|
return { stdout: error.stdout || '', stderr: error.stderr || error.message };
|
|
}
|
|
}
|
|
|
|
describe('Phase 2 CLI Integration Tests', () => {
|
|
beforeEach(async () => {
|
|
await fs.ensureDir(TEST_OUTPUT_DIR);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
// Clean up test output
|
|
await fs.remove(TEST_OUTPUT_DIR);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// aqe learn commands
|
|
// ===========================================================================
|
|
|
|
describe('aqe learn commands', () => {
|
|
it('should show learning status', async () => {
|
|
const { stdout, stderr } = await execCommand('npm run dev -- learn status');
|
|
|
|
expect(stderr).toBe('');
|
|
expect(stdout).toContain('Learning Engine Status');
|
|
expect(stdout).toContain('Experiences:');
|
|
expect(stdout).toContain('Average Quality:');
|
|
}, 15000);
|
|
|
|
it('should enable learning for specific agents', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- learn enable --agent test-generator');
|
|
|
|
expect(stdout).toContain('Learning enabled');
|
|
expect(stdout).toContain('test-generator');
|
|
}, 10000);
|
|
|
|
it('should enable learning for all agents', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- learn enable --all');
|
|
|
|
expect(stdout).toContain('Learning enabled');
|
|
expect(stdout).toMatch(/all\s+agents/i);
|
|
}, 10000);
|
|
|
|
it('should disable learning', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- learn disable --agent coverage-analyzer');
|
|
|
|
expect(stdout).toContain('Learning disabled');
|
|
}, 10000);
|
|
|
|
it('should train learning engine with historical data', async () => {
|
|
// Create mock historical data file
|
|
const historyFile = path.join(TEST_OUTPUT_DIR, 'test-history.json');
|
|
await fs.writeJSON(historyFile, {
|
|
tests: [
|
|
{ id: 'test-1', outcome: 'success', quality: 0.9, coverage: 0.85 },
|
|
{ id: 'test-2', outcome: 'success', quality: 0.88, coverage: 0.82 }
|
|
]
|
|
});
|
|
|
|
const { stdout } = await execCommand(`npm run dev -- learn train --file ${historyFile}`);
|
|
|
|
expect(stdout).toContain('Training completed');
|
|
expect(stdout).toMatch(/experiences?\s+recorded/i);
|
|
}, 15000);
|
|
|
|
it('should display learning insights', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- learn insights --days 30');
|
|
|
|
expect(stdout).toContain('Learning Insights');
|
|
expect(stdout).toMatch(/trends|recommendations|quality/i);
|
|
}, 10000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// aqe patterns commands
|
|
// ===========================================================================
|
|
|
|
describe('aqe patterns commands', () => {
|
|
it('should list available patterns', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- patterns list');
|
|
|
|
expect(stdout).toContain('Test Patterns');
|
|
expect(stdout).toMatch(/total|count|patterns/i);
|
|
}, 10000);
|
|
|
|
it('should list patterns filtered by framework', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- patterns list --framework jest');
|
|
|
|
expect(stdout).toContain('jest');
|
|
expect(stdout).toMatch(/patterns?/i);
|
|
}, 10000);
|
|
|
|
it('should extract patterns from test files', async () => {
|
|
// Create mock test file
|
|
const testFile = path.join(TEST_OUTPUT_DIR, 'sample.test.ts');
|
|
await fs.writeFile(testFile, `
|
|
describe('SampleService', () => {
|
|
it('should create entity', () => {
|
|
const service = new SampleService();
|
|
const result = service.create({ name: 'Test' });
|
|
expect(result.id).toBeDefined();
|
|
});
|
|
});
|
|
`);
|
|
|
|
const { stdout } = await execCommand(`npm run dev -- patterns extract ${TEST_OUTPUT_DIR}`);
|
|
|
|
expect(stdout).toContain('patterns extracted');
|
|
expect(stdout).toMatch(/\d+\s+patterns?/i);
|
|
}, 15000);
|
|
|
|
it('should find matching patterns by query', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- patterns find --query "user create" --framework jest');
|
|
|
|
expect(stdout).toMatch(/patterns?|matches?/i);
|
|
}, 10000);
|
|
|
|
it('should show pattern statistics', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- patterns stats');
|
|
|
|
expect(stdout).toContain('Pattern Statistics');
|
|
expect(stdout).toMatch(/total|usage|success rate/i);
|
|
}, 10000);
|
|
|
|
it('should export patterns to file', async () => {
|
|
const exportFile = path.join(TEST_OUTPUT_DIR, 'patterns.json');
|
|
const { stdout } = await execCommand(`npm run dev -- patterns export --output ${exportFile}`);
|
|
|
|
expect(stdout).toContain('exported');
|
|
expect(await fs.pathExists(exportFile)).toBe(true);
|
|
|
|
const exported = await fs.readJSON(exportFile);
|
|
expect(exported.patterns).toBeDefined();
|
|
}, 15000);
|
|
|
|
it('should import patterns from file', async () => {
|
|
// Create mock patterns file
|
|
const importFile = path.join(TEST_OUTPUT_DIR, 'import-patterns.json');
|
|
await fs.writeJSON(importFile, {
|
|
patterns: [
|
|
{
|
|
id: 'pattern-1',
|
|
name: 'CRUD Test Pattern',
|
|
category: 'integration',
|
|
framework: 'jest',
|
|
template: 'describe("CRUD", () => { ... });'
|
|
}
|
|
]
|
|
});
|
|
|
|
const { stdout } = await execCommand(`npm run dev -- patterns import --file ${importFile}`);
|
|
|
|
expect(stdout).toContain('imported');
|
|
expect(stdout).toMatch(/\d+\s+patterns?/i);
|
|
}, 15000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// aqe improve commands
|
|
// ===========================================================================
|
|
|
|
describe('aqe improve commands', () => {
|
|
it('should show improvement loop status', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- improve status');
|
|
|
|
expect(stdout).toContain('Improvement Loop Status');
|
|
expect(stdout).toMatch(/baseline|current|target/i);
|
|
}, 10000);
|
|
|
|
it('should analyze improvement opportunities', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- improve analyze --agent coverage-analyzer');
|
|
|
|
expect(stdout).toContain('Improvement Analysis');
|
|
expect(stdout).toMatch(/opportunities|recommendations/i);
|
|
}, 15000);
|
|
|
|
it('should run improvement cycle', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- improve cycle --iterations 3');
|
|
|
|
expect(stdout).toContain('Improvement Cycle');
|
|
expect(stdout).toMatch(/iteration|improvement|baseline/i);
|
|
}, 20000);
|
|
|
|
it('should set improvement target', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- improve target --value 0.25 --agent test-generator');
|
|
|
|
expect(stdout).toContain('Target set');
|
|
expect(stdout).toContain('25%');
|
|
}, 10000);
|
|
|
|
it('should validate improvement target achievement', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- improve validate --agent coverage-analyzer');
|
|
|
|
expect(stdout).toMatch(/target\s+(reached|not\s+reached)/i);
|
|
expect(stdout).toMatch(/improvement\s+rate/i);
|
|
}, 10000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Integration with other commands
|
|
// ===========================================================================
|
|
|
|
describe('Command Integration', () => {
|
|
it('should chain pattern extraction → learning → improvement', async () => {
|
|
// Step 1: Extract patterns
|
|
const testDir = path.join(TEST_OUTPUT_DIR, 'tests');
|
|
await fs.ensureDir(testDir);
|
|
await fs.writeFile(path.join(testDir, 'test.ts'), `
|
|
describe('Test', () => {
|
|
it('works', () => { expect(true).toBe(true); });
|
|
});
|
|
`);
|
|
|
|
const { stdout: extractOut } = await execCommand(`npm run dev -- patterns extract ${testDir}`);
|
|
expect(extractOut).toContain('extracted');
|
|
|
|
// Step 2: Enable learning
|
|
const { stdout: learnOut } = await execCommand('npm run dev -- learn enable --all');
|
|
expect(learnOut).toContain('enabled');
|
|
|
|
// Step 3: Check improvement status
|
|
const { stdout: improveOut } = await execCommand('npm run dev -- improve status');
|
|
expect(improveOut).toContain('Status');
|
|
}, 30000);
|
|
|
|
it('should display comprehensive system status', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- status --verbose');
|
|
|
|
expect(stdout).toContain('System Status');
|
|
expect(stdout).toMatch(/learning|patterns|improvement/i);
|
|
}, 10000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Error Handling
|
|
// ===========================================================================
|
|
|
|
describe('CLI Error Handling', () => {
|
|
it('should handle invalid command gracefully', async () => {
|
|
const { stderr } = await execCommand('npm run dev -- invalid-command');
|
|
|
|
expect(stderr).toMatch(/unknown|invalid|not found/i);
|
|
}, 10000);
|
|
|
|
it('should validate required parameters', async () => {
|
|
const { stderr } = await execCommand('npm run dev -- patterns extract');
|
|
|
|
expect(stderr).toMatch(/required|missing|path/i);
|
|
}, 10000);
|
|
|
|
it('should handle non-existent file paths', async () => {
|
|
const { stderr } = await execCommand('npm run dev -- patterns extract /non/existent/path');
|
|
|
|
expect(stderr).toMatch(/not found|does not exist/i);
|
|
}, 10000);
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Output Format Tests
|
|
// ===========================================================================
|
|
|
|
describe('Output Format', () => {
|
|
it('should support JSON output format', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- learn status --format json');
|
|
|
|
const parsed = JSON.parse(stdout);
|
|
expect(parsed).toBeDefined();
|
|
expect(parsed.status).toBeDefined();
|
|
}, 10000);
|
|
|
|
it('should support table output format', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- patterns list --format table');
|
|
|
|
expect(stdout).toMatch(/\||\u2502|\u2500/); // Table border characters
|
|
}, 10000);
|
|
|
|
it('should support compact output format', async () => {
|
|
const { stdout } = await execCommand('npm run dev -- improve status --format compact');
|
|
|
|
expect(stdout.split('\n').length).toBeLessThan(10); // Concise output
|
|
}, 10000);
|
|
});
|
|
});
|