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