jay-code
Version:
Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability
401 lines (345 loc) • 11.3 kB
JavaScript
/**
* Comprehensive Test Runner for Claude Flow v2.0.0
*/
import { spawn } from 'child_process';
import chalk from 'chalk';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.join(__dirname, '..');
// Test configurations
const testSuites = [
{
name: 'Unit Tests',
command: 'npm',
args: ['run', 'test:unit'],
description: 'Run all unit tests for individual components',
timeout: 120000 // 2 minutes
},
{
name: 'Integration Tests',
command: 'npm',
args: ['run', 'test:integration'],
description: 'Run integration tests for system components',
timeout: 300000 // 5 minutes
},
{
name: 'End-to-End Tests',
command: 'npm',
args: ['run', 'test:e2e'],
description: 'Run end-to-end swarm coordination tests',
timeout: 600000 // 10 minutes
},
{
name: 'Performance Tests',
command: 'npm',
args: ['run', 'test:performance'],
description: 'Run performance benchmark tests',
timeout: 900000 // 15 minutes
},
{
name: 'CLI Tests',
command: 'npm',
args: ['run', 'test:cli'],
description: 'Run CLI command tests',
timeout: 180000 // 3 minutes
}
];
// Load tests (optional)
const loadTests = [
{
name: 'Swarm Load Test',
command: 'node',
args: ['scripts/load-test-swarm.js'],
description: 'Test swarm coordination under heavy load',
timeout: 1200000 // 20 minutes
},
{
name: 'Memory Load Test',
command: 'node',
args: ['scripts/load-test-memory.js'],
description: 'Test memory management under high throughput',
timeout: 600000 // 10 minutes
}
];
// Docker tests (optional)
const dockerTests = [
{
name: 'Docker Build Test',
command: 'docker',
args: ['build', '-t', 'jay-code:test', '.'],
description: 'Test Docker image build',
timeout: 600000 // 10 minutes
},
{
name: 'Docker Container Test',
command: 'docker',
args: ['run', '--rm', 'jay-code:test', 'jay-code', '--version'],
description: 'Test Docker container execution',
timeout: 120000 // 2 minutes
}
];
// NPX tests (optional)
const npxTests = [
{
name: 'NPX Installation Test',
command: 'npm',
args: ['pack'],
description: 'Test NPX package creation',
timeout: 180000 // 3 minutes
}
];
class TestRunner {
constructor(options = {}) {
this.verbose = options.verbose || false;
this.includeLoad = options.load || false;
this.includeDocker = options.docker || false;
this.includeNpx = options.npx || false;
this.parallel = options.parallel || false;
this.results = new Map();
this.startTime = Date.now();
}
log(message, level = 'info') {
const timestamp = new Date().toISOString();
const prefix = `[${timestamp}]`;
switch (level) {
case 'success':
console.log(chalk.green(`${prefix} ✅ ${message}`));
break;
case 'error':
console.log(chalk.red(`${prefix} ❌ ${message}`));
break;
case 'warning':
console.log(chalk.yellow(`${prefix} ⚠️ ${message}`));
break;
case 'info':
default:
console.log(chalk.blue(`${prefix} ℹ️ ${message}`));
break;
}
}
async runTest(test) {
this.log(`Starting: ${test.name} - ${test.description}`);
const startTime = Date.now();
return new Promise((resolve) => {
const child = spawn(test.command, test.args, {
cwd: projectRoot,
stdio: this.verbose ? 'inherit' : 'pipe',
shell: process.platform === 'win32'
});
let stdout = '';
let stderr = '';
if (!this.verbose) {
child.stdout?.on('data', (data) => {
stdout += data.toString();
});
child.stderr?.on('data', (data) => {
stderr += data.toString();
});
}
// Set timeout
const timeoutId = setTimeout(() => {
child.kill('SIGTERM');
const result = {
name: test.name,
success: false,
error: 'Test timed out',
duration: Date.now() - startTime,
stdout: stdout,
stderr: stderr
};
this.results.set(test.name, result);
resolve(result);
}, test.timeout);
child.on('close', (code) => {
clearTimeout(timeoutId);
const duration = Date.now() - startTime;
const result = {
name: test.name,
success: code === 0,
exitCode: code,
duration: duration,
stdout: stdout,
stderr: stderr
};
if (code === 0) {
this.log(`Completed: ${test.name} (${duration}ms)`, 'success');
} else {
this.log(`Failed: ${test.name} (exit code: ${code})`, 'error');
if (!this.verbose && stderr) {
console.log(chalk.red('Error output:'));
console.log(stderr);
}
}
this.results.set(test.name, result);
resolve(result);
});
child.on('error', (error) => {
clearTimeout(timeoutId);
const result = {
name: test.name,
success: false,
error: error.message,
duration: Date.now() - startTime,
stdout: stdout,
stderr: stderr
};
this.log(`Error: ${test.name} - ${error.message}`, 'error');
this.results.set(test.name, result);
resolve(result);
});
});
}
async runTestSuite(tests, suiteName) {
this.log(`\n🏃♂️ Running ${suiteName} (${tests.length} tests)`);
if (this.parallel) {
const results = await Promise.all(tests.map(test => this.runTest(test)));
return results;
} else {
const results = [];
for (const test of tests) {
const result = await this.runTest(test);
results.push(result);
// Short delay between tests
await new Promise(resolve => setTimeout(resolve, 1000));
}
return results;
}
}
generateReport() {
const totalTime = Date.now() - this.startTime;
const results = Array.from(this.results.values());
const passed = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
const total = results.length;
console.log('\n' + '='.repeat(80));
console.log(chalk.bold.blue('📊 CLAUDE FLOW v2.0.0 TEST REPORT'));
console.log('='.repeat(80));
console.log(`\n📈 Summary:`);
console.log(` Total Tests: ${total}`);
console.log(` Passed: ${chalk.green(passed)}`);
console.log(` Failed: ${chalk.red(failed)}`);
console.log(` Success Rate: ${chalk.cyan(((passed / total) * 100).toFixed(1))}%`);
console.log(` Total Time: ${chalk.yellow((totalTime / 1000).toFixed(2))}s`);
if (failed > 0) {
console.log(`\n❌ Failed Tests:`);
results.filter(r => !r.success).forEach(result => {
console.log(` • ${chalk.red(result.name)}: ${result.error || `Exit code ${result.exitCode}`}`);
});
}
console.log(`\n✅ Passed Tests:`);
results.filter(r => r.success).forEach(result => {
console.log(` • ${chalk.green(result.name)}: ${(result.duration / 1000).toFixed(2)}s`);
});
// Performance summary
const performanceResults = results.filter(r => r.name.includes('Performance'));
if (performanceResults.length > 0) {
console.log(`\n⚡ Performance Summary:`);
performanceResults.forEach(result => {
if (result.success) {
console.log(` • ${result.name}: ${chalk.green('PASSED')} (${(result.duration / 1000).toFixed(2)}s)`);
} else {
console.log(` • ${result.name}: ${chalk.red('FAILED')}`);
}
});
}
console.log('\n' + '='.repeat(80));
return {
total,
passed,
failed,
successRate: (passed / total) * 100,
totalTime,
results
};
}
async run() {
this.log('🚀 Starting Claude Flow v2.0.0 Comprehensive Test Suite');
try {
// Core test suites
await this.runTestSuite(testSuites, 'Core Test Suites');
// Optional test suites
if (this.includeLoad) {
await this.runTestSuite(loadTests, 'Load Tests');
}
if (this.includeDocker) {
await this.runTestSuite(dockerTests, 'Docker Tests');
}
if (this.includeNpx) {
await this.runTestSuite(npxTests, 'NPX Tests');
}
} catch (error) {
this.log(`Test runner error: ${error.message}`, 'error');
}
const report = this.generateReport();
// Exit with appropriate code
process.exit(report.failed > 0 ? 1 : 0);
}
}
// CLI handling
function parseArgs() {
const args = process.argv.slice(2);
const options = {
verbose: args.includes('--verbose') || args.includes('-v'),
load: args.includes('--load') || args.includes('-l'),
docker: args.includes('--docker') || args.includes('-d'),
npx: args.includes('--npx') || args.includes('-n'),
parallel: args.includes('--parallel') || args.includes('-p'),
help: args.includes('--help') || args.includes('-h')
};
return options;
}
function showHelp() {
console.log(`
${chalk.bold.blue('Claude Flow v2.0.0 Comprehensive Test Runner')}
${chalk.bold('Usage:')}
node scripts/test-comprehensive.js [options]
${chalk.bold('Options:')}
-v, --verbose Show detailed test output
-l, --load Include load tests
-d, --docker Include Docker tests
-n, --npx Include NPX tests
-p, --parallel Run tests in parallel (faster but less stable)
-h, --help Show this help message
${chalk.bold('Examples:')}
node scripts/test-comprehensive.js # Run core tests
node scripts/test-comprehensive.js --verbose # Run with detailed output
node scripts/test-comprehensive.js --load --docker # Include load and Docker tests
node scripts/test-comprehensive.js --parallel # Run tests in parallel
${chalk.bold('Test Suites:')}
• Unit Tests - Individual component tests
• Integration Tests - System integration tests
• End-to-End Tests - Complete workflow tests
• Performance Tests - Benchmark and load tests
• CLI Tests - Command-line interface tests
• Load Tests - Heavy load and stress tests (optional)
• Docker Tests - Container and deployment tests (optional)
• NPX Tests - Package distribution tests (optional)
`);
}
// Main execution
async function main() {
const options = parseArgs();
if (options.help) {
showHelp();
process.exit(0);
}
const runner = new TestRunner(options);
await runner.run();
}
// Handle uncaught errors
process.on('uncaughtException', (error) => {
console.error(chalk.red('Uncaught Exception:'), error);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error(chalk.red('Unhandled Rejection at:'), promise, chalk.red('reason:'), reason);
process.exit(1);
});
// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}
export default TestRunner;