72 lines
3.1 KiB
JavaScript
72 lines
3.1 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")}\nglobalThis.detectPrettyLang = detectPrettyLang; globalThis.buildPrettyHtml = buildPrettyHtml;`, sandbox);
|
|
const { detectPrettyLang, buildPrettyHtml } = 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("✅ All pretty-print tests passed successfully!");
|