New test infrastructure:
- site-server.js: shared OCaml HTTP server lifecycle (beforeAll/afterAll)
- site-full.spec.js: full site test suite, no Docker
Tests:
home (7 features): boot, header island, stepper island, stepper click,
SPA navigation, universal smoke, no console errors
hyperscript (8 features): boot, HS element discovery, activation (8/8),
toggle color on/off, count clicks, bounce add/wait/remove, smoke, errors
geography: 12/12 pages render
applications: 9/9 pages render
tools: 5/5 pages render
etc: 5/5 pages render
SPA navigation: SKIPPED (link boosting not working yet)
language: FAILS — /sx/(language.(spec.(explore.evaluator))) hangs (real bug)
Run: npx playwright test tests/playwright/site-full.spec.js
Run one: npx playwright test tests/playwright/site-full.spec.js -g "hyperscript"
Each test prints a feature report showing exactly what was verified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
// Shared OCaml HTTP server lifecycle for Playwright tests.
|
|
// Starts sx_server.exe --http on a random port, waits for ready.
|
|
// One instance serves all tests in a spec file.
|
|
|
|
const { spawn } = require('child_process');
|
|
const path = require('path');
|
|
|
|
const PROJECT_ROOT = path.resolve(__dirname, '../..');
|
|
|
|
class SiteServer {
|
|
constructor() {
|
|
this.port = 49152 + Math.floor(Math.random() * 16000);
|
|
this.proc = null;
|
|
this._stderr = '';
|
|
}
|
|
|
|
async start() {
|
|
const serverBin = path.join(PROJECT_ROOT, 'hosts/ocaml/_build/default/bin/sx_server.exe');
|
|
|
|
this.proc = spawn(serverBin, ['--http', String(this.port)], {
|
|
cwd: PROJECT_ROOT,
|
|
env: { ...process.env, SX_PROJECT_DIR: PROJECT_ROOT, OCAMLRUNPARAM: 'b' },
|
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
});
|
|
|
|
this.proc.stderr.on('data', chunk => { this._stderr += chunk.toString(); });
|
|
this.proc.stdout.on('data', () => {});
|
|
|
|
await new Promise((resolve, reject) => {
|
|
const timeout = setTimeout(() => reject(new Error('Server did not start within 30s\n' + this._stderr.slice(-500))), 30000);
|
|
this.proc.stderr.on('data', () => {
|
|
if (this._stderr.includes('Listening on port')) {
|
|
clearTimeout(timeout);
|
|
resolve();
|
|
}
|
|
});
|
|
this.proc.on('error', err => { clearTimeout(timeout); reject(err); });
|
|
this.proc.on('exit', code => { clearTimeout(timeout); reject(new Error('Server exited: ' + code)); });
|
|
});
|
|
}
|
|
|
|
get baseUrl() { return `http://localhost:${this.port}`; }
|
|
|
|
stop() {
|
|
if (this.proc && !this.proc.killed) {
|
|
this.proc.kill('SIGTERM');
|
|
setTimeout(() => { if (this.proc && !this.proc.killed) this.proc.kill('SIGKILL'); }, 2000);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = { SiteServer, PROJECT_ROOT };
|