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");
});
});
});