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
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
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", "close");
|
||||
const OUT = path.join(ROOT, ".nova", "MermaidPreview");
|
||||
|
||||
fs.rmSync(ROOT, { recursive: true, force: true });
|
||||
fs.mkdirSync(path.join(ROOT, "docs"), { recursive: true });
|
||||
const MD = path.join(ROOT, "docs", "note.md");
|
||||
fs.writeFileSync(MD, "# Note\n\n```mermaid\ngraph TD\nA-->B\n```\n");
|
||||
|
||||
const nova = stub.build({ root: ROOT, extensionPath: EXT });
|
||||
global.nova = nova;
|
||||
global.Disposable = stub.Disposable;
|
||||
global.CompositeDisposable = stub.CompositeDisposable;
|
||||
global.Range = stub.Range;
|
||||
|
||||
require(path.join(EXT, "Scripts", "main.js")).activate();
|
||||
|
||||
const results = [];
|
||||
const check = (name, ok) => results.push([ok ? "PASS" : "FAIL", name]);
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
const pages = () => (fs.existsSync(OUT) ? fs.readdirSync(OUT).filter((f) => f.endsWith(".html")) : []);
|
||||
|
||||
function openSource() {
|
||||
const editor = new stub.FakeEditor(MD, fs.readFileSync(MD, "utf8"));
|
||||
nova.workspace.textEditors.push(editor);
|
||||
nova.workspace.activeTextEditor = editor;
|
||||
return editor;
|
||||
}
|
||||
function pageEditor() {
|
||||
return nova.workspace.textEditors.find((e) => e.document.path.endsWith(".html"));
|
||||
}
|
||||
|
||||
(async () => {
|
||||
// -- 1. closing the generated page removes it ------------------------
|
||||
let source = openSource();
|
||||
await nova.__invoke("mermaidpreview.preview");
|
||||
check("preview opens a page", pages().length === 1);
|
||||
|
||||
const page = pageEditor();
|
||||
nova.__close(page);
|
||||
check("page survives the grace period", pages().length === 1);
|
||||
await sleep(3000);
|
||||
check("closing the page tab deletes it", pages().length === 0);
|
||||
check("last page out removes the directory", !fs.existsSync(OUT));
|
||||
|
||||
// -- 2. a tab flipping to preview must not count as a close ----------
|
||||
nova.workspace.textEditors = [];
|
||||
source = openSource();
|
||||
await nova.__invoke("mermaidpreview.preview");
|
||||
const flipping = pageEditor();
|
||||
flipping.fireDestroy(); // destroyed, but the tab is still open
|
||||
await sleep(3000);
|
||||
check("a rebuilt editor is not mistaken for a close", pages().length === 1);
|
||||
|
||||
// -- 3. closing the Markdown file cleans up too ----------------------
|
||||
nova.__close(source);
|
||||
check("closing the source deletes the page immediately", pages().length === 0);
|
||||
check("directory removed with it", !fs.existsSync(OUT));
|
||||
|
||||
// -- 4. cleanup can be turned off ------------------------------------
|
||||
nova.workspace.textEditors = [];
|
||||
nova.config.set("mermaidpreview.cleanUpOnClose", false);
|
||||
source = openSource();
|
||||
await nova.__invoke("mermaidpreview.preview");
|
||||
const kept = pageEditor();
|
||||
nova.__close(kept);
|
||||
nova.__close(source);
|
||||
await sleep(3000);
|
||||
check("nothing is deleted when the setting is off", pages().length === 1);
|
||||
|
||||
for (const [status, name] of results) console.log(`${status} ${name}`);
|
||||
process.exitCode = results.some(([s]) => s === "FAIL") ? 1 : 0;
|
||||
})();
|
||||
Reference in New Issue
Block a user