import { render, screen } from "@testing-library/svelte"; import ProgressIndicator from "./ProgressIndicator.test.svelte"; import { user } from "../setup-tests"; describe("ProgressIndicator", () => { describe("Default (horizontal)", () => { it("should render steps with correct states", () => { render(ProgressIndicator, { currentIndex: 2, steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: true }, { label: "Step 3", description: "Third step", complete: true }, { label: "Step 4", description: "Fourth step", complete: false }, ], }); const listItems = screen.getAllByRole("listitem"); // Check if all steps are rendered expect(listItems).toHaveLength(4); // Check completed steps const completedSteps = listItems.filter((step) => step.classList.contains("bx--progress-step--complete"), ); expect(completedSteps).toHaveLength(3); // Check current step expect(listItems[2]).toHaveTextContent("Step 3"); // Check incomplete step const incompleteStep = screen.getByText("Step 4"); expect(incompleteStep).toBeInTheDocument(); expect(incompleteStep.closest("li")).not.toHaveClass( "bx--progress-step--complete", ); }); it("should update currentIndex when clicking on completed steps", async () => { const consoleLog = vi.spyOn(console, "log"); render(ProgressIndicator, { currentIndex: 2, steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: true }, { label: "Step 3", description: "Third step", complete: true }, { label: "Step 4", description: "Fourth step", complete: false }, ], }); expect(consoleLog).not.toHaveBeenCalled(); // Click on a completed step await user.click(screen.getByText("Step 1")); expect(consoleLog).toHaveBeenCalledWith("change", 0); }); it("should not update currentIndex when preventChangeOnClick is true", async () => { const { component } = render(ProgressIndicator, { currentIndex: 2, preventChangeOnClick: true, steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: true }, { label: "Step 3", description: "Third step", complete: true }, { label: "Step 4", description: "Fourth step", complete: false }, ], }); const changeHandler = vi.fn(); component.$on("change", changeHandler); // Click on a completed step await user.click(screen.getByText("Step 1")); expect(changeHandler).not.toHaveBeenCalled(); }); }); describe("Invalid and disabled states", () => { it("should render invalid step", () => { render(ProgressIndicator, { steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: false, invalid: true, disabled: false, }, { label: "Step 3", description: "Third step", complete: false }, ], }); const invalidStep = screen.getByText("Step 2").closest("li"); expect(invalidStep).toHaveClass("bx--progress-step--incomplete"); }); it("should render disabled steps", () => { render(ProgressIndicator, { steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: false, invalid: false, disabled: true, }, { label: "Step 3", description: "Third step", complete: false, invalid: false, disabled: true, }, ], }); const disabledSteps = screen.getAllByRole("listitem").slice(1); disabledSteps.forEach((step) => { expect(step).toHaveClass("bx--progress-step--disabled"); }); }); }); describe("Variants", () => { it("should render vertical variant", () => { render(ProgressIndicator, { vertical: true, steps: [ { label: "Step 1", description: "First step", complete: false }, { label: "Step 2", description: "Second step", complete: false }, { label: "Step 3", description: "Third step", complete: false }, ], }); const progressIndicator = screen.getByRole("list"); expect(progressIndicator).toHaveClass("bx--progress--vertical"); }); it("should render with equal spacing", () => { render(ProgressIndicator, { spaceEqually: true, steps: [ { label: "Step 1", description: "First step", complete: false }, { label: "Step 2", description: "Second step", complete: false }, { label: "Step 3", description: "Third step", complete: false }, ], }); const progressIndicator = screen.getByRole("list"); expect(progressIndicator).toHaveClass("bx--progress--space-equal"); }); it("should not apply equal spacing in vertical variant", () => { render(ProgressIndicator, { vertical: true, spaceEqually: true, steps: [ { label: "Step 1", description: "First step", complete: false }, { label: "Step 2", description: "Second step", complete: false }, { label: "Step 3", description: "Third step", complete: false }, ], }); const progressIndicator = screen.getByRole("list"); expect(progressIndicator).not.toHaveClass("bx--progress--space-equal"); }); }); describe("Accessibility", () => { it("should have correct button attributes for different states", () => { render(ProgressIndicator, { currentIndex: 1, steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: false }, { label: "Step 3", description: "Third step", complete: false }, ], }); const buttons = screen.getAllByRole("button"); // Complete step button should be clickable expect(buttons[0]).toHaveAttribute("tabindex", "0"); expect(buttons[0]).toHaveAttribute("aria-disabled", "false"); expect(buttons[0]).not.toHaveClass( "bx--progress-step-button--unclickable", ); // Current step button should be unclickable expect(buttons[1]).toHaveAttribute("tabindex", "-1"); expect(buttons[1]).toHaveAttribute("aria-disabled", "false"); expect(buttons[1]).toHaveClass("bx--progress-step-button--unclickable"); // Incomplete step button should be unclickable expect(buttons[2]).toHaveAttribute("tabindex", "0"); expect(buttons[2]).toHaveAttribute("aria-disabled", "false"); expect(buttons[2]).not.toHaveClass( "bx--progress-step-button--unclickable", ); }); it("should have correct button attributes for disabled state", () => { render(ProgressIndicator, { steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: false, disabled: true, }, ], }); const disabledButton = screen.getAllByRole("button")[1]; expect(disabledButton).toHaveAttribute("disabled"); expect(disabledButton).toHaveAttribute("aria-disabled", "true"); expect(disabledButton).toHaveAttribute("tabindex", "-1"); }); it("should support keyboard navigation for complete steps", async () => { const consoleLog = vi.spyOn(console, "log"); render(ProgressIndicator, { currentIndex: 1, steps: [ { label: "Step 1", description: "First step", complete: true }, { label: "Step 2", description: "Second step", complete: false }, ], }); expect(consoleLog).not.toHaveBeenCalled(); const completeStepButton = screen.getAllByRole("button")[0]; await user.tab(); expect(completeStepButton).toHaveFocus(); await user.keyboard("{Enter}"); expect(consoleLog).toHaveBeenCalledWith("change", 0); await user.keyboard(" "); expect(consoleLog).toHaveBeenCalledWith("change", 0); }); }); });