// Breadcrumb helper unit test — the parent-nav-crumb rule that decides whether // the responsible sidebar entry is prefixed to the loader-derived trail. import { describe, expect, it } from "vitest"; import { shouldShowParentNavCrumb, type BreadcrumbTrailEntry } from "./useTitleData"; const CONTACTS_TRAIL: BreadcrumbTrailEntry[] = [ { label: "Kontakte", href: "/app/acme/contacts" }, { label: "Tags", href: "/app/acme/contacts/admin/tags" }, ]; describe("shouldShowParentNavCrumb", () => { it("drops a nav crumb whose target the trail already points at under a different name", () => { // The CRM sidebar entry links to the contact list; the trail names that very // page "Kontakte". A "CRM" crumb would be a second crumb for one route. expect( shouldShowParentNavCrumb({ navPath: "/app/acme/contacts", navTitle: "CRM", currentPathname: "/app/acme/contacts/admin/tags", currentCrumbLabel: "Tags", trail: CONTACTS_TRAIL, }), ).toBe(false); }); it("ignores a trailing slash when comparing the nav target with the trail", () => { expect( shouldShowParentNavCrumb({ navPath: "/app/acme/contacts/", navTitle: "CRM", currentPathname: "/app/acme/contacts/admin/tags", currentCrumbLabel: "Tags", trail: CONTACTS_TRAIL, }), ).toBe(false); }); it("drops a nav crumb that the trail already carries under the same label", () => { expect( shouldShowParentNavCrumb({ navPath: "/app/acme/other", navTitle: "Kontakte", currentPathname: "/app/acme/contacts/admin/tags", currentCrumbLabel: "Tags", trail: CONTACTS_TRAIL, }), ).toBe(false); }); it("drops the nav crumb when it is the current page", () => { expect( shouldShowParentNavCrumb({ navPath: "/app/acme/contacts", navTitle: "CRM", currentPathname: "/app/acme/contacts/", currentCrumbLabel: "Kontakte", trail: [{ label: "Kontakte", href: "/app/acme/contacts" }], }), ).toBe(false); }); it("keeps a nav crumb that names a section the trail does not cover", () => { expect( shouldShowParentNavCrumb({ navPath: "/app/acme/bookings/pages", navTitle: "Buchungsseiten", currentPathname: "/app/acme/bookings/pages/p1/edit", currentCrumbLabel: "Editor", trail: [{ label: "Editor", href: "/app/acme/bookings/pages/p1/edit" }], }), ).toBe(true); }); it("drops the nav crumb when the current page has its own row in the inner sub-sidenav", () => { // /leads-statistics is a sibling entry under the Leads area. The rail // already shows that context, so a "Leads" crumb would invent a level. expect( shouldShowParentNavCrumb({ navPath: "/app/acme/leads", navTitle: "Leads", currentPathname: "/app/acme/leads-statistics", currentCrumbLabel: "Lead-Statistiken", trail: [{ label: "Lead-Statistiken", href: "/app/acme/leads-statistics" }], navContextPaths: ["/app/acme/leads", "/app/acme/leads-statistics"], }), ).toBe(false); }); it("keeps the nav crumb for a sub-page that has no row of its own in the rail", () => { expect( shouldShowParentNavCrumb({ navPath: "/app/acme/leads", navTitle: "Leads", currentPathname: "/app/acme/leads/l1", currentCrumbLabel: "Karin Lehmann", trail: [{ label: "Karin Lehmann", href: "/app/acme/leads/l1" }], navContextPaths: ["/app/acme/leads", "/app/acme/leads-statistics"], }), ).toBe(true); }); it("drops the nav crumb when the trail already links to a row of the inner sub-sidenav", () => { // Booking detail below the "Buchungen" row of the Termine rail: the trail // names that row itself, so the area crumb would add a third level for a // path the user walked in two steps. expect( shouldShowParentNavCrumb({ navPath: "/app/acme/calendar", navTitle: "Termine", currentPathname: "/app/acme/bookings/b1", currentCrumbLabel: "Buchung", trail: [ { label: "Buchungen", href: "/app/acme/bookings" }, { label: "Buchung", href: "/app/acme/bookings/b1" }, ], navContextPaths: ["/app/acme/calendar", "/app/acme/bookings", "/app/acme/availability"], }), ).toBe(false); }); it("drops the nav crumb when the entry has no path to link to", () => { expect( shouldShowParentNavCrumb({ navPath: "", navTitle: "CRM", currentPathname: "/app/acme/contacts/admin/tags", currentCrumbLabel: "Tags", trail: CONTACTS_TRAIL, }), ).toBe(false); }); });