#!/usr/bin/env node /** * Nexus Test Harness * Validates the scene loads without errors using only Node.js built-ins. * Run: node test.js */ import { execSync } from 'child_process'; import { readFileSync, statSync } from 'fs'; import { resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); let passed = 0; let failed = 0; function pass(name) { console.log(` ✓ ${name}`); passed++; } function fail(name, reason) { console.log(` ✗ ${name}`); if (reason) console.log(` → ${reason}`); failed++; } function section(name) { console.log(`\n${name}`); } // ── Syntax checks ────────────────────────────────────────────────────────── section('JS Syntax'); for (const file of ['app.js', 'ws-client.js']) { try { execSync(`node --check ${resolve(__dirname, file)}`, { stdio: 'pipe' }); pass(`${file} parses without syntax errors`); } catch (e) { fail(`${file} syntax check`, e.stderr?.toString().trim() || e.message); } } // ── File size budget ──────────────────────────────────────────────────────── section('File Size Budget (< 500 KB)'); for (const file of ['app.js', 'ws-client.js']) { try { const bytes = statSync(resolve(__dirname, file)).size; const kb = (bytes / 1024).toFixed(1); if (bytes < 500 * 1024) { pass(`${file} is ${kb} KB`); } else { fail(`${file} exceeds 500 KB budget`, `${kb} KB`); } } catch (e) { fail(`${file} size check`, e.message); } } // ── JSON validation ───────────────────────────────────────────────────────── section('JSON Files'); for (const file of ['manifest.json', 'portals.json', 'vision.json']) { try { const raw = readFileSync(resolve(__dirname, file), 'utf8'); JSON.parse(raw); pass(`${file} is valid JSON`); } catch (e) { fail(`${file}`, e.message); } } // ── HTML structure ────────────────────────────────────────────────────────── section('HTML Structure (index.html)'); const html = (() => { try { return readFileSync(resolve(__dirname, 'index.html'), 'utf8'); } catch (e) { fail('index.html readable', e.message); return ''; } })(); if (html) { const checks = [ ['DOCTYPE declaration', //i], [' attribute', /]+lang=/i], ['charset meta tag', /]+charset/i], ['viewport meta tag', /]+viewport/i], ['