import { describe, expect, it } from "vitest"; import type { PostWithTags } from "@/lib/services/posts"; import { buildRssXml } from "@/lib/feed"; import { absolutifyHtml, resolveSiteUrl } from "@/lib/seo"; const post = (overrides: Partial = {}): PostWithTags => ({ id: 1, title: "Hello", slug: "hello", body: "

Hi there

", authorName: "Matt", authorId: null, featuredImageUrl: null, featuredImageAlt: null, status: "published", createdAt: new Date("2026-01-01T00:00:00Z"), updatedAt: new Date("2026-01-02T00:00:00Z"), publishedAt: new Date("2026-01-03T12:00:00Z"), tags: [], ...overrides, }); const settings = { siteTitle: "My Blog", headerText: "A blog" }; describe("resolveSiteUrl", () => { it("prefers the setting and strips trailing slashes", () => { expect(resolveSiteUrl({ siteUrl: "https://example.com/" })).toBe("https://example.com"); expect(resolveSiteUrl({ siteUrl: "" })).toMatch(/^http/); }); }); describe("absolutifyHtml", () => { it("rewrites relative src and href, leaves absolute and protocol-relative alone", () => { const html = 'x' + 'y'; const out = absolutifyHtml(html, "https://example.com"); expect(out).toContain('src="https://example.com/uploads/a.png"'); expect(out).toContain('href="https://example.com/posts/x"'); expect(out).toContain('href="https://other.example/y"'); expect(out).toContain('src="//cdn.example/z.png"'); }); }); describe("buildRssXml", () => { it("produces a channel with items, absolute links, and pubDate", () => { const xml = buildRssXml({ settings, siteUrl: "https://example.com", posts: [post({ tags: [{ id: 1, name: "Design", slug: "design" }] })], }); expect(xml).toContain("My Blog"); expect(xml).toContain("https://example.com/posts/hello"); expect(xml).toContain("Sat, 03 Jan 2026 12:00:00 GMT"); expect(xml).toContain("Design"); expect(xml).toContain("Matt"); expect(xml).toContain('href="https://example.com/feed.xml" rel="self"'); }); it("escapes XML-hostile titles and splits CDATA breakouts", () => { const xml = buildRssXml({ settings: { siteTitle: 'Tom & "Jerry" ', headerText: "" }, siteUrl: "https://example.com", posts: [ post({ title: "A & B ", body: '

body with ]]> literal

and ]]> raw

', }), ], }); expect(xml).toContain("Tom & "Jerry" <Show>"); expect(xml).toContain("A & B <C>"); // The raw "]]>" inside the body must not terminate the CDATA section. expect(xml).toContain("]]]]>"); }); it("rewrites relative image URLs inside content:encoded", () => { const xml = buildRssXml({ settings, siteUrl: "https://example.com", posts: [post({ body: '

' })], }); expect(xml).toContain('src="https://example.com/uploads/pic.png"'); }); });