import { beforeEach, describe, expect, it, vi } from "vitest"; import { render, screen } from "@testing-library/react"; const mockConsumeVersionUpdateFlag = vi.fn(() => false); vi.mock("../../versionCheck", () => ({ consumeVersionUpdateFlag: () => mockConsumeVersionUpdateFlag(), })); import { DashboardLoader } from "../DashboardLoader"; import { SWR_CACHE_KEYS, clearCache } from "../../utils/swrCache"; vi.mock("../../versionCheck", () => ({ consumeVersionUpdateFlag: vi.fn(() => false), })); vi.mock("../../utils/swrCache", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, clearCache: vi.fn(), }; }); import { consumeVersionUpdateFlag } from "../../versionCheck"; const mockConsumeVersionUpdateFlag = vi.mocked(consumeVersionUpdateFlag); const mockClearCache = vi.mocked(clearCache); function getStep(label: string): HTMLElement { const step = screen.getByText(label).closest("li"); if (!step) { throw new Error(`Could not find step for label: ${label}`); } return step; } describe("DashboardLoader", () => { beforeEach(() => { mockConsumeVersionUpdateFlag.mockReset(); mockConsumeVersionUpdateFlag.mockReturnValue(false); }); it("renders projects stage with active first step and pending remaining steps", () => { render(); expect(screen.getByText("Fusion")).toBeInTheDocument(); expect(getStep("Loading projects").className).toContain("dashboard-loader__step--active"); expect(getStep("Selecting project").className).toContain("dashboard-loader__step--pending"); expect(getStep("Fetching tasks").className).toContain("dashboard-loader__step--pending"); }); it("marks previous stages done when current stage is tasks", () => { render(); expect(getStep("Loading projects").className).toContain("dashboard-loader__step--done"); expect(getStep("Selecting project").className).toContain("dashboard-loader__step--done"); expect(getStep("Fetching tasks").className).toContain("dashboard-loader__step--active"); }); it("marks all steps done when stage is ready", () => { render(); expect(getStep("Loading projects").className).toContain("dashboard-loader__step--done"); expect(getStep("Selecting project").className).toContain("dashboard-loader__step--done"); expect(getStep("Fetching tasks").className).toContain("dashboard-loader__step--done"); }); it("announces loading state for assistive technologies", () => { render(); const statusRegion = screen.getByRole("status", { name: "Loading Fusion dashboard" }); expect(statusRegion).toHaveAttribute("aria-live", "polite"); expect(screen.getByLabelText("Dashboard loading progress")).toBeInTheDocument(); }); it("shows the version update copy when the flag is consumed", () => { mockConsumeVersionUpdateFlag.mockReturnValue(true); render(); expect(screen.getByText("Updating to a new frontend version...")).toBeInTheDocument(); expect(screen.getByRole("status", { name: "Updating Fusion dashboard" })).toBeInTheDocument(); }); it("keeps stage visuals stable across all stages", () => { const stages = ["projects", "project", "tasks", "ready"] as const; const snapshots = stages.map((stage) => { const { container, unmount } = render(); const steps = Array.from(container.querySelectorAll(".dashboard-loader__step")).map((step) => ({ className: step.className, label: step.querySelector(".dashboard-loader__step-label")?.textContent, iconText: step.querySelector(".dashboard-loader__step-icon")?.textContent?.trim() ?? "", hasSpinner: Boolean(step.querySelector(".dashboard-loader__spinner")), })); unmount(); return { stage, steps }; }); expect(snapshots).toMatchInlineSnapshot(` [ { "stage": "projects", "steps": [ { "className": "dashboard-loader__step dashboard-loader__step--active", "hasSpinner": true, "iconText": "", "label": "Loading projects", }, { "className": "dashboard-loader__step dashboard-loader__step--pending", "hasSpinner": false, "iconText": "•", "label": "Selecting project", }, { "className": "dashboard-loader__step dashboard-loader__step--pending", "hasSpinner": false, "iconText": "•", "label": "Fetching tasks", }, ], }, { "stage": "project", "steps": [ { "className": "dashboard-loader__step dashboard-loader__step--done", "hasSpinner": false, "iconText": "✓", "label": "Loading projects", }, { "className": "dashboard-loader__step dashboard-loader__step--active", "hasSpinner": true, "iconText": "", "label": "Selecting project", }, { "className": "dashboard-loader__step dashboard-loader__step--pending", "hasSpinner": false, "iconText": "•", "label": "Fetching tasks", }, ], }, { "stage": "tasks", "steps": [ { "className": "dashboard-loader__step dashboard-loader__step--done", "hasSpinner": false, "iconText": "✓", "label": "Loading projects", }, { "className": "dashboard-loader__step dashboard-loader__step--done", "hasSpinner": false, "iconText": "✓", "label": "Selecting project", }, { "className": "dashboard-loader__step dashboard-loader__step--active", "hasSpinner": true, "iconText": "", "label": "Fetching tasks", }, ], }, { "stage": "ready", "steps": [ { "className": "dashboard-loader__step dashboard-loader__step--done", "hasSpinner": false, "iconText": "✓", "label": "Loading projects", }, { "className": "dashboard-loader__step dashboard-loader__step--done", "hasSpinner": false, "iconText": "✓", "label": "Selecting project", }, { "className": "dashboard-loader__step dashboard-loader__step--done", "hasSpinner": false, "iconText": "✓", "label": "Fetching tasks", }, ], }, ] `); }); });