/ examples / js / run-feature-tests.ts
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  });