import test from "node:test"; import assert from "node:assert/strict"; import { CmapRepository, StoredConceptMap } from "../static/cmap/model/cmap-repository.js"; import { CmapModel } from "../static/cmap/model/concept-map.js"; const documentValue = { schemaVersion: 2, concepts: [{ id: "concept-1", label: "Legacy concept" }], items: [{ id: 1, conceptId: "concept-1", kind: "concept", x: 10, y: 20 }], connectors: [] }; test("CmapRepository decodes backend documents and normalizes legacy concept ids", async () => { const repository = new CmapRepository(async () => ({ slug: "roadmap", title: "Roadmap", currentVersion: 3, document: JSON.stringify(JSON.stringify(documentValue)) })); const storedMap = await repository.load("roadmap"); assert.ok(storedMap instanceof StoredConceptMap); assert.ok(storedMap.model instanceof CmapModel); assert.equal(storedMap.currentVersion, 3); assert.equal(storedMap.toDocument().concepts[0].id, "legacy:roadmap:concept-1"); assert.equal(storedMap.toDocument().items[0].conceptId, "legacy:roadmap:concept-1"); }); test("CmapRepository serializes model saves with backend version information", async () => { const calls = []; const api = async (path, options = {}) => { calls.push({ path, options }); return { slug: "roadmap", title: "Roadmap", currentVersion: calls.length, document: documentValue }; }; const repository = new CmapRepository(api); const storedMap = await repository.load("roadmap"); const savedMap = await repository.save(storedMap, storedMap.model, { summary: "Manual save", saveKind: "manual", snapshot: true }); assert.equal(savedMap.currentVersion, 2); assert.equal(calls[1].path, "/api/cmaps/roadmap"); const body = JSON.parse(calls[1].options.body); assert.equal(body.baseVersion, 1); assert.equal(body.summary, "Manual save"); assert.equal(body.saveKind, "manual"); assert.equal(body.snapshot, true); assert.deepEqual(body.document.concepts, storedMap.toDocument().concepts); }); test("CmapRepository keeps CMap routes behind its public storage API", async () => { const calls = []; const api = async (path, options = {}) => { calls.push({ path, options }); if (path === "/api/cmaps") { if (!options.method) return { conceptMaps: [{ slug: "one", title: "One" }] }; return { slug: "one", title: "One", currentVersion: 1, document: documentValue }; } if (path.endsWith("/history")) return { versions: [{ version: 1 }] }; if (path === "/api/cmaps/concept-usage") return { placements: [{ conceptId: "one" }] }; return { slug: "one", title: "One", currentVersion: 2, document: documentValue }; }; const repository = new CmapRepository(api); const summaries = await repository.list(); const storedMap = await repository.create("One", CmapModel.fromDocument(documentValue), "one"); const versions = await repository.history(storedMap); const placements = await repository.conceptUsage(); await repository.deleteVersion(storedMap, 1); await repository.archive(storedMap, "One"); assert.equal(summaries[0].slug, "one"); assert.equal(versions[0].version, 1); assert.equal(placements[0].conceptId, "one"); assert.ok(calls.some((call) => call.path === "/api/cmaps/one/versions/1" && call.options.method === "DELETE")); assert.ok(calls.some((call) => call.path === "/api/cmaps/one" && call.options.method === "DELETE")); });