run-feature-tests.ts
1 /** 2 * Feature Parity Integration Test Runner 3 * 4 * Runs all integration tests for the new TypeScript features. 5 * Tests include real API calls when OPENAI_API_KEY is available. 6 * 7 * Run: npx ts-node run-feature-tests.ts 8 */ 9 10 import { execSync, spawn } from 'child_process'; 11 import * as path from 'path'; 12 import * as fs from 'fs'; 13 14 interface TestResult { 15 name: string; 16 passed: boolean; 17 duration: number; 18 output: string; 19 error?: string; 20 } 21 22 const TEST_FILES = [ 23 // Workflow patterns 24 'workflows/loop-pattern.ts', 25 'workflows/repeat-pattern.ts', 26 // Agents 27 'agents/audio-agent.ts', 28 // Knowledge 29 'knowledge/chonkie-adapter.ts', 30 // MCP 31 'mcp/mcp-client-test.ts', 32 ]; 33 34 async function runTest(testFile: string): Promise<TestResult> { 35 const startTime = Date.now(); 36 const fullPath = path.join(__dirname, testFile); 37 const name = path.basename(testFile, '.ts'); 38 39 return new Promise((resolve) => { 40 const proc = spawn('npx', ['ts-node', fullPath], { 41 cwd: __dirname, 42 env: { ...process.env }, 43 stdio: ['pipe', 'pipe', 'pipe'] 44 }); 45 46 let stdout = ''; 47 let stderr = ''; 48 49 proc.stdout.on('data', (data) => { 50 stdout += data.toString(); 51 }); 52 53 proc.stderr.on('data', (data) => { 54 stderr += data.toString(); 55 }); 56 57 proc.on('close', (code) => { 58 const duration = Date.now() - startTime; 59 resolve({ 60 name, 61 passed: code === 0, 62 duration, 63 output: stdout, 64 error: stderr || undefined 65 }); 66 }); 67 68 proc.on('error', (error) => { 69 const duration = Date.now() - startTime; 70 resolve({ 71 name, 72 passed: false, 73 duration, 74 output: '', 75 error: error.message 76 }); 77 }); 78 79 // Timeout after 60 seconds 80 setTimeout(() => { 81 proc.kill(); 82 resolve({ 83 name, 84 passed: false, 85 duration: 60000, 86 output: stdout, 87 error: 'Test timed out after 60 seconds' 88 }); 89 }, 60000); 90 }); 91 } 92 93 async function main() { 94 console.log('╔════════════════════════════════════════════════════════════╗'); 95 console.log('║ PraisonAI TypeScript Feature Parity Integration Tests ║'); 96 console.log('╚════════════════════════════════════════════════════════════╝\n'); 97 98 // Environment info 99 console.log('Environment:'); 100 console.log(` OPENAI_API_KEY: ${process.env.OPENAI_API_KEY ? '✅ Set' : '❌ Not set'}`); 101 console.log(` MCP_SERVER_URL: ${process.env.MCP_SERVER_URL ? '✅ Set' : '❌ Not set'}`); 102 console.log(` Node version: ${process.version}`); 103 console.log(''); 104 105 // Check if test files exist 106 console.log('Test Files:'); 107 for (const file of TEST_FILES) { 108 const fullPath = path.join(__dirname, file); 109 const exists = fs.existsSync(fullPath); 110 console.log(` ${exists ? '✅' : '❌'} ${file}`); 111 } 112 console.log(''); 113 114 // Run tests 115 console.log('Running Tests...\n'); 116 console.log('─'.repeat(60)); 117 118 const results: TestResult[] = []; 119 for (const testFile of TEST_FILES) { 120 const fullPath = path.join(__dirname, testFile); 121 if (!fs.existsSync(fullPath)) { 122 results.push({ 123 name: path.basename(testFile, '.ts'), 124 passed: false, 125 duration: 0, 126 output: '', 127 error: 'File not found' 128 }); 129 continue; 130 } 131 132 console.log(`\n▶ Running: ${testFile}`); 133 const result = await runTest(testFile); 134 results.push(result); 135 136 if (result.passed) { 137 console.log(` ✅ PASSED (${result.duration}ms)`); 138 } else { 139 console.log(` ❌ FAILED (${result.duration}ms)`); 140 if (result.error) { 141 console.log(` Error: ${result.error.slice(0, 200)}...`); 142 } 143 } 144 } 145 146 console.log('\n' + '─'.repeat(60)); 147 148 // Summary 149 const passed = results.filter(r => r.passed).length; 150 const failed = results.filter(r => !r.passed).length; 151 const totalDuration = results.reduce((sum, r) => sum + r.duration, 0); 152 153 console.log('\n╔════════════════════════════════════════════════════════════╗'); 154 console.log('║ TEST SUMMARY ║'); 155 console.log('╚════════════════════════════════════════════════════════════╝'); 156 console.log(` Total Tests: ${results.length}`); 157 console.log(` Passed: ${passed} ✅`); 158 console.log(` Failed: ${failed} ${failed > 0 ? '❌' : ''}`); 159 console.log(` Duration: ${(totalDuration / 1000).toFixed(2)}s`); 160 console.log(''); 161 162 // Detailed results 163 if (failed > 0) { 164 console.log('Failed Tests:'); 165 for (const result of results.filter(r => !r.passed)) { 166 console.log(` ❌ ${result.name}`); 167 if (result.error) { 168 console.log(` ${result.error.slice(0, 100)}`); 169 } 170 } 171 console.log(''); 172 } 173 174 // Exit with appropriate code 175 process.exit(failed > 0 ? 1 : 0); 176 } 177 178 main().catch((error) => { 179 console.error('Test runner failed:', error); 180 process.exit(1); 181 });