104 lines
3.4 KiB
JavaScript
104 lines
3.4 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { CmapJsonExporter } from "../static/cmap/model/json-exporter.js";
|
|
import { CmapJsonImporter } from "../static/cmap/model/json-importer.js";
|
|
import {
|
|
CmapRepository,
|
|
StoredConceptMap
|
|
} from "../static/cmap/model/cmap-repository.js";
|
|
import { CmapModel } from "../static/cmap/model/concept-map.js";
|
|
|
|
const conceptId = "11111111-1111-4111-8111-111111111111";
|
|
const rootMap = {
|
|
slug: "root",
|
|
title: "Root",
|
|
document: {
|
|
schemaVersion: 2,
|
|
metadata: { explanationPageSlug: "root-page" },
|
|
concepts: [{ id: conceptId, label: "Root concept" }],
|
|
items: [{ id: 1, conceptId, kind: "concept", x: 10, y: 20 }],
|
|
connectors: []
|
|
}
|
|
};
|
|
const page = {
|
|
slug: "root-page",
|
|
title: "Root page",
|
|
markdown: "",
|
|
tags: []
|
|
};
|
|
const storedRootMap = new StoredConceptMap(rootMap, CmapModel.fromDocument(rootMap.document));
|
|
const cmapRepository = { load: async () => { throw new Error("no linked map expected"); } };
|
|
|
|
test("CmapJsonExporter builds a complete bundle including attachments", async () => {
|
|
const exporter = new CmapJsonExporter(
|
|
cmapRepository,
|
|
async () => page,
|
|
async () => ({
|
|
ok: true,
|
|
headers: { get: () => "image/png" },
|
|
arrayBuffer: async () => Uint8Array.from([1, 2, 3]).buffer
|
|
}),
|
|
"test"
|
|
);
|
|
|
|
const bundle = await exporter.export(storedRootMap);
|
|
|
|
assert.equal(bundle.generator, "test");
|
|
assert.equal(bundle.pages[0].attachments[0].contentBase64, "AQID");
|
|
});
|
|
|
|
test("CmapJsonImporter reports conflicts and imports pages, attachments and maps", async () => {
|
|
const calls = [];
|
|
const api = async (path, options = {}) => {
|
|
calls.push({ path, options });
|
|
if (path.endsWith("/upload")) return { url: "/uploads/root-page/imported-image.png" };
|
|
if (path === "/api/pages" && options.method === "POST") return { currentVersion: 1 };
|
|
if (path === "/api/cmaps" && options.method === "POST") {
|
|
const body = JSON.parse(options.body);
|
|
return {
|
|
slug: body.slug,
|
|
title: body.title,
|
|
currentVersion: 1,
|
|
document: body.document
|
|
};
|
|
}
|
|
return {};
|
|
};
|
|
const importer = new CmapJsonImporter(
|
|
new CmapRepository(api), api, (_key, fallback) => fallback);
|
|
const exporter = new CmapJsonExporter(
|
|
cmapRepository,
|
|
async () => page,
|
|
async () => ({
|
|
ok: true,
|
|
headers: { get: () => "image/png" },
|
|
arrayBuffer: async () => Uint8Array.from([1, 2, 3]).buffer
|
|
})
|
|
);
|
|
const bundle = await exporter.export(storedRootMap);
|
|
const file = { size: 100, text: async () => JSON.stringify(bundle) };
|
|
|
|
const parsed = await importer.read(file);
|
|
assert.equal(parsed.rootCmapSlug, "root");
|
|
assert.deepEqual(importer.conflicts(parsed, [{ slug: "root-page" }], []), {
|
|
pages: [parsed.pages[0]],
|
|
conceptMaps: []
|
|
});
|
|
|
|
const result = await importer.import(parsed, {
|
|
pages: [], conceptMaps: [], summary: "Imported"
|
|
});
|
|
assert.equal(result.pagesCreated, 1);
|
|
assert.equal(result.mapsCreated, 1);
|
|
assert.equal(result.attachmentsImported, 1);
|
|
assert.deepEqual(calls.map((call) => `${call.options.method} ${call.path}`), [
|
|
"POST /api/pages",
|
|
"POST /api/pages/root-page/upload",
|
|
"PUT /api/pages/root-page",
|
|
"POST /api/cmaps"
|
|
]);
|
|
const pageUpdate = JSON.parse(calls[2].options.body);
|
|
assert.match(pageUpdate.markdown, /imported-image\.png/);
|
|
});
|