import test from "node:test"; import assert from "node:assert/strict"; import { coercePublishedTags, groupPublishedTags, selectableTags, tagLabels, } from "./publishedTags"; const tag = (over: Record = {}) => ({ id: "eva-collab", label: "Collab", count: 2, channels: { "legal-mindset": 2 }, ...over, }); test("coercePublishedTags reads the document compose-site writes", () => { const tags = coercePublishedTags({ version: 1, tags: [ tag({ group: "eva", groupLabel: "Eva", color: "#b48ead", order: 1 }), tag({ id: "eva-topic", label: "Discussed", order: 2, count: 1 }), ], }); assert.equal(tags.length, 2); assert.deepEqual(tags.map((t) => t.id), ["eva-collab", "eva-topic"]); assert.equal(tags[0].groupLabel, "Eva"); assert.equal(tags[0].count, 2); assert.deepEqual(tags[0].channels, { "legal-mindset": 2 }); }); test("absence and junk both read as 'this site publishes no tags'", () => { // The two shapes of absence a viewer actually meets: the file is a 404 (a // site with nothing shippable, or one built before corpus spec 4) and the // file is there but unrecognisable. Neither may throw. for (const raw of [null, undefined, "", 42, {}, { tags: null }, { tags: {} }]) { assert.deepEqual(coercePublishedTags(raw), []); } }); test("a malformed entry is dropped, not fatal", () => { const tags = coercePublishedTags({ version: 1, tags: [ null, { label: "no id" }, tag({ id: "Not A Tag Id" }), tag({ count: undefined }), // no count — cannot be offered as a chip tag({ count: "many" }), tag(), ], }); assert.deepEqual(tags.map((t) => t.id), ["eva-collab"]); }); test("ids are lowercased and the first definition of an id wins", () => { const tags = coercePublishedTags({ tags: [tag({ id: "EVA-COLLAB", label: "First" }), tag({ label: "Second" })], }); assert.equal(tags.length, 1); assert.equal(tags[0].id, "eva-collab"); assert.equal(tags[0].label, "First"); }); test("a tag with no label falls back to its id", () => { const tags = coercePublishedTags({ tags: [tag({ label: " " })] }); assert.equal(tags[0].label, "eva-collab"); }); test("tags sort by order, then id — the same row on every site", () => { const tags = coercePublishedTags({ tags: [ tag({ id: "c", order: 3 }), tag({ id: "a", order: 1 }), tag({ id: "b", order: 1 }), ], }); assert.deepEqual(tags.map((t) => t.id), ["a", "b", "c"]); }); test("selectableTags refuses a chip that would match nothing", () => { const tags = coercePublishedTags({ tags: [tag(), tag({ id: "stale", count: 0, channels: {} })], }); assert.deepEqual(selectableTags(tags).map((t) => t.id), ["eva-collab"]); }); test("groupPublishedTags keeps tag order and sinks the ungrouped bucket", () => { const tags = coercePublishedTags({ tags: [ tag({ id: "loose", order: 1 }), tag({ id: "eva-collab", group: "eva", groupLabel: "Eva", order: 2 }), tag({ id: "eva-topic", group: "eva", order: 3 }), ], }); const groups = groupPublishedTags(tags); assert.deepEqual( groups.map((g) => [g.id, g.label, g.tags.map((t) => t.id)]), [ ["eva", "Eva", ["eva-collab", "eva-topic"]], ["", "", ["loose"]], ], ); }); test("a group label carried by a later member is still used", () => { const groups = groupPublishedTags( coercePublishedTags({ tags: [ tag({ id: "a", group: "eva", order: 1 }), tag({ id: "b", group: "eva", groupLabel: "Eva", order: 2 }), ], }), ); assert.equal(groups[0].label, "Eva"); }); test("tagLabels falls back to the id for a tag this site does not publish", () => { const labels = tagLabels(coercePublishedTags({ tags: [tag()] })); assert.equal(labels.get("eva-collab"), "Collab"); assert.equal(labels.get("eva-topic"), undefined); });