import { describe, expect, it } from "vitest"; import { NoteFrontmatterSchema, PublishFrontmatterSchema, parseFrontmatter, } from "./frontmatter"; const baseTimestamps = { created: "2026-04-01T10:00:00+00:00", updated: "2026-04-26T14:00:00+00:00", }; describe("PublishFrontmatterSchema — 6 valid cases", () => { it("accepts a minimal published blog post", () => { const parsed = PublishFrontmatterSchema.parse({ status: "published", outlets: [ { outlet: "stargue.com", status: "published", published_url: "https://stargue.com/blog/post" }, ], category: "blog", }); expect(parsed.language).toBe("en"); expect(parsed.canonical).toBe("stargue.com"); expect(parsed.sanitize).toBe(true); expect(parsed.version).toBe(1); }); it("accepts a draft with no outlets yet", () => { const parsed = PublishFrontmatterSchema.parse({ status: "draft", outlets: [], category: "research", }); expect(parsed.scheduled).toBeNull(); }); it("accepts a queued post with future scheduled time", () => { const parsed = PublishFrontmatterSchema.parse({ status: "queued", outlets: [ { outlet: "linkedin.member", status: "queued", published_url: null }, ], scheduled: "2026-05-01T08:30:00-04:00", category: "blog", }); expect(parsed.scheduled).toBe("2026-05-01T08:30:00-04:00"); }); it("accepts multi-outlet partial publish", () => { const parsed = PublishFrontmatterSchema.parse({ status: "partial", outlets: [ { outlet: "stargue.com", status: "published", published_url: "https://stargue.com/x" }, { outlet: "linkedin.org", status: "failed", published_url: null }, ], category: "case-study", slug: "x", }); expect(parsed.outlets).toHaveLength(2); }); it("accepts non-English language with explicit canonical", () => { const parsed = PublishFrontmatterSchema.parse({ status: "published", language: "pap", canonical: "stargue.com", outlets: [ { outlet: "stargue.com", status: "published", published_url: "https://stargue.com/pap/x" }, ], category: "blog", }); expect(parsed.language).toBe("pap"); }); it("accepts sanitize=false explicit override", () => { const parsed = PublishFrontmatterSchema.parse({ status: "ready", outlets: [], category: "white-paper", sanitize: false, version: 3, }); expect(parsed.sanitize).toBe(false); expect(parsed.version).toBe(3); }); }); describe("PublishFrontmatterSchema — 6 invalid cases", () => { it("rejects unknown status", () => { expect(() => PublishFrontmatterSchema.parse({ status: "drafted", outlets: [], category: "blog", }), ).toThrow(); }); it("rejects unknown outlet", () => { expect(() => PublishFrontmatterSchema.parse({ status: "published", outlets: [ { outlet: "facebook", status: "published", published_url: "https://fb.com/x" }, ], category: "blog", }), ).toThrow(); }); it("rejects unknown language", () => { expect(() => PublishFrontmatterSchema.parse({ status: "draft", language: "fr", outlets: [], category: "blog", }), ).toThrow(); }); it("rejects malformed scheduled timestamp (no offset)", () => { expect(() => PublishFrontmatterSchema.parse({ status: "queued", outlets: [], scheduled: "2026-05-01T08:30:00", category: "blog", }), ).toThrow(); }); it("rejects negative version", () => { expect(() => PublishFrontmatterSchema.parse({ status: "draft", outlets: [], category: "blog", version: -1, }), ).toThrow(); }); it("rejects unknown category", () => { expect(() => PublishFrontmatterSchema.parse({ status: "draft", outlets: [], category: "newsletter", }), ).toThrow(); }); }); describe("NoteFrontmatterSchema — round-trip", () => { it("round-trips a full vault note frontmatter", () => { const input = { ...baseTimestamps, tags: ["MOC"], publish: { status: "published", outlets: [ { outlet: "stargue.com", status: "published", published_url: "https://stargue.com/x" }, ], category: "blog", }, }; const parsed = NoteFrontmatterSchema.parse(input); expect(parsed.publish?.status).toBe("published"); expect(parsed.publish?.canonical).toBe("stargue.com"); }); it("accepts a note without publish block (private vault notes)", () => { const parsed = parseFrontmatter({ ...baseTimestamps, tags: null }); expect(parsed.publish).toBeUndefined(); }); it("rejects a note missing required timestamps", () => { expect(() => NoteFrontmatterSchema.parse({ tags: [] }), ).toThrow(); }); });