syntaxai/tdd.md · main · src / b32_sitemap.test.ts
import { describe, expect, test } from "bun:test";
import {
escapeXml,
renderSitemap,
STATIC_PATHS,
type SitemapUrl,
} from "./b32_sitemap.ts";
describe("escapeXml", () => {
test("escapes the five named entities", () => {
expect(escapeXml("&")).toBe("&");
expect(escapeXml("<")).toBe("<");
expect(escapeXml(">")).toBe(">");
expect(escapeXml('"')).toBe(""");
expect(escapeXml("'")).toBe("'");
});
test("leaves regular URL characters untouched", () => {
const s = "https://tdd.md/blog/2026-05/sama-v2-workingset-cross-repo-baseline";
expect(escapeXml(s)).toBe(s);
});
test("ampersand always escapes first (no double-escape)", () => {
expect(escapeXml("a & b < c")).toBe("a & b < c");
});
});
describe("renderSitemap", () => {
test("empty list → valid urlset with no <url> children", () => {
const xml = renderSitemap([]);
expect(xml).toBe(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
</urlset>`);
});
test("single URL with lastmod", () => {
const xml = renderSitemap([
{ loc: "https://tdd.md/blog/x", lastmod: "2026-05-25" },
]);
expect(xml).toBe(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://tdd.md/blog/x</loc><lastmod>2026-05-25</lastmod></url>
</urlset>`);
});
test("single URL without lastmod omits the <lastmod> element", () => {
const xml = renderSitemap([{ loc: "https://tdd.md/sama" }]);
expect(xml).toContain("<url><loc>https://tdd.md/sama</loc></url>");
expect(xml).not.toContain("<lastmod>");
});
test("multiple URLs preserve input order", () => {
const xml = renderSitemap([
{ loc: "https://tdd.md/a" },
{ loc: "https://tdd.md/b" },
{ loc: "https://tdd.md/c" },
]);
const aIdx = xml.indexOf("/a</loc>");
const bIdx = xml.indexOf("/b</loc>");
const cIdx = xml.indexOf("/c</loc>");
expect(aIdx).toBeGreaterThan(-1);
expect(aIdx).toBeLessThan(bIdx);
expect(bIdx).toBeLessThan(cIdx);
});
test("XML-escapes & and < inside <loc> values", () => {
const xml = renderSitemap([
{ loc: "https://tdd.md/q?a=1&b=2" },
{ loc: "https://tdd.md/<weird>" },
]);
expect(xml).toContain("<loc>https://tdd.md/q?a=1&b=2</loc>");
expect(xml).toContain("<loc>https://tdd.md/<weird></loc>");
expect(xml).not.toContain("a=1&b=2");
});
test("opens with the XML declaration and closes with </urlset>", () => {
const xml = renderSitemap([{ loc: "https://tdd.md/" }]);
expect(xml.startsWith('<?xml version="1.0" encoding="UTF-8"?>')).toBe(true);
expect(xml.endsWith("</urlset>")).toBe(true);
});
test("deterministic — same input twice → byte-identical output", () => {
const urls: ReadonlyArray<SitemapUrl> = [
{ loc: "https://tdd.md/", lastmod: "2026-05-25" },
{ loc: "https://tdd.md/blog" },
];
expect(renderSitemap(urls)).toBe(renderSitemap(urls));
});
});
describe("STATIC_PATHS", () => {
test("covers the load-bearing routes (incl. /goals + /contributing)", () => {
expect(STATIC_PATHS).toEqual([
"/",
"/blog",
"/contributing",
"/games",
"/goals",
"/leaderboard",
"/sama",
"/sama/v2",
"/sama/v2/verify",
"/sama/v2/example-crud",
"/sama/v2/example-wordpress",
"/sama/skill",
"/guides",
]);
});
test("each path is absolute (starts with /)", () => {
for (const p of STATIC_PATHS) {
expect(p.startsWith("/")).toBe(true);
}
});
});