import { fireEvent, screen } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { DashboardRangeKey } from "@/domain/dashboard/types/dashboard-range"; import { renderWithProviders } from "@/test/test-utils"; const navigate = vi.fn(); const statsRange = vi.fn<(range: DashboardRangeKey) => void>(); vi.mock("react-router", async (importOriginal) => ({ ...(await importOriginal()), useNavigate: () => navigate, })); vi.mock("@/domain/dashboard/use-cases/use-dashboard-workload", () => ({ useDashboardWorkload: () => ({ data: [], isLoading: false, isFetching: false, error: null }), })); vi.mock("@/domain/dashboard/use-cases/use-dashboard-performance", () => ({ useDashboardPerformance: () => ({ data: [], isLoading: false, isFetching: false, error: null }), })); vi.mock("@/domain/dashboard/use-cases/use-dashboard-regions", () => ({ useDashboardRegions: () => ({ data: [], isLoading: false, isFetching: false, error: null }), })); vi.mock("@/domain/dashboard/use-cases/use-dashboard-vendor-insights", () => ({ useDashboardVendorInsights: () => ({ data: [], isLoading: false, isFetching: false, error: null, }), })); vi.mock("@/domain/dashboard/use-cases/use-dashboard-trend", () => ({ useDashboardTrend: () => ({ data: { granularity: null, points: [] }, isLoading: false, isFetching: false, error: null, }), })); const statsData = { scheduledTomorrow: 3, pendingUplifts: 5, avetaPending: 0, breakdown: [ { status: "PM", count: 7 }, { status: "Completed", count: 0 }, ], }; vi.mock("@/domain/dashboard/use-cases/use-dashboard-stats", () => ({ useDashboardStats: (range: DashboardRangeKey) => { statsRange(range); return { data: statsData, isLoading: false, isFetching: false, error: null }; }, })); import DashboardPage from "@/app/(protected)/dashboard"; import { avetaPendingDrilldownSearch, scheduledTomorrowDrilldownSearch, } from "@/domain/dashboard/utils/work-order-drilldown-links"; import { addDaysIso, businessTodayIso } from "@/domain/dashboard/utils/dashboard-range-utils"; function renderDashboard() { return renderWithProviders(); } describe("DashboardPage", () => { beforeEach(() => { navigate.mockReset(); statsRange.mockReset(); }); it("renders the prototype title, range options, and card titles", () => { renderDashboard(); expect(screen.getByRole("heading", { name: "Dashboard" })).toBeInTheDocument(); for (const label of ["This week", "Last 3 months", "Today", "All time"]) { expect(screen.getByRole("button", { name: label })).toBeInTheDocument(); } for (const title of [ "Scheduled Tomorrow", "Pending Uplifts", "Aveta Pending", "Work Order Breakdown", "Dispatcher Workload", "Dispatcher Performance", "Work Orders by Region", "Vendor Insights", ]) { expect(screen.getByText(title)).toBeInTheDocument(); } expect(statsRange).toHaveBeenCalledWith("this-week"); }); it("exposes positive KPI cards as keyboard-accessible drill-downs", () => { renderDashboard(); const tomorrowCard = screen.getByRole("button", { name: /Scheduled Tomorrow/ }); expect(tomorrowCard).toBeInTheDocument(); fireEvent.click(tomorrowCard); const today = businessTodayIso(); expect(navigate).toHaveBeenCalledWith( `/workorders?${scheduledTomorrowDrilldownSearch(today).toString()}`, ); fireEvent.click(screen.getByRole("button", { name: /Pending Uplifts/ })); expect(navigate).toHaveBeenCalledWith("/uplifts"); }); it("keeps zero counts inert", () => { renderDashboard(); expect(screen.queryByRole("button", { name: /Aveta Pending/ })).toBeNull(); fireEvent.click(screen.getByText("Aveta Pending")); expect(navigate).not.toHaveBeenCalled(); const inertRow = screen.getByText("Completed"); fireEvent.click(inertRow); expect(navigate).not.toHaveBeenCalled(); }); it("drills the breakdown status into filtered work orders", () => { renderDashboard(); fireEvent.click(screen.getByText("PM")); const calls = navigate.mock.calls; const [url] = calls[calls.length - 1] ?? []; expect(String(url)).toContain("/workorders?"); expect(String(url)).toContain("types=PM"); }); it("switches the stats range from the toggle", () => { renderDashboard(); fireEvent.click(screen.getByRole("button", { name: "Today" })); expect(statsRange).toHaveBeenCalledWith("today"); }); it("shows the documented empty states when datasets are empty", () => { renderDashboard(); // Breakdown and Trend share this empty copy, so both cards surface it. expect(screen.getAllByText("No work orders match the current filters.")).toHaveLength(2); expect(screen.getAllByText("No dispatchers are set up yet.")).toHaveLength(2); expect(screen.getByText("No active vendor has any work orders yet.")).toBeInTheDocument(); }); it("keeps drilldown dates deterministic on the business clock", () => { const today = businessTodayIso(); expect(scheduledTomorrowDrilldownSearch(today).get("dateFrom")).toBe(addDaysIso(today, 1)); expect(avetaPendingDrilldownSearch(today).get("aveta")).toBe("1"); }); });