/** * Markdown citation card renderer tests (CE-WP-0004-T02). * * Snapshots lock the output format defined in * `docs/decisions/ADR-0007-citation-card-format.md`. If a snapshot * intentionally changes, update ADR-0007 in the same commit so the * written contract and the runtime stay in sync. */ import { describe, expect, it } from "vitest"; import type { Annotation } from "@shared/annotation"; import type { Document } from "@shared/document"; import type { EvidenceItem } from "@shared/evidence"; import type { AnnotationId, DocumentId, EvidenceItemId, RepresentationId, } from "@shared/ids"; import { renderCitationCardMarkdown } from "./markdown"; const DOC_ID = "doc_2024-order" as DocumentId; const REP_ID = "rep_2024-order" as RepresentationId; const ANN_ID = "ann_para3" as AnnotationId; const EV_ID = "ev_para3" as EvidenceItemId; function makeDoc(overrides: Partial = {}): Document { return { id: DOC_ID, title: "Order from 14 Mar 2024", mediaType: "application/pdf", createdAt: "2026-05-25T00:00:00.000Z", updatedAt: "2026-05-25T00:00:00.000Z", ...overrides, }; } function makeAnn(overrides: Partial = {}): Annotation { return { id: ANN_ID, documentId: DOC_ID, representationId: REP_ID, selectors: [], quote: "Die Frist endet am 31. März 2024.", normalizeVersion: 1, createdAt: "2026-05-25T00:00:00.000Z", updatedAt: "2026-05-25T00:00:00.000Z", ...overrides, }; } function makeEv(overrides: Partial = {}): EvidenceItem { return { id: EV_ID, annotationIds: [ANN_ID], status: "candidate", createdAt: "2026-05-25T00:00:00.000Z", updatedAt: "2026-05-25T00:00:00.000Z", ...overrides, }; } describe("renderCitationCardMarkdown()", () => { it("renders quote + attribution + commentary", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv({ commentary: "Deadline clause for the buyer." }), document: makeDoc(), annotation: makeAnn(), }); expect(out).toMatchInlineSnapshot(` "> Die Frist endet am 31. März 2024. — *Order from 14 Mar 2024* · [Open source](/viewer?document=doc_2024-order&annotation=ann_para3) Deadline clause for the buyer. " `); }); it("omits the commentary paragraph when none is set", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv(), document: makeDoc(), annotation: makeAnn(), }); expect(out).toMatchInlineSnapshot(` "> Die Frist endet am 31. März 2024. — *Order from 14 Mar 2024* · [Open source](/viewer?document=doc_2024-order&annotation=ann_para3) " `); }); it("preserves multi-line quotes by prefixing each line with '> '", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv(), document: makeDoc(), annotation: makeAnn({ quote: "Line one.\nLine two.\nLine three." }), }); expect(out).toMatchInlineSnapshot(` "> Line one. > Line two. > Line three. — *Order from 14 Mar 2024* · [Open source](/viewer?document=doc_2024-order&annotation=ann_para3) " `); }); it("falls back to metadata.filename when document.title is missing", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv(), document: { id: DOC_ID, mediaType: "application/pdf", createdAt: "2026-05-25T00:00:00.000Z", updatedAt: "2026-05-25T00:00:00.000Z", metadata: { filename: "order-2024.pdf" }, }, annotation: makeAnn(), }); expect(out).toMatchInlineSnapshot(` "> Die Frist endet am 31. März 2024. — *order-2024.pdf* · [Open source](/viewer?document=doc_2024-order&annotation=ann_para3) " `); }); it("escapes * and _ in the source label to keep italics intact", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv(), document: makeDoc({ title: "Order *2024_v2*" }), annotation: makeAnn(), }); expect(out).toMatchInlineSnapshot(` "> Die Frist endet am 31. März 2024. — *Order \\*2024\\_v2\\** · [Open source](/viewer?document=doc_2024-order&annotation=ann_para3) " `); }); it("omits the open-context link when override is empty", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv(), document: makeDoc(), annotation: makeAnn(), openContextUrlOverride: "", }); expect(out).toMatchInlineSnapshot(` "> Die Frist endet am 31. März 2024. — *Order from 14 Mar 2024* " `); }); it("honours an openContextUrlOverride for mounted-prefix hosts", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv(), document: makeDoc(), annotation: makeAnn(), openContextUrlOverride: "https://citations.example.test/v?d=foo&a=bar", }); expect(out).toContain( "[Open source](https://citations.example.test/v?d=foo&a=bar)", ); }); it("renders an empty blockquote line when the annotation has no quote", () => { const out = renderCitationCardMarkdown({ evidenceItem: makeEv(), document: makeDoc(), annotation: { id: ANN_ID, documentId: DOC_ID, representationId: REP_ID, selectors: [], normalizeVersion: 1, createdAt: "2026-05-25T00:00:00.000Z", updatedAt: "2026-05-25T00:00:00.000Z", }, }); expect(out).toMatchInlineSnapshot(` "> — *Order from 14 Mar 2024* · [Open source](/viewer?document=doc_2024-order&annotation=ann_para3) " `); }); });