/** * Frontend tests for Pretty print helpers (#89). * detectPrettyLang / buildPrettyHtml are pure functions extracted from * frontend/js/viewer.js; they are evaluated in a sandbox to avoid importing * the full viewer module chain (browser-only dependencies). */ import { strict as assert } from "node:assert"; import { readFileSync } from "node:fs"; import vm from "node:vm"; import path from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const src = readFileSync(path.join(__dirname, "..", "..", "frontend", "js", "viewer.js"), "utf8"); function extractFn(name) { const start = src.indexOf(`function ${name}(`); assert.ok(start !== -1, `function ${name} not found in viewer.js`); let depth = 0; let i = src.indexOf("{", start); const begin = i; for (; i < src.length; i++) { if (src[i] === "{") depth++; else if (src[i] === "}") { depth--; if (depth === 0) break; } } return src.slice(start, i + 1); } function escapeHtml(s) { return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } const sandbox = { escapeHtml }; vm.createContext(sandbox); vm.runInContext( `${extractFn("detectPrettyLang")}\n${extractFn("buildPrettyHtml")}\n${src.slice(src.indexOf("const PP_TOKEN_RE"), src.indexOf("function applyPrettyHighlight"))}\nglobalThis.fallbackTokenize = fallbackTokenize;`, sandbox, ); const { detectPrettyLang, buildPrettyHtml, fallbackTokenize } = sandbox; console.log("Testing detectPrettyLang..."); assert.equal(detectPrettyLang({ is_json: true }), "json"); assert.equal(detectPrettyLang({ extension: ".json" }), "json"); assert.equal(detectPrettyLang({ extension: ".py", html: '
x' }), "python");
assert.equal(detectPrettyLang({ extension: ".sh", html: 'x' }), "bash");
assert.equal(detectPrettyLang({ extension: ".txt", html: "x" }), "plaintext");
console.log("Testing buildPrettyHtml (json reformat)...");
const jsonOut = buildPrettyHtml({ is_json: true }, '{"a":1,"b":[2,3]}');
assert.ok(jsonOut.includes("pretty-view"), "wrapper class present");
assert.ok(jsonOut.includes("pp-gutter"), "gutter present");
assert.ok(jsonOut.includes('class="language-json"'), "language class present");
// 4 formatted lines: {, "a": 1, "b": [...], } -> gutter must show 4 numbers at least
assert.ok(/4<\/span>/.test(jsonOut), "line numbers computed on formatted text");
assert.ok(jsonOut.includes(""a""), "HTML-escaped quotes");
console.log("Testing buildPrettyHtml (invalid json falls back to raw)...");
const bad = buildPrettyHtml({ is_json: true }, "{not valid json}");
assert.ok(bad.includes("{not valid json}"), "raw content displayed when JSON invalid");
console.log("Testing buildPrettyHtml (xss escaped)...");
const xss = buildPrettyHtml({ extension: ".py", html: "" }, 'print("")');
assert.ok(!xss.includes("