Files
uutils.github.io/scripts/run-tests.js
T
Sylvestre Ledru adc6d38c5a Add playground tests and CI integration
- Browser-based unit tests (111 tests) covering parsing, builtins,
  pipes, UTF-8, l10n, virtual filesystem, and WASM integration
- Headless Puppeteer test runner (scripts/run-tests.js)
- CI workflow step to build WASM and run tests
2026-04-03 21:47:38 +02:00

121 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Run the wasm-terminal unit tests headlessly using Puppeteer.
*
* Usage:
* npm install puppeteer # one-time setup
* node scripts/run-tests.js [--port 8080] [--dir public]
*
* The script starts a local HTTP server, opens the test page in headless
* Chrome, waits for the results, and exits with code 1 on failure.
*/
const http = require("http");
const fs = require("fs");
const path = require("path");
// Parse CLI args
const args = process.argv.slice(2);
let port = 8080;
let dir = "public";
for (let i = 0; i < args.length; i++) {
if (args[i] === "--port" && args[i + 1]) port = parseInt(args[++i]);
if (args[i] === "--dir" && args[i + 1]) dir = args[++i];
}
// Resolve serve directory — fall back to static/ if public/ doesn't exist
// (public/ is the zola build output; static/ works for running without a build)
const serveDir = fs.existsSync(path.resolve(dir))
? path.resolve(dir)
: path.resolve("static");
const MIME_TYPES = {
".html": "text/html",
".js": "application/javascript",
".css": "text/css",
".wasm": "application/wasm",
".json": "application/json",
".svg": "image/svg+xml",
".png": "image/png",
};
function startServer() {
return new Promise((resolve) => {
const server = http.createServer((req, res) => {
const url = req.url.split("?")[0];
let filePath = path.join(serveDir, url === "/" ? "index.html" : url);
// Prevent path traversal outside the serve directory
if (!path.resolve(filePath).startsWith(serveDir + path.sep) && path.resolve(filePath) !== serveDir) {
res.writeHead(403);
res.end("Forbidden");
return;
}
if (!fs.existsSync(filePath)) {
res.writeHead(404);
res.end("Not found");
return;
}
if (fs.statSync(filePath).isDirectory()) {
filePath = path.join(filePath, "index.html");
}
const ext = path.extname(filePath);
const mime = MIME_TYPES[ext] || "application/octet-stream";
res.writeHead(200, { "Content-Type": mime });
fs.createReadStream(filePath).pipe(res);
});
server.listen(port, "127.0.0.1", () => {
console.log(`Serving ${serveDir} on http://127.0.0.1:${port}`);
resolve(server);
});
});
}
async function runTests(server) {
let puppeteer;
try {
puppeteer = require("puppeteer");
} catch {
console.error("Puppeteer not found. Install it with: npm install puppeteer");
process.exit(1);
}
const browser = await puppeteer.launch({
headless: true,
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
const page = await browser.newPage();
page.on("console", (msg) => console.log("BROWSER:", msg.text()));
page.on("pageerror", (err) => console.error("PAGE ERROR:", err.message));
const testUrl = `http://127.0.0.1:${port}/js/wasm-terminal.test.html`;
console.log(`Opening ${testUrl}`);
await page.goto(testUrl, { waitUntil: "networkidle0", timeout: 30000 });
await page.waitForFunction("window.__testsFailed !== undefined", {
timeout: 30000,
});
const failed = await page.evaluate(() => window.__testsFailed);
const passed = await page.evaluate(() => window.__testsPassed);
console.log(`\nResults: ${passed} passed, ${failed} failed`);
await browser.close();
server.close();
process.exit(failed > 0 ? 1 : 0);
}
(async () => {
const server = await startServer();
await runTests(server);
})();