import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { fireEvent, render, screen, waitFor, within, } from "@testing-library/react"; import type { ComponentProps } from "react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { UsageDashboard } from "@/components/usage/UsageDashboard"; const useProviderStatsMock = vi.hoisted(() => vi.fn()); const useModelStatsMock = vi.hoisted(() => vi.fn()); vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string, fallback?: string) => fallback ?? key, i18n: { resolvedLanguage: "en", language: "en", }, }), })); vi.mock("framer-motion", () => ({ motion: { div: ({ children, ...props }: any) =>
{children}
, }, })); vi.mock("@/hooks/useUsageEventBridge", () => ({ useUsageEventBridge: () => {}, })); vi.mock("@/lib/query/usage", async () => { const actual = await vi.importActual( "@/lib/query/usage", ); return { ...actual, useProviderStats: (...args: unknown[]) => useProviderStatsMock(...args), useModelStats: (...args: unknown[]) => useModelStatsMock(...args), }; }); vi.mock("@/components/usage/UsageHero", () => ({ UsageHero: () =>
, })); vi.mock("@/components/usage/UsageTrendChart", () => ({ UsageTrendChart: () =>
, })); vi.mock("@/components/usage/RequestLogTable", () => ({ RequestLogTable: () =>
, })); vi.mock("@/components/usage/ProviderStatsTable", () => ({ ProviderStatsTable: () =>
, })); vi.mock("@/components/usage/ModelStatsTable", () => ({ ModelStatsTable: () =>
, })); vi.mock("@/components/usage/PricingConfigPanel", () => ({ PricingConfigPanel: () =>
, })); vi.mock("@/components/usage/UsageDateRangePicker", () => ({ UsageDateRangePicker: () => , })); vi.mock("@/components/ui/select", () => ({ Select: ({ value, onValueChange, children }: any) => (
{children}
), SelectTrigger: ({ children, ...props }: any) => ( ), SelectValue: () => null, SelectContent: ({ children }: any) =>
{children}
, SelectItem: ({ children, ...props }: any) =>
{children}
, })); const renderDashboard = (props: ComponentProps = {}) => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, }, }); return render( , ); }; describe("UsageDashboard", () => { beforeEach(() => { useProviderStatsMock.mockReset(); useModelStatsMock.mockReset(); useProviderStatsMock.mockReturnValue({ data: [] }); useModelStatsMock.mockReturnValue({ data: [] }); }); it("uses the saved refresh interval when mounted", () => { renderDashboard({ refreshIntervalMs: 5000 }); expect(screen.getByTestId("select-5000")).toBeInTheDocument(); }); it("persists refresh interval changes", async () => { const onRefreshIntervalChange = vi.fn().mockResolvedValue(true); renderDashboard({ onRefreshIntervalChange }); fireEvent.click( within(screen.getByTestId("select-30000")).getByRole("button", { name: "choose-5000", }), ); await waitFor(() => expect(onRefreshIntervalChange).toHaveBeenCalledWith(5000), ); expect(screen.getByTestId("select-5000")).toBeInTheDocument(); }); it("rolls back optimistic interval changes when persistence fails", async () => { const onRefreshIntervalChange = vi.fn().mockResolvedValue(false); renderDashboard({ onRefreshIntervalChange }); fireEvent.click( within(screen.getByTestId("select-30000")).getByRole("button", { name: "choose-5000", }), ); await waitFor(() => expect(onRefreshIntervalChange).toHaveBeenCalledWith(5000), ); await waitFor(() => expect(screen.getByTestId("select-30000")).toBeInTheDocument(), ); }); });