/* Unit tests for page utils covering extractAnswerBlocksFromMarkdown; blocksToMarkdown; toPageEntryId. It also guards the documented public contract and regression-sensitive edge cases. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the page suite's contract for test-file scaffold coverage. */ import { describe, expect, it } from "vitest"; import { blocksToMarkdown, extractAnswerBlocksFromMarkdown, toPageEntryId, toSemanticAnswerBlocks, } from "../page-utils.ts"; describe("extractAnswerBlocksFromMarkdown", () => { it("extracts h2 sections with content", () => { const md = "## Section 1\n\nContent 1\n\n## Section 2\n\nContent 2"; const blocks = extractAnswerBlocksFromMarkdown(md); expect(blocks).toHaveLength(2); expect(blocks[0]).toEqual({ heading: "Section 1", content: "Content 1" }); expect(blocks[1]).toEqual({ heading: "Section 2", content: "Content 2" }); }); it("ignores content before first h2", () => { const md = "Intro text\n\n## Section\n\nContent"; const blocks = extractAnswerBlocksFromMarkdown(md); expect(blocks).toHaveLength(1); expect(blocks[0].heading).toBe("Section"); }); it("returns empty for no h2", () => { expect(extractAnswerBlocksFromMarkdown("Just text")).toEqual([]); }); }); describe("blocksToMarkdown", () => { it("converts blocks back to markdown", () => { const blocks = [ { heading: "Section 1", content: "Content 1" }, { heading: "Section 2", content: "Content 2" }, ]; expect(blocksToMarkdown(blocks)).toBe("## Section 1\n\nContent 1\n\n## Section 2\n\nContent 2"); }); }); describe("toPageEntryId", () => { it("strips language prefix and .html", () => { expect(toPageEntryId(new URL("https://example.com/de/about.html"))).toBe("about"); }); it("handles nested paths", () => { expect(toPageEntryId(new URL("https://example.com/de/section/page"))).toBe("section-page"); }); it("returns index for root", () => { expect(toPageEntryId(new URL("https://example.com/de/"))).toBe("index"); }); }); describe("toSemanticAnswerBlocks", () => { it("produces SemanticBlock with blockType prose", () => { const blocks = [{ heading: "Section", content: "Summary line\n- fact 1\n- fact 2" }]; const result = toSemanticAnswerBlocks(blocks); expect(result).toHaveLength(1); expect(result[0].blockType).toBe("prose"); expect(result[0].heading).toBe("Section"); expect(result[0].summary).toBe("Summary line"); expect(result[0].facts).toEqual(["- fact 1", "- fact 2"]); }); it("preserves table content as summary", () => { const blocks = [ { heading: "Pricing", content: "| Col1 | Col2 |\n| --- | --- |\n| a | b |", }, ]; const result = toSemanticAnswerBlocks(blocks); expect(result[0].summary).toContain("| Col1 | Col2 |"); expect(result[0].facts).toBeUndefined(); }); it("preserves multi-paragraph content as summary", () => { const blocks = [ { heading: "Section", content: "First paragraph.\n\nSecond paragraph.", }, ]; const result = toSemanticAnswerBlocks(blocks); expect(result[0].summary).toBe("First paragraph.\n\nSecond paragraph."); expect(result[0].facts).toBeUndefined(); }); });