import { describe, expect, it } from "bun:test";
import { parseAppcastItems } from "./_appcast";
// The /changelog page renders exactly what the Sparkle updater receives, so
// the parser's contract is the appcast's contract: newest-first items, a
// shortVersionString title with the raw
as fallback, CDATA and
// plain-encoded descriptions both accepted, garbage in → empty list out.
const item = (over: Record) => `
-
Version ${over.title ?? "1.0.0"}
${over.short ? `${over.short}` : ""}
${over.build ? `${over.build}` : ""}
${over.date ? `${over.date}` : ""}
${over.desc ?? `Fixes]]>`}
`;
describe("parseAppcastItems", () => {
it("parses newest-first items with version, build, date and CDATA notes", () => {
const xml = `
${item({ title: "1.2.0", short: "1.2.0", build: "42", date: "Sat, 03 Oct 2026 12:00:00 +0000" })}
${item({ title: "1.1.0", short: "1.1.0", build: "41", date: "Fri, 02 Oct 2026 12:00:00 +0000" })}
`;
const releases = parseAppcastItems(xml);
expect(releases.length).toBe(2);
expect(releases[0].version).toBe("1.2.0");
expect(releases[0].build).toBe("42");
expect(releases[0].date).toContain("03 Oct 2026");
expect(releases[0].notesHtml).toBe("");
expect(releases[1].version).toBe("1.1.0");
});
it("falls back to the plain title when shortVersionString is absent", () => {
const xml = `${item({ title: "1.0.0" })}`;
const releases = parseAppcastItems(xml);
expect(releases[0].version).toBe("1.0.0");
expect(releases[0].build).toBeNull();
});
it("accepts non-CDATA escaped-HTML descriptions", () => {
const xml = `
${item({ desc: "<p>Hello</p>" })}
`;
expect(parseAppcastItems(xml)[0].notesHtml).toBe("Hello
");
});
it("returns [] for empty, non-XML, or item-less input", () => {
expect(parseAppcastItems("")).toEqual([]);
expect(parseAppcastItems("not an appcast")).toEqual([]);
expect(parseAppcastItems("")).toEqual([]);
});
it("skips items with no version signal at all", () => {
const xml = `
- orphan]]>
${item({ title: "1.0.0" })}
`;
const releases = parseAppcastItems(xml);
expect(releases.length).toBe(1);
expect(releases[0].version).toBe("1.0.0");
});
});