88 lines
3.9 KiB
JavaScript
88 lines
3.9 KiB
JavaScript
/**
|
|
* 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, ">")
|
|
.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: '<pre><code class="language-python">x</code></pre>' }), "python");
|
|
assert.equal(detectPrettyLang({ extension: ".sh", html: '<pre><code class="language-bash">x</code></pre>' }), "bash");
|
|
assert.equal(detectPrettyLang({ extension: ".txt", html: "<pre><code>x</code></pre>" }), "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(/<span>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("<script>alert(1)</script>")');
|
|
assert.ok(!xss.includes("<script>"), "no raw script tag injected");
|
|
assert.ok(xss.includes("<script>"), "script tag escaped");
|
|
|
|
console.log("Testing fallbackTokenize (log levels, strings, comments)...");
|
|
const fb = fallbackTokenize('2026-09-14 ERROR failed to open "/var/db"\n# note simple\nvalue=42');
|
|
assert.ok(fb.includes("pp-err"), "ERROR level colored");
|
|
assert.ok(fb.includes("hljs-string"), "quoted string colored");
|
|
assert.ok(fb.includes("hljs-comment"), "comment colored");
|
|
assert.ok(fb.includes("hljs-number"), "number colored");
|
|
assert.ok(fb.includes("hljs-attr"), "key= colored");
|
|
|
|
console.log("Testing fallbackTokenize (no html injection)...");
|
|
const fbXss = fallbackTokenize('bad <img src=x onerror="alert(1)">');
|
|
assert.ok(!/<img/.test(fbXss), "no raw img tag");
|
|
assert.ok(fbXss.includes("<img"), "img escaped");
|
|
|
|
console.log("✅ All pretty-print tests passed successfully!");
|