/*
Unit tests for breadcrumbs covering stripSiteNameFromTitle; surfaceAncestorPageIds; buildBreadcrumbTrail. It also guards the documented public contract and regression-sensitive edge cases.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1311: Compass header sweep — declares the breadcrumbs suite's contract for test-file scaffold coverage.
*/
import { describe, expect, it } from "vitest";
import {
buildBreadcrumbTrail,
stripSiteNameFromTitle,
surfaceAncestorPageIds,
type BreadcrumbAncestorResolver,
} from "../breadcrumbs.ts";
describe("stripSiteNameFromTitle", () => {
it("strips site name suffix", () => {
expect(stripSiteNameFromTitle("About | Warpgogol")).toBe("About");
});
it("returns title unchanged when no separator", () => {
expect(stripSiteNameFromTitle("About")).toBe("About");
});
it("trims whitespace", () => {
expect(stripSiteNameFromTitle(" About ")).toBe("About");
});
});
describe("surfaceAncestorPageIds", () => {
it("returns empty for non-surface pageId", () => {
expect(surfaceAncestorPageIds("some-page")).toEqual([]);
});
it("returns empty for depth-0 root landing", () => {
expect(surfaceAncestorPageIds("industry:_root")).toEqual([]);
});
it("returns root + intermediate ancestors for depth-2", () => {
expect(surfaceAncestorPageIds("industry:tech:saas")).toEqual([
"industry:_root",
"industry:tech",
]);
});
});
describe("buildBreadcrumbTrail", () => {
const noopResolver: BreadcrumbAncestorResolver = {
resolveAncestors: async () => [],
};
it("builds [Home, self] trail with no ancestors", async () => {
const trail = await buildBreadcrumbTrail({
pageId: "about",
pageTitle: "About | Site",
selfUrl: "https://example.com/de/about/",
homeLabel: "Home",
homeUrl: "https://example.com/de/",
lang: "de",
defaultLang: "de",
resolver: noopResolver,
});
expect(trail).toHaveLength(2);
expect(trail[0]).toEqual({ name: "Home", url: "https://example.com/de/" });
expect(trail[1]).toEqual({
name: "About",
url: "https://example.com/de/about/",
pageId: "about",
});
});
it("inserts ancestors between Home and self", async () => {
const resolver: BreadcrumbAncestorResolver = {
resolveAncestors: async () => [{ name: "Section", url: "https://example.com/de/section/" }],
};
const trail = await buildBreadcrumbTrail({
pageId: "page",
pageTitle: "Page",
selfUrl: "https://example.com/de/section/page/",
homeLabel: "Home",
homeUrl: "https://example.com/de/",
lang: "de",
defaultLang: "de",
resolver,
});
expect(trail).toHaveLength(3);
expect(trail[1]).toEqual({ name: "Section", url: "https://example.com/de/section/" });
});
it("deduplicates ancestors that collapse onto Home or self", async () => {
const resolver: BreadcrumbAncestorResolver = {
resolveAncestors: async () => [
{ name: "Home", url: "https://example.com/de/" },
{ name: "Self", url: "https://example.com/de/page/" },
{ name: "Real Ancestor", url: "https://example.com/de/real/" },
],
};
const trail = await buildBreadcrumbTrail({
pageId: "page",
pageTitle: "Page",
selfUrl: "https://example.com/de/page/",
homeLabel: "Home",
homeUrl: "https://example.com/de/",
lang: "de",
defaultLang: "de",
resolver,
});
expect(trail).toHaveLength(3);
expect(trail[1]).toEqual({ name: "Real Ancestor", url: "https://example.com/de/real/" });
});
it("drops ancestors with empty names", async () => {
const resolver: BreadcrumbAncestorResolver = {
resolveAncestors: async () => [
{ name: " ", url: "https://example.com/de/empty/" },
{ name: "Valid", url: "https://example.com/de/valid/" },
],
};
const trail = await buildBreadcrumbTrail({
pageId: "page",
pageTitle: "Page",
selfUrl: "https://example.com/de/page/",
homeLabel: "Home",
homeUrl: "https://example.com/de/",
lang: "de",
defaultLang: "de",
resolver,
});
expect(trail).toHaveLength(3);
expect(trail[1]).toEqual({ name: "Valid", url: "https://example.com/de/valid/" });
});
});