#!/usr/bin/env node /** * Runs `npm test` in every submodule under `nodes/` and prints a * summary table. Exits non-zero if any submodule's test run failed. * * Usage: node scripts/test-platform.js * (or `npm run test:platform` from the EVOLV root) */ 'use strict'; const { spawnSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const ROOT = path.resolve(__dirname, '..'); const NODES_DIR = path.join(ROOT, 'nodes'); const TIMEOUT_MS = 300_000; // 5 minutes per node (mathjs-heavy ones can take ~13s/file) function listSubmodules() { return fs.readdirSync(NODES_DIR) .filter((d) => fs.existsSync(path.join(NODES_DIR, d, 'package.json'))) .sort(); } function pad(s, w) { s = String(s); return s + ' '.repeat(Math.max(0, w - s.length)); } function runOne(name) { const dir = path.join(NODES_DIR, name); const t0 = Date.now(); const r = spawnSync('npm', ['test', '--silent'], { cwd: dir, encoding: 'utf8', timeout: TIMEOUT_MS, env: { ...process.env, FORCE_COLOR: '0' }, }); const out = (r.stdout || '') + (r.stderr || ''); const pass = Number((out.match(/^# pass (\d+)/m) || [])[1] || 0); const fail = Number((out.match(/^# fail (\d+)/m) || [])[1] || 0); const tests = Number((out.match(/^# tests (\d+)/m) || [])[1] || 0); const durSec = ((Date.now() - t0) / 1000).toFixed(1); const ok = r.status === 0 && fail === 0; return { name, pass, fail, tests, durSec, ok, output: out }; } function main() { const nodes = listSubmodules(); console.log(`Running tests across ${nodes.length} submodules...\n`); const results = []; for (const node of nodes) { process.stdout.write(` ${pad(node, 22)}`); const r = runOne(node); results.push(r); const mark = r.ok ? '✓' : '✗'; process.stdout.write(`${mark} ${pad(`${r.pass} pass / ${r.fail} fail`, 22)} ${r.durSec}s\n`); } console.log('\n--- Summary ---'); const totalPass = results.reduce((s, r) => s + r.pass, 0); const totalFail = results.reduce((s, r) => s + r.fail, 0); const totalDur = results.reduce((s, r) => s + Number(r.durSec), 0).toFixed(1); const allOk = results.every((r) => r.ok); console.log(` ${totalPass} pass / ${totalFail} fail across ${results.length} submodules in ${totalDur}s`); if (!allOk) { console.log('\n--- Failures ---'); for (const r of results.filter((r) => !r.ok)) { console.log(`\n[${r.name}]`); const failingLines = r.output.split('\n').filter((l) => /^not ok|AssertionError|Error:/.test(l) ).slice(0, 10); failingLines.forEach((l) => console.log(` ${l}`)); } } process.exit(allOk ? 0 : 1); } main();