#!/usr/bin/env node const { execFileSync } = require('child_process'); const { globSync } = require('glob'); const path = require('path'); const fs = require('fs'); const args = process.argv.slice(2); const nodeArgs = ['--import', 'tsx']; const patterns = []; const excludePatterns = []; let perFile = false; const nodeMajor = Number.parseInt(process.versions.node.split('.')[0], 10); const nativeTestArgs = nodeMajor >= 22 ? ['--test-force-exit'] : []; // Derive a unique package name for JUnit XML output function getPackageName() { try { const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8')); return (pkg.name || 'unknown').replace(/[^a-zA-Z0-9-]/g, '_'); } catch { return 'unknown'; } } let i = 0; while (i < args.length) { const arg = args[i]; if (arg === '--') { i += 1; break; } if (arg === '--per-file') { perFile = true; i += 1; continue; } if (arg === '--exclude') { const value = args[i + 1]; if (!value) { console.error('Missing value for --exclude'); process.exit(1); } excludePatterns.push(value); i += 2; continue; } if (arg === '--import') { const value = args[i + 1]; if (!value) { console.error('Missing value for --import'); process.exit(1); } nodeArgs.push(arg, value); i += 2; continue; } nodeArgs.push(arg); i += 1; } patterns.push(...args.slice(i)); if (patterns.length === 0) { console.error('No test patterns provided'); process.exit(1); } const files = [...new Set(patterns.flatMap((pattern) => globSync(pattern)).sort())]; const excluded = new Set(excludePatterns.flatMap((pattern) => globSync(pattern))); const filteredFiles = files.filter((file) => !excluded.has(file)); if (filteredFiles.length === 0) { console.error('No test files found for patterns:', patterns.join(', ')); process.exit(1); } // When CI_JUNIT_DIR is set, add dual reporter: spec to stdout + junit to file const junitArgs = []; if (process.env.CI_JUNIT_DIR) { const junitDir = process.env.CI_JUNIT_DIR; const pkgName = getPackageName(); const junitFile = path.join(junitDir, `${pkgName}.xml`); fs.mkdirSync(junitDir, { recursive: true }); junitArgs.push( '--test-reporter=spec', '--test-reporter-destination=stdout', '--test-reporter=junit', `--test-reporter-destination=${junitFile}` ); } const testRunnerArgs = junitArgs.length > 0 ? junitArgs : []; if (perFile) { for (const file of filteredFiles) { execFileSync(process.execPath, [...nodeArgs, ...testRunnerArgs, ...nativeTestArgs, '--test', file], { cwd: process.cwd(), stdio: 'inherit', }); } } else { execFileSync(process.execPath, [...nodeArgs, ...testRunnerArgs, ...nativeTestArgs, '--test', ...filteredFiles], { cwd: process.cwd(), stdio: 'inherit', }); }