P10.7: top-level test:platform runner + bump submodule pointers

scripts/test-platform.js iterates each submodule, runs npm test, shows
a per-node pass/fail summary, exits non-zero if any node fails.

Wired as `npm run test:platform` in the parent package.json.

Submodule pointer bumps:
  dashboardAPI     2874608 → 92d7eba  (Mocha → node:test conversion for edge+integration)
  diffuser         0ec9dd1 → 15cfb22  (P10.7a test script fix)
  generalFunctions 8ebf31d → 95c5e68  (P10.7a test script fix + remove 5 broken Mocha dupes)
  pumpingStation   52d3889 → d2384b1  (P10.7a test script fix)

Current platform-wide gate: 729 pass / 5 fail across 12 submodules
(5 failures are all pre-existing AssertionErrors logged in
OPEN_QUESTIONS.md for Phase 10.5).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
znetsixe
2026-05-11 14:45:06 +02:00
parent e03a7a51b7
commit 3b7acdaa88
6 changed files with 81 additions and 4 deletions

View File

@@ -44,6 +44,7 @@
"test:node": "node --test nodes/valve/test/basic/*.test.js nodes/valve/test/edge/*.test.js nodes/valve/test/integration/*.test.js nodes/valveGroupControl/test/basic/*.test.js nodes/valveGroupControl/test/edge/*.test.js nodes/valveGroupControl/test/integration/*.test.js",
"test:legacy": "node nodes/machineGroupControl/src/groupcontrol.test.js && node nodes/generalFunctions/src/nrmse/errorMetric.test.js",
"test:all": "npm test && npm run test:node && npm run test:legacy",
"test:platform": "node scripts/test-platform.js",
"test:e2e:reactor": "node scripts/e2e-reactor-roundtrip.js",
"lint": "eslint nodes/",
"lint:fix": "eslint nodes/ --fix",

76
scripts/test-platform.js Normal file
View File

@@ -0,0 +1,76 @@
#!/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();