component-source from data/helpers.sx was overriding the native OCaml version. The SX version calls env-get with wrong arity (1 arg vs required 2), producing empty source. Re-bind the native version in SSR overrides after file loading. Note: source code still not visible because highlight function returns empty — separate issue in the aser rendering pipeline. Also adds: - spec/tests/test-reactive-islands.sx — 22 SX-native tests for all 14 reactive island demos (render + signal logic + DOM) - tests/node/run-sx-tests.js — Node runner for SX test files - tests/node/test-reactive-islands.js — 39 Node/happy-dom tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
84 lines
2.2 KiB
JavaScript
84 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* run-sx-tests.js — Run SX deftest forms in the Node WASM harness.
|
|
*
|
|
* Loads island definitions + test file, runs all registered tests,
|
|
* reports results.
|
|
*
|
|
* Usage:
|
|
* node tests/node/run-sx-tests.js [test-file.sx]
|
|
*/
|
|
const { createSxEnv } = require('./sx-harness');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const DEFAULT_TEST_FILE = path.resolve(__dirname, '../../spec/tests/test-reactive-islands.sx');
|
|
const ISLAND_SRC = path.resolve(__dirname, '../../sx/sx/reactive-islands/index.sx');
|
|
|
|
async function main() {
|
|
const testFile = process.argv[2] || DEFAULT_TEST_FILE;
|
|
const origLog = console.log;
|
|
const origErr = console.error;
|
|
|
|
origLog(`=== SX Test Runner (Node+WASM) ===`);
|
|
origLog(`Test file: ${path.basename(testFile)}\n`);
|
|
|
|
const t0 = Date.now();
|
|
|
|
const env = await createSxEnv({
|
|
html: '<div id="portal-root"></div>',
|
|
});
|
|
|
|
// Load island definitions
|
|
const islandSrc = fs.readFileSync(ISLAND_SRC, 'utf8');
|
|
env.load(islandSrc);
|
|
|
|
// Load test file
|
|
const testSrc = fs.readFileSync(testFile, 'utf8');
|
|
env.load(testSrc);
|
|
|
|
// Get registered tests
|
|
const tests = env.eval('_island-tests');
|
|
const testList = tests?.items || [];
|
|
|
|
if (testList.length === 0) {
|
|
origLog('No tests found (check _island-tests registry)');
|
|
env.close();
|
|
process.exit(1);
|
|
}
|
|
|
|
origLog(`Running ${testList.length} tests...\n`);
|
|
|
|
let passed = 0, failed = 0;
|
|
const failures = [];
|
|
|
|
for (const test of testList) {
|
|
const name = test.name;
|
|
const fn = test.fn;
|
|
try {
|
|
env.K.callFn(fn, []);
|
|
passed++;
|
|
origLog(` \u2713 ${name}`);
|
|
} catch (e) {
|
|
failed++;
|
|
const msg = e.message || String(e);
|
|
// Extract the assertion message from the error
|
|
const clean = msg.replace(/^Error:\s*/, '').replace(/\s*\(in .*$/, '');
|
|
origErr(` \u2717 ${name}: ${clean}`);
|
|
failures.push({ name, error: clean });
|
|
}
|
|
}
|
|
|
|
env.close();
|
|
|
|
const dt = Date.now() - t0;
|
|
origLog(`\n=== ${passed} passed, ${failed} failed (${dt}ms) ===`);
|
|
if (failures.length > 0) {
|
|
origLog('\nFailures:');
|
|
for (const f of failures) origLog(` ${f.name}: ${f.error}`);
|
|
}
|
|
process.exit(failed > 0 ? 1 : 0);
|
|
}
|
|
|
|
main().catch(e => { console.error(e); process.exit(1); });
|