166 lines
6.1 KiB
JavaScript
166 lines
6.1 KiB
JavaScript
"use strict";
|
|
|
|
const test = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
let CmapMarkdownExporter;
|
|
|
|
test.before(async () => {
|
|
({ CmapMarkdownExporter } = await import(
|
|
"../static/js/cmap/model/markdown-exporter.js"));
|
|
});
|
|
|
|
function map(slug, title, document) {
|
|
return { slug, title, toDocument: () => document };
|
|
}
|
|
|
|
function repository(maps) {
|
|
return { load: async (slug) => maps[slug] };
|
|
}
|
|
|
|
const root = map("root", "Root map", {
|
|
schemaVersion: 2,
|
|
metadata: {
|
|
tags: ["architecture", "report"],
|
|
summary: "Summary of the root map.",
|
|
explanationPageSlug: "cmap:root-explanation"
|
|
},
|
|
concepts: [
|
|
{
|
|
id: "concept-a", label: "Decision", synopsis: "Choose the approach.",
|
|
aspects: ["governance"], pageSlug: "decisions:approach",
|
|
descriptionPageSlug: "cmap:decision",
|
|
cmapSlug: "child",
|
|
externalUrl: "https://example.com/decision",
|
|
tags: [{ type: "person", value: "Alex Morgan" }, { type: "person", value: "Sam de Vries" }]
|
|
},
|
|
{ id: "concept-b", label: "Delivery" }
|
|
],
|
|
items: [
|
|
{ id: 1, conceptId: "concept-a", kind: "concept" },
|
|
{ id: 2, kind: "phrase", label: "enables" },
|
|
{ id: 3, conceptId: "concept-b", kind: "concept" }
|
|
],
|
|
connectors: [
|
|
{ id: 1, sourceId: 1, targetId: 2, hasArrow: false },
|
|
{ id: 2, sourceId: 2, targetId: 3, hasArrow: true }
|
|
]
|
|
});
|
|
|
|
const child = map("child", "Child map", {
|
|
schemaVersion: 2,
|
|
metadata: { tags: ["detail"], summary: "Child summary." },
|
|
concepts: [{ id: "concept-c", label: "Child concept", cmapSlug: "root" }],
|
|
items: [{ id: 1, conceptId: "concept-c", kind: "concept" }],
|
|
connectors: []
|
|
});
|
|
|
|
const pages = new Map([
|
|
["cmap:root-explanation", { slug: "cmap:root-explanation", title: "Root explanation", tags: ["explanation"], markdown: "# Why\n\nBecause." }],
|
|
["decisions:approach", { slug: "decisions:approach", title: "Approach", tags: ["decision"], markdown: "# Decision\n\nUse the simple option." }],
|
|
["cmap:decision", { slug: "cmap:decision", title: "Decision explanation", tags: [], markdown: "Details." }]
|
|
]);
|
|
|
|
test("exports metadata, person tags, relations and linked maps to the selected depth", async () => {
|
|
const exporter = new CmapMarkdownExporter(
|
|
repository({ root, child }),
|
|
async (slug) => pages.get(slug));
|
|
const markdown = await exporter.export(root, {
|
|
maxDepth: 1,
|
|
includeWikiPages: false,
|
|
language: "nl"
|
|
});
|
|
|
|
assert.match(markdown, /CMap: Root map \(niveau 0\)/);
|
|
assert.match(markdown, /CMap: Child map \(niveau 1\)/);
|
|
assert.match(markdown, /`architecture`, `report`/);
|
|
assert.match(markdown, /Personen \(verantwoordelijkheid\/actie\):\*\* Alex Morgan, Sam de Vries/);
|
|
assert.match(markdown, /Decision — \*\*enables\*\* → Delivery/);
|
|
assert.match(markdown, /### CMap-uitleg/);
|
|
assert.match(markdown, /Webpagina:\*\* https:\/\/example\.com\/decision/);
|
|
assert.doesNotMatch(markdown, /## Gekoppelde wikipagina's/);
|
|
assert.equal((markdown.match(/## CMap: Root map/g) || []).length, 1, "cycles are exported once");
|
|
});
|
|
|
|
test("depth zero exports only the selected map", async () => {
|
|
const exporter = new CmapMarkdownExporter(
|
|
repository({ root, child }),
|
|
async (slug) => pages.get(slug));
|
|
const markdown = await exporter.export(root, {
|
|
maxDepth: 0,
|
|
includeWikiPages: false
|
|
});
|
|
assert.match(markdown, /Root map/);
|
|
assert.doesNotMatch(markdown, /## CMap: Child map/);
|
|
});
|
|
|
|
test("optionally appends linked wiki pages and concept explanations", async () => {
|
|
const exporter = new CmapMarkdownExporter(
|
|
repository({ root, child }),
|
|
async (slug) => pages.get(slug));
|
|
const markdown = await exporter.export(root, {
|
|
maxDepth: 0,
|
|
includeWikiPages: true,
|
|
language: "en"
|
|
});
|
|
assert.match(markdown, /## Linked wiki pages/);
|
|
assert.match(markdown, /### Approach/);
|
|
assert.match(markdown, /### Decision explanation/);
|
|
assert.equal((markdown.match(/Root explanation/g) || []).length, 0,
|
|
"the explanation page is embedded under the CMap rather than duplicated as an appendix heading");
|
|
assert.match(markdown, /Because\./);
|
|
});
|
|
|
|
test("derived views contain their root subtree and inherit useful root metadata", async () => {
|
|
const source = {
|
|
schemaVersion: 2,
|
|
concepts: [
|
|
{ id: "root-concept", label: "Team", synopsis: "Team scope", aspects: ["people"], descriptionPageSlug: "cmap:team" },
|
|
{ id: "child-concept", label: "Work" },
|
|
{ id: "outside-concept", label: "Outside" }
|
|
],
|
|
items: [
|
|
{ id: 10, conceptId: "root-concept", kind: "submap" },
|
|
{ id: 11, conceptId: "child-concept", kind: "concept", parentSubmapId: 10 },
|
|
{ id: 12, conceptId: "outside-concept", kind: "concept" }
|
|
],
|
|
connectors: [
|
|
{ id: 1, sourceId: 10, targetId: 11 },
|
|
{ id: 2, sourceId: 11, targetId: 12 }
|
|
]
|
|
};
|
|
const derived = map("team", "Team", {
|
|
derivedView: { sourceCmapSlug: "source", rootItemId: 10 }
|
|
});
|
|
const sourceMap = map("source", "Source", source);
|
|
const exporter = new CmapMarkdownExporter(
|
|
repository({ source: sourceMap }),
|
|
async (slug) => ({ slug, title: slug, markdown: "Team explanation", tags: [] }));
|
|
const markdown = await exporter.export(derived, { maxDepth: 0 });
|
|
assert.match(markdown, /Team scope/);
|
|
assert.match(markdown, /`people`/);
|
|
assert.match(markdown, /#### Work/);
|
|
assert.doesNotMatch(markdown, /#### Outside/);
|
|
assert.match(markdown, /Team explanation/);
|
|
});
|
|
|
|
test("direct and phrase relations receive readable Markdown", async () => {
|
|
const documentValue = {
|
|
items: [
|
|
{ id: 1, label: "A" }, { id: 2, kind: "phrase", label: "supports" },
|
|
{ id: 3, label: "B" }, { id: 4, label: "C" }
|
|
],
|
|
connectors: [
|
|
{ sourceId: 1, targetId: 2, hasArrow: false },
|
|
{ sourceId: 2, targetId: 3, hasArrow: true },
|
|
{ sourceId: 3, targetId: 4, hasArrow: true }
|
|
]
|
|
};
|
|
const relationMap = map("relations", "Relations", documentValue);
|
|
const exporter = new CmapMarkdownExporter(
|
|
repository({ relations: relationMap }),
|
|
async () => null);
|
|
const markdown = await exporter.export(relationMap);
|
|
assert.match(markdown, /A — \*\*supports\*\* → B/);
|
|
assert.match(markdown, /B → C/);
|
|
});
|