carbon-components-svelte/tests/ProgressIndicator/ProgressIndicator.test.ts
2025-03-20 17:34:20 -07:00

247 lines
8.5 KiB
TypeScript

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