Folio/tests/run-project-test.mjs

76 lines
2.7 KiB
JavaScript

// Standalone test for the pure project/recents logic.
// Builds src/main/project.ts with esbuild (no Electron needed) and asserts behavior.
// Run with: node tests/run-project-test.mjs
import fs from "fs";
import os from "os";
import path from "path";
import { bundleForTest } from "./helpers/bundle.mjs";
const { mod, cleanupBundle } = await bundleForTest({
name: "folio-project",
entryPoints: ["src/main/project.ts"],
});
const {
APP_ID,
META_FILE,
CHAPTERS_DIR,
createBook,
loadBook,
saveMeta,
hasBook,
listRecents,
addRecent,
makeChapterId,
chapterFileName,
} = mod;
let failures = 0;
function ok(cond, msg) {
if (cond) console.log(" ok -", msg);
else { failures++; console.error("FAIL -", msg); }
}
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "folio-test-"));
const meta = createBook(dir, "My Novel");
ok(meta.app === APP_ID, "book app id is folio");
ok(meta.title === "My Novel", "book title set");
ok(meta.chapterOrder.length === 0, "new book has empty chapter order");
ok(fs.existsSync(path.join(dir, CHAPTERS_DIR)), "chapters/ dir created");
ok(fs.existsSync(path.join(dir, META_FILE)), "folio.json created");
const loaded = loadBook(dir);
ok(loaded.title === "My Novel", "load returns title");
ok(hasBook(dir) === true, "hasBook true for created book");
ok(hasBook("/tmp") === false, "hasBook false for non-book dir");
let threw = false;
try { loadBook("/tmp"); } catch { threw = true; }
ok(threw, "loadBook throws on non-book");
const m = loadBook(dir);
m.chapterOrder.push("x");
m.chapters["x"] = { id: "x", title: "Intro", file: "chapters/x.md" };
saveMeta(dir, m);
const m2 = loadBook(dir);
ok(m2.chapterOrder[0] === "x", "chapter order persisted");
ok(m2.chapters["x"].title === "Intro", "chapter entry persisted");
const rf = path.join(dir, "recents.json");
const r1 = addRecent(rf, { path: dir, title: "My Novel", lastOpened: "2026-01-01T00:00:00Z" });
ok(r1.length === 1, "first recent added");
ok(listRecents(rf).length === 1, "recent read back");
const r2 = addRecent(rf, { path: "/other", title: "Other", lastOpened: "2026-02-02T00:00:00Z" });
ok(r2.length === 2 && r2[0].path === "/other", "second recent added to top");
const r3 = addRecent(rf, { path: dir, title: "My Novel", lastOpened: "2026-03-03T00:00:00Z" });
ok(r3.length === 2 && r3[0].path === dir, "duplicate path deduped + moved to top");
const id = makeChapterId("Chapter One");
ok(id.startsWith("chapter-one-"), "chapter id slugified: " + id);
ok(chapterFileName(id) === `${id}.md`, "filename is <id>.md");
cleanupBundle();
fs.rmSync(dir, { recursive: true, force: true });
console.log("\nProject tests: " + (failures === 0 ? "ALL PASSED" : failures + " FAILED"));
process.exit(failures === 0 ? 0 : 1);