import { describe, test, expect, vi, beforeEach } from "vitest"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Header, { navigationItems, avatarImages, logoConfig, } from "../../app/components/Header.js"; describe("Header", () => { const mockOnToggle = vi.fn(); beforeEach(() => { mockOnToggle.mockClear(); // Clear any existing rendered content document.body.innerHTML = ""; }); describe("Accessibility and Landmarks", () => { test("renders header with correct structure and accessibility attributes", () => { const { container } = render(
); // Check main header structure - use container to scope the search const header = container.querySelector( '[role="banner"][aria-label="Main navigation header"]' ); expect(header).toBeInTheDocument(); expect(header).toHaveAttribute("aria-label", "Main navigation header"); // Check navigation - use container to scope the search const nav = container.querySelector( '[role="navigation"][aria-label="Main navigation"]' ); expect(nav).toBeInTheDocument(); expect(nav).toHaveAttribute("aria-label", "Main navigation"); }); test("renders all navigation items with proper accessibility", () => { render(
); // Check all navigation items have proper aria-labels - use menuitem role since they're in a menubar expect( screen.getAllByRole("menuitem", { name: "Navigate to Use cases page" }) .length ).toBeGreaterThan(0); expect( screen.getAllByRole("menuitem", { name: "Navigate to Learn page" }) .length ).toBeGreaterThan(0); expect( screen.getAllByRole("menuitem", { name: "Navigate to About page" }) .length ).toBeGreaterThan(0); }); }); describe("Schema Markup", () => { test("renders schema markup for site navigation", () => { render(
); const script = document.querySelector( 'script[type="application/ld+json"]' ); expect(script).toBeInTheDocument(); const schemaData = JSON.parse(script.textContent); expect(schemaData["@type"]).toBe("WebSite"); expect(schemaData.name).toBe("CommunityRule"); expect(schemaData.url).toBe("https://communityrule.com"); expect(schemaData.potentialAction["@type"]).toBe("SearchAction"); }); }); describe("Configuration Data", () => { test("navigationItems has correct structure and count", () => { expect(navigationItems).toHaveLength(3); expect(navigationItems[0]).toEqual({ href: "#", text: "Use cases", extraPadding: true, }); expect(navigationItems[1]).toEqual({ href: "#", text: "Learn", }); expect(navigationItems[2]).toEqual({ href: "#", text: "About", }); }); test("avatarImages has correct structure and count", () => { expect(avatarImages).toHaveLength(3); expect(avatarImages[0]).toEqual({ src: "/assets/Avatar_1.png", alt: "Avatar 1", }); expect(avatarImages[1]).toEqual({ src: "/assets/Avatar_2.png", alt: "Avatar 2", }); expect(avatarImages[2]).toEqual({ src: "/assets/Avatar_3.png", alt: "Avatar 3", }); }); test("logoConfig has correct structure and count", () => { expect(logoConfig).toHaveLength(5); // Check first config (xs) expect(logoConfig[0]).toEqual({ breakpoint: "block sm:hidden", size: "header", showText: false, }); // Check last config (xl+) expect(logoConfig[4]).toEqual({ breakpoint: "hidden xl:block", size: "headerXl", showText: true, }); }); }); describe("Logo Configuration", () => { test("renders correct number of logo variants", () => { render(
); const logoWrappers = screen.getAllByTestId("logo-wrapper"); expect(logoWrappers).toHaveLength(logoConfig.length); }); test("logo wrappers include expected breakpoint classes", () => { render(
); const logoWrappers = screen.getAllByTestId("logo-wrapper"); // Check first logo variant (xs only) expect(logoWrappers[0]).toHaveClass("block", "sm:hidden"); // Check second logo variant (sm only) expect(logoWrappers[1]).toHaveClass("hidden", "sm:block", "md:hidden"); // Check third logo variant (md only) expect(logoWrappers[2]).toHaveClass("hidden", "md:block", "lg:hidden"); // Check fourth logo variant (lg only) expect(logoWrappers[3]).toHaveClass("hidden", "lg:block", "xl:hidden"); // Check fifth logo variant (xl+) expect(logoWrappers[4]).toHaveClass("hidden", "xl:block"); }); }); describe("Navigation Structure", () => { test("renders all breakpoint-specific navigation containers", () => { render(
); expect(screen.getByTestId("nav-xs")).toBeInTheDocument(); expect(screen.getByTestId("nav-sm")).toBeInTheDocument(); expect(screen.getByTestId("nav-md")).toBeInTheDocument(); expect(screen.getByTestId("nav-lg")).toBeInTheDocument(); expect(screen.getByTestId("nav-xl")).toBeInTheDocument(); }); test("navigation containers use expected breakpoint classes", () => { render(
); // XSmall navigation const navXs = screen.getByTestId("nav-xs"); expect(navXs).toHaveClass("block", "sm:hidden"); // Small navigation const navSm = screen.getByTestId("nav-sm"); expect(navSm).toHaveClass("hidden", "sm:block", "md:hidden"); // Medium navigation const navMd = screen.getByTestId("nav-md"); expect(navMd).toHaveClass("hidden", "md:block", "lg:hidden"); // Large navigation const navLg = screen.getByTestId("nav-lg"); expect(navLg).toHaveClass("hidden", "lg:block", "xl:hidden"); // XLarge navigation const navXl = screen.getByTestId("nav-xl"); expect(navXl).toHaveClass("hidden", "xl:block"); }); test("renders navigation items with correct text and links", () => { render(
); // Check navigation items expect(screen.getAllByText("Use cases").length).toBeGreaterThan(0); expect(screen.getAllByText("Learn").length).toBeGreaterThan(0); expect(screen.getAllByText("About").length).toBeGreaterThan(0); }); test("renders multiple instances of navigation items for responsive design", () => { render(
); // Should have multiple instances of navigation items for different breakpoints const useCasesLinks = screen.getAllByText("Use cases"); const learnLinks = screen.getAllByText("Learn"); const aboutLinks = screen.getAllByText("About"); expect(useCasesLinks.length).toBeGreaterThan(1); expect(learnLinks.length).toBeGreaterThan(1); expect(aboutLinks.length).toBeGreaterThan(1); }); }); describe("Authentication Structure", () => { test("renders all breakpoint-specific auth containers", () => { render(
); expect(screen.getByTestId("auth-xs")).toBeInTheDocument(); expect(screen.getByTestId("auth-sm")).toBeInTheDocument(); expect(screen.getByTestId("auth-md")).toBeInTheDocument(); expect(screen.getByTestId("auth-lg")).toBeInTheDocument(); expect(screen.getByTestId("auth-xl")).toBeInTheDocument(); }); test("auth containers use expected breakpoint classes", () => { render(
); // XSmall auth const authXs = screen.getByTestId("auth-xs"); expect(authXs).toHaveClass("block", "sm:hidden"); // Small auth const authSm = screen.getByTestId("auth-sm"); expect(authSm).toHaveClass("hidden", "sm:block", "md:hidden"); // Medium auth const authMd = screen.getByTestId("auth-md"); expect(authMd).toHaveClass("hidden", "md:block", "lg:hidden"); // Large auth const authLg = screen.getByTestId("auth-lg"); expect(authLg).toHaveClass("hidden", "lg:block", "xl:hidden"); // XLarge auth const authXl = screen.getByTestId("auth-xl"); expect(authXl).toHaveClass("hidden", "xl:block"); }); test("renders login button with correct accessibility", () => { render(
); const loginLinks = screen.getAllByRole("menuitem", { name: "Log in to your account", }); expect(loginLinks.length).toBeGreaterThan(0); expect(screen.getAllByText("Log in").length).toBeGreaterThan(0); }); test("renders multiple login buttons for responsive design", () => { render(
); // Should have multiple login buttons for different breakpoints const loginButtons = screen.getAllByText("Log in"); expect(loginButtons.length).toBeGreaterThan(1); }); test("renders create rule button with avatar decoration", () => { render(
); const createRuleButtons = screen.getAllByRole("button", { name: "Create a new rule with avatar decoration", }); expect(createRuleButtons.length).toBeGreaterThan(0); expect(screen.getAllByText("Create rule").length).toBeGreaterThan(0); }); test("renders multiple create rule buttons for responsive design", () => { render(
); // Should have multiple create rule buttons for different breakpoints const createRuleButtons = screen.getAllByText("Create rule"); expect(createRuleButtons.length).toBeGreaterThan(1); }); }); describe("Avatar Images", () => { test("renders avatar images with correct attributes", () => { render(
); const avatars = screen.getAllByRole("img"); expect(avatars.length).toBeGreaterThan(0); // Check for avatar images const avatarImages = avatars.filter( (img) => img.alt === "Avatar 1" || img.alt === "Avatar 2" || img.alt === "Avatar 3" ); expect(avatarImages.length).toBeGreaterThan(0); }); }); describe("User Interactions", () => { test("calls onToggle when navigation items are clicked", async () => { const user = userEvent.setup(); render(
); // Find and click a navigation item - use menuitem role since they're in a menubar const useCasesLinks = screen.getAllByRole("menuitem", { name: "Navigate to Use cases page", }); expect(useCasesLinks.length).toBeGreaterThan(0); const useCasesLink = useCasesLinks[0]; await user.click(useCasesLink); expect(mockOnToggle).toHaveBeenCalledTimes(1); }); }); describe("CSS Classes and Styling", () => { test("has correct CSS classes for styling", () => { const { container } = render(
); const header = container.querySelector( '[role="banner"][aria-label="Main navigation header"]' ); expect(header).toHaveClass("bg-[var(--color-surface-default-primary)]"); expect(header).toHaveClass("w-full"); expect(header).toHaveClass("border-b"); expect(header).toHaveClass( "border-[var(--border-color-default-tertiary)]" ); const nav = container.querySelector( '[role="navigation"][aria-label="Main navigation"]' ); expect(nav).toHaveClass("flex"); expect(nav).toHaveClass("items-center"); expect(nav).toHaveClass("justify-between"); }); }); });