import { describe, expect, it } from "vitest"; import { anchorHref, generateToc, headingSlug, type TocBlockInput } from "./toc.js"; const b = (id: string, type: string, text: string, parentId: string | null = null, position = "a0"): TocBlockInput => ({ id, type, content: { text }, parentId, position }); describe("TOC + heading anchors (T-147)", () => { it("generates entries in document order with levels 1-3", () => { const blocks: TocBlockInput[] = [ b("p1", "PARAGRAPH", "intro"), b("h1", "HEADING_1", "Alpha"), b("h2", "HEADING_2", "Beta"), b("h3", "HEADING_3", "Gamma"), b("h4", "HEADING_4" as string, "nope"), // not a heading level b("p2", "PARAGRAPH", "more") ]; const toc = generateToc(blocks); expect(toc.map((e) => [e.level, e.text])).toEqual([ [1, "Alpha"], [2, "Beta"], [3, "Gamma"] ]); expect(toc.every((e) => e.blockId)).toBe(true); }); it("includes headings nested in the tree (toggle children) at their own level", () => { const blocks: TocBlockInput[] = [ b("t1", "TOGGLE", "section", null, "a0"), b("h2", "HEADING_2", "Nested", "t1", "a0"), b("h1", "HEADING_1", "Top", null, "a1") ]; const toc = generateToc(blocks); expect(toc.map((e) => e.text)).toEqual(["Nested", "Top"]); }); it("derives stable, de-duplicated slugs", () => { expect(headingSlug("Hello, World!")).toBe("hello-world"); expect(headingSlug(" Mixed Case ")).toBe("mixed-case"); expect(headingSlug("")).toBe(""); // de-dup within a page const blocks: TocBlockInput[] = [b("a", "HEADING_1", "Intro", null, "a0"), b("c", "HEADING_1", "Intro", null, "a1")]; const toc = generateToc(blocks); expect(toc.map((e) => e.anchor)).toEqual(["intro", "intro-2"]); }); it("treats blocks with a missing parent as root (defensive)", () => { const blocks: TocBlockInput[] = [b("x", "HEADING_1", "Orphan", "ghost", "a0")]; expect(generateToc(blocks).map((e) => e.text)).toEqual(["Orphan"]); }); it("anchorHref produces a # fragment", () => { expect(anchorHref("hello-world")).toBe("#hello-world"); }); });