import "@testing-library/jest-dom"; import React from "react"; import { BreadcrumbNavigation } from "./index"; import { render, screen } from "@testing-library/react"; jest.mock("@shared/components/material-icon", () => ({ MaterialIcon: ({ name, className }: any) => ( {name} ), })); jest.mock("@shared/components/text", () => ({ Text: ({ as: Tag = "span", children, className }: any) => ( {children} ), })); const baseLinks = [ { buttonLabel: "Home", href: "/" }, { buttonLabel: "Blog", href: "/blog" }, { buttonLabel: "Current Page" }, ]; describe("BreadcrumbNavigation", () => { it("renders nothing when links is empty", () => { const { container } = render(); expect(container.querySelector("nav")).not.toBeInTheDocument(); }); it("renders nothing when links is undefined", () => { const { container } = render(); expect(container.querySelector("nav")).not.toBeInTheDocument(); }); it("renders nav with aria-label", () => { render(); expect(screen.getByLabelText("Breadcrumb")).toBeInTheDocument(); }); it("renders non-last links as anchor elements with chevron", () => { const { container } = render(); const anchors = container.querySelectorAll("a"); expect(anchors).toHaveLength(2); expect(anchors[0]).toHaveAttribute("href", "/"); expect(anchors[0]).toHaveTextContent("Home"); expect(anchors[1]).toHaveAttribute("href", "/blog"); const icons = screen.getAllByTestId("material-icon"); expect(icons).toHaveLength(2); icons.forEach(icon => { expect(icon).toHaveTextContent("chevron_right"); }); }); it("renders last link as Text span", () => { render(); expect(screen.getByText("Current Page")).toBeInTheDocument(); }); describe("textColor", () => { it("applies dark text color by default", () => { const { container } = render( ); const anchor = container.querySelector("a"); expect(anchor?.className).toContain("text-text"); }); it("applies light text color", () => { const { container } = render( ); const anchor = container.querySelector("a"); expect(anchor?.className).toContain("text-white"); }); it("applies mobileTextColor override", () => { const { container } = render( ); const anchor = container.querySelector("a"); expect(anchor?.className).toContain("text-white"); }); it("applies desktopTextColor override", () => { const { container } = render( ); const anchor = container.querySelector("a"); expect(anchor?.className).toContain("xl:text-white"); }); }); describe("float prop", () => { it("applies absolute class when float is always", () => { const { container } = render( ); const ol = container.querySelector("ol"); expect(ol?.className).toContain("absolute"); }); it("applies relative xl:absolute class when float is desktop (default)", () => { const { container } = render( ); const ol = container.querySelector("ol"); expect(ol?.className).toContain("relative xl:absolute"); }); it("applies absolute xl:relative class when float is mobile", () => { const { container } = render( ); const ol = container.querySelector("ol"); expect(ol?.className).toContain("absolute xl:relative"); }); it("applies relative class when float is none", () => { const { container } = render( ); const ol = container.querySelector("ol"); expect(ol?.className).toContain("relative"); expect(ol?.className).not.toContain("absolute"); }); it("applies px-7 when float is always", () => { const { container } = render( ); const ol = container.querySelector("ol"); expect(ol?.className).toContain("px-7"); }); }); describe("maxWidth", () => { it("applies max-w-120 class when maxWidth is true", () => { const { container } = render( ); expect(container.querySelector("nav")?.className).toContain("max-w-120"); }); it("applies mx-auto without max-w-120 when maxWidth is false", () => { const { container } = render( ); const nav = container.querySelector("nav"); expect(nav?.className).toContain("mx-auto"); expect(nav?.className).not.toContain("max-w-120"); }); it("applies mx-5 when maxWidth is true and float is none", () => { const { container } = render( ); const nav = container.querySelector("nav"); expect(nav?.className).toContain("mx-5"); }); it("does not apply mx-5 when float is not none", () => { const { container } = render( ); const nav = container.querySelector("nav"); expect(nav?.className).not.toContain("mx-5"); }); }); describe("Image handling", () => { it("renders image with https prefix for protocol-relative URLs", () => { const links = [ { buttonLabel: "Home", href: "/", image: { url: "//cdn.test/img.png", alt: "Logo" }, }, { buttonLabel: "Current" }, ]; render(); const img = screen.getAllByRole("img")[0]; expect(img).toHaveAttribute("src", "https://cdn.test/img.png"); expect(img).toHaveAttribute("alt", "Logo"); }); it("renders image with original URL when it does not start with //", () => { const links = [ { buttonLabel: "Home", href: "/", image: { url: "https://cdn.test/img.png", alt: "Logo" }, }, { buttonLabel: "Current" }, ]; render(); expect(screen.getAllByRole("img")[0]).toHaveAttribute( "src", "https://cdn.test/img.png" ); }); it("does not render image when url is missing", () => { const links = [ { buttonLabel: "Home", href: "/", image: {} }, { buttonLabel: "Current" }, ]; render(); expect(screen.queryByRole("img")).not.toBeInTheDocument(); }); it("renders image on last breadcrumb item", () => { const links = [ { buttonLabel: "Home", href: "/" }, { buttonLabel: "Current", image: { url: "https://cdn.test/last.png", alt: "Last" }, }, ]; render(); expect(screen.getByRole("img")).toHaveAttribute( "src", "https://cdn.test/last.png" ); }); it("uses empty alt when image alt is not provided", () => { const links = [ { buttonLabel: "Home", href: "/", image: { url: "https://cdn.test/img.png" }, }, { buttonLabel: "Current" }, ]; const { container } = render(); const img = container.querySelector("img"); expect(img).toHaveAttribute("alt", ""); }); }); describe("default float behavior", () => { it("defaults float to desktop", () => { const { container } = render(); const ol = container.querySelector("ol"); expect(ol?.className).toContain("relative xl:absolute"); }); it("default textColor derives mobileTextColor as dark when float is desktop", () => { const { container } = render( ); // When float=desktop, resolvedMobile = "dark" (always) const anchor = container.querySelector("a"); expect(anchor?.className).toContain("text-text"); }); it("default textColor derives desktopTextColor from textColor when float is desktop", () => { const { container } = render( ); const anchor = container.querySelector("a"); expect(anchor?.className).toContain("xl:text-white"); }); }); });