Files
Mermaid-Preview-Nova/Tests/generate.test.js
T
thatguygriffandClaude Opus 5 aebc72b85e Add CLAUDE.md and the test harness
CLAUDE.md records the Nova constraints this extension is built around —
established by reading Nova 14.1's bundle and probing its preview server,
and expensive to re-derive: no previewer extension point, generated pages
must live under the preview root, dot-directories are served, and no API
reaches into a preview WebView. It also flags the one unverified
assumption, that a tab showing Preview still appears in
nova.workspace.textEditors, with its symptom and fix.

Tests/ is the harness that built the extension, kept rather than left in a
scratchpad: a stubbed Nova runtime backed by the real filesystem, node
suites for generation and the four close paths, and a headless-browser
render test that skips itself without a browser. It caught the ./ doubling
in rebased links and checkbox state not surviving serialization.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TueXpMi7eAtgWPuMr4ii52
2026-08-20 23:02:08 -03:00

62 lines
3.0 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const stub = require("./nova-stub.js");
const EXT = path.join(__dirname, "..");
const ROOT = path.join(__dirname, ".tmp", "generate");
fs.rmSync(ROOT, { recursive: true, force: true });
fs.mkdirSync(path.join(ROOT, "docs"), { recursive: true });
fs.writeFileSync(path.join(ROOT, "docs", "one.md"), "# One\n\n```mermaid\ngraph TD\nA-->B\n```\n");
fs.writeFileSync(path.join(ROOT, "docs", "two.md"), "# Two\n");
const nova = stub.build({ root: ROOT, extensionPath: EXT });
global.nova = nova;
global.Disposable = stub.Disposable;
global.CompositeDisposable = stub.CompositeDisposable;
global.Range = stub.Range;
const preview = require(path.join(EXT, "Scripts", "preview.js"));
const OUT = path.join(ROOT, ".nova", "MermaidPreview");
const results = [];
function check(name, condition) {
results.push([condition ? "PASS" : "FAIL", name]);
}
// -- generate ------------------------------------------------------------
const one = { path: path.join(ROOT, "docs", "one.md"), mode: "markdown",
editor: new stub.FakeEditor(path.join(ROOT, "docs", "one.md"), fs.readFileSync(path.join(ROOT, "docs", "one.md"), "utf8")) };
const two = { path: path.join(ROOT, "docs", "two.md"), mode: "markdown",
editor: new stub.FakeEditor(path.join(ROOT, "docs", "two.md"), fs.readFileSync(path.join(ROOT, "docs", "two.md"), "utf8")) };
const pathOne = preview.generate(one);
check("generate writes a page", fs.existsSync(pathOne));
check("assets installed", fs.existsSync(path.join(OUT, "assets", "vendor", "mermaid.min.js")));
check("stylesheet installed", fs.existsSync(path.join(OUT, "assets", "preview.css")));
check("page references relative assets", fs.readFileSync(pathOne, "utf8").includes('src="assets/vendor/mermaid.min.js"'));
check("page embeds the markdown", fs.readFileSync(pathOne, "utf8").includes("graph TD"));
const mtime = fs.statSync(path.join(OUT, "assets", "preview.css")).mtimeMs;
const pathTwo = preview.generate(two);
check("second page has its own filename", pathOne !== pathTwo && fs.existsSync(pathTwo));
check("assets not reinstalled when current", fs.statSync(path.join(OUT, "assets", "preview.css")).mtimeMs === mtime);
// -- discard -------------------------------------------------------------
preview.discard(pathOne);
check("discard removes that page", !fs.existsSync(pathOne));
check("discard keeps the other page", fs.existsSync(pathTwo));
check("discard keeps assets while a page remains", fs.existsSync(path.join(OUT, "assets", "preview.css")));
preview.discard(pathTwo);
check("last discard removes the directory", !fs.existsSync(OUT));
check("workspace otherwise untouched", fs.existsSync(path.join(ROOT, "docs", "one.md")));
// -- discard is safe to repeat -------------------------------------------
let threw = false;
try { preview.discard(pathTwo); } catch (e) { threw = true; }
check("discarding twice does not throw", !threw);
for (const [status, name] of results) console.log(`${status} ${name}`);
process.exitCode = results.some(([s]) => s === "FAIL") ? 1 : 0;