// @vitest-environment happy-dom // SP27 Task 13: server-aggregated Dashboard KPIs. // // These tests pin the hook's contract independent of the Dashboard // page: when the backend is wired, it calls ``api.getDashboardKpis`` // with the requested parameters and returns the resolved value; when // the backend is not wired, it returns ``data: undefined`` so the // Dashboard can render zero-shaped fallbacks. (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; import { describe, expect, it, vi, beforeEach } from "vitest"; import { renderHook, waitFor } from "@testing-library/react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import React from "react"; import { api, type DashboardKpis } from "@/lib/api"; // Mock the api module so we can control isConfigured + getDashboardKpis // without spinning up a real backend. vi.mock("@/lib/api", async () => { const actual = await vi.importActual("@/lib/api"); return { ...actual, api: { ...actual.api, getDashboardKpis: vi.fn(), }, }; }); // Import AFTER the mock so the hook sees the mocked api. const { useDashboardKpis } = await import("./useDashboardKpis"); // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function makeWrapper() { const client = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0, staleTime: 0 }, }, }); return ({ children }: { children: React.ReactNode }) => React.createElement(QueryClientProvider, { client }, children); } // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- describe("useDashboardKpis", () => { beforeEach(() => { vi.clearAllMocks(); }); it("calls api.getDashboardKpis and returns the resolved value when configured", async () => { const payload: DashboardKpis = { totals: { count: 60295, billed: 940143.58, received: 59753, outstandingAr: 880390.58, denied: 542, denialRate: 0.9, pending: 60, }, monthly: [ { month: "2026-01", label: "Jan", count: 100, billed: 15000, received: 12000, denied: 2, denialRate: 2.0, ar: 3000 }, ], topProviders: [ { npi: "1234567893", label: "Cedar Park", claimCount: 200, billed: 30000, denied: 1 }, ], topDenials: [ { id: "C-1", patientName: "Jane Doe", billedAmount: 250, denialReason: "Missing modifier", submissionDate: "2026-06-20T12:00:00Z" }, ], }; (api.getDashboardKpis as ReturnType).mockResolvedValue(payload); // Override the isConfigured bit too — the hook keys off this. (api as unknown as { isConfigured: boolean }).isConfigured = true; const { result } = renderHook(() => useDashboardKpis({ months: 6 }), { wrapper: makeWrapper(), }); await waitFor(() => { expect(result.current.data).toEqual(payload); }); expect(api.getDashboardKpis).toHaveBeenCalledWith({ months: 6 }); expect(result.current.isError).toBe(false); }); it("returns data: undefined when the backend is not configured", () => { (api as unknown as { isConfigured: boolean }).isConfigured = false; const { result } = renderHook(() => useDashboardKpis(), { wrapper: makeWrapper(), }); expect(result.current.data).toBeUndefined(); expect(result.current.isLoading).toBe(false); expect(result.current.isError).toBe(false); // queryFn should NOT have been called — bypassed entirely. expect(api.getDashboardKpis).not.toHaveBeenCalled(); }); it("passes top_n_providers / top_n_denials through to the API", async () => { (api.getDashboardKpis as ReturnType).mockResolvedValue({ totals: { count: 0, billed: 0, received: 0, outstandingAr: 0, denied: 0, denialRate: 0, pending: 0 }, monthly: [], topProviders: [], topDenials: [], }); (api as unknown as { isConfigured: boolean }).isConfigured = true; renderHook( () => useDashboardKpis({ months: 3, top_n_providers: 2, top_n_denials: 5 }), { wrapper: makeWrapper() }, ); expect(api.getDashboardKpis).toHaveBeenCalledWith({ months: 3, top_n_providers: 2, top_n_denials: 5, }); }); });