diff --git a/ui/litellm-dashboard/tests/UsageViewSelect.adminFiltering.test.tsx b/ui/litellm-dashboard/tests/UsageViewSelect.adminFiltering.test.tsx index 8744618411e..4a7f4065e72 100644 --- a/ui/litellm-dashboard/tests/UsageViewSelect.adminFiltering.test.tsx +++ b/ui/litellm-dashboard/tests/UsageViewSelect.adminFiltering.test.tsx @@ -3,27 +3,47 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, fireEvent, act } from "@testing-library/react"; import { UsageViewSelect } from "../src/components/UsagePage/components/UsageViewSelect/UsageViewSelect"; +// ── Types for antd mocks ───────────────────────────────────────────────────── + +type SelectOption = { + value: string; + label: React.ReactNode; +}; + +type SelectProps = { + value?: string; + onChange?: (value: string) => void; + options?: SelectOption[]; +}; + +type BadgeProps = { + count?: React.ReactNode; + children?: React.ReactNode; +}; + // ── Mocks (mirrors the pattern from UsageViewSelect.test.tsx in src/) ────────── vi.mock("antd", async () => { const React = await import("react"); - function Select(props: any) { + function Select(props: SelectProps) { const { value, onChange, options } = props; return React.createElement( "select", - { value, onChange: (e: any) => onChange?.(e.target.value), role: "combobox" }, - options?.map((opt: any) => - React.createElement("option", { key: opt.value, value: opt.value }, opt.label), - ), + { + value, + onChange: (e: React.ChangeEvent) => onChange?.(e.target.value), + role: "combobox", + }, + options?.map((opt) => React.createElement("option", { key: opt.value, value: opt.value }, opt.label)), ); } - (Select as any).displayName = "AntdSelect"; + Select.displayName = "AntdSelect"; - function Badge(props: any) { + function Badge(props: BadgeProps) { return React.createElement("span", { "data-testid": "antd-badge" }, props.count, props.children); } - (Badge as any).displayName = "AntdBadge"; + Badge.displayName = "AntdBadge"; return { Select, Badge }; }); @@ -53,9 +73,7 @@ const NON_ADMIN_VISIBLE = ["global", "organization", "team"]; // ── Helpers ──────────────────────────────────────────────────────────────────── function getOptionValues(): string[] { - return Array.from(screen.getByRole("combobox").querySelectorAll("option")).map( - (o) => (o as HTMLOptionElement).value, - ); + return Array.from(screen.getByRole("combobox").querySelectorAll("option")).map((o) => (o as HTMLOptionElement).value); } // ── Tests ────────────────────────────────────────────────────────────────────── diff --git a/ui/litellm-dashboard/tests/useLogDetails.test.ts b/ui/litellm-dashboard/tests/useLogDetails.test.ts index c0e1f1ecf6b..89dbbceb60a 100644 --- a/ui/litellm-dashboard/tests/useLogDetails.test.ts +++ b/ui/litellm-dashboard/tests/useLogDetails.test.ts @@ -34,8 +34,12 @@ function makeWrapper() { const qc = new QueryClient({ defaultOptions: { queries: { retry: false } }, }); - return ({ children }: { children: React.ReactNode }) => + + const Wrapper = ({ children }: { children: React.ReactNode }) => React.createElement(QueryClientProvider, { client: qc }, children); + + Wrapper.displayName = "QueryClientWrapper"; + return Wrapper; } // ── Tests ────────────────────────────────────────────────────────────────────── @@ -51,62 +55,44 @@ describe("useLogDetails — conditional lazy loading", () => { }); it("should not call the API when enabled is false", () => { - renderHook( - () => useLogDetails("req-123", "2025-01-01 00:00:00", false), - { wrapper: makeWrapper() }, - ); + renderHook(() => useLogDetails("req-123", "2025-01-01 00:00:00", false), { wrapper: makeWrapper() }); expect(mockApiCall).not.toHaveBeenCalled(); }); it("should not call the API when requestId is undefined", () => { - renderHook( - () => useLogDetails(undefined, "2025-01-01 00:00:00", true), - { wrapper: makeWrapper() }, - ); + renderHook(() => useLogDetails(undefined, "2025-01-01 00:00:00", true), { wrapper: makeWrapper() }); expect(mockApiCall).not.toHaveBeenCalled(); }); it("should not call the API when startTime is undefined", () => { - renderHook( - () => useLogDetails("req-123", undefined, true), - { wrapper: makeWrapper() }, - ); + renderHook(() => useLogDetails("req-123", undefined, true), { wrapper: makeWrapper() }); expect(mockApiCall).not.toHaveBeenCalled(); }); it("should not call the API when accessToken is null", () => { - mockUseAuthorized.mockReturnValue({ ...DEFAULT_AUTH, accessToken: null as any }); + mockUseAuthorized.mockReturnValue({ ...DEFAULT_AUTH, accessToken: null }); - renderHook( - () => useLogDetails("req-123", "2025-01-01 00:00:00", true), - { wrapper: makeWrapper() }, - ); + renderHook(() => useLogDetails("req-123", "2025-01-01 00:00:00", true), { wrapper: makeWrapper() }); expect(mockApiCall).not.toHaveBeenCalled(); }); it("should call the API with accessToken, requestId and startTime when all conditions met", async () => { - const { result } = renderHook( - () => useLogDetails("req-123", "2025-01-01 00:00:00", true), - { wrapper: makeWrapper() }, - ); + const { result } = renderHook(() => useLogDetails("req-123", "2025-01-01 00:00:00", true), { + wrapper: makeWrapper(), + }); await waitFor(() => expect(result.current.isSuccess).toBe(true)); - expect(mockApiCall).toHaveBeenCalledWith( - "mock-access-token", - "req-123", - "2025-01-01 00:00:00", - ); + expect(mockApiCall).toHaveBeenCalledWith("mock-access-token", "req-123", "2025-01-01 00:00:00"); }); it("should return the data from the API response", async () => { const mockData = { messages: [{ role: "user", content: "hello" }], response: { id: "resp-1" } }; mockApiCall.mockResolvedValue(mockData); - const { result } = renderHook( - () => useLogDetails("req-456", "2025-01-02 12:00:00", true), - { wrapper: makeWrapper() }, - ); + const { result } = renderHook(() => useLogDetails("req-456", "2025-01-02 12:00:00", true), { + wrapper: makeWrapper(), + }); await waitFor(() => expect(result.current.isSuccess).toBe(true)); @@ -115,8 +101,7 @@ describe("useLogDetails — conditional lazy loading", () => { it("should transition from disabled to enabled and trigger the API call", async () => { const { result, rerender } = renderHook( - ({ enabled }: { enabled: boolean }) => - useLogDetails("req-789", "2025-01-03 00:00:00", enabled), + ({ enabled }: { enabled: boolean }) => useLogDetails("req-789", "2025-01-03 00:00:00", enabled), { wrapper: makeWrapper(), initialProps: { enabled: false } }, ); @@ -132,14 +117,17 @@ describe("useLogDetails — conditional lazy loading", () => { it("should expose isLoading=true while the API call is in progress", async () => { // Make the API call never resolve during this check - let resolveCall!: (v: any) => void; - mockApiCall.mockReturnValue(new Promise((res) => { resolveCall = res; })); - - const { result } = renderHook( - () => useLogDetails("req-loading", "2025-01-04 00:00:00", true), - { wrapper: makeWrapper() }, + let resolveCall!: (v: { messages: unknown[]; response: Record }) => void; + mockApiCall.mockReturnValue( + new Promise((res) => { + resolveCall = res; + }), ); + const { result } = renderHook(() => useLogDetails("req-loading", "2025-01-04 00:00:00", true), { + wrapper: makeWrapper(), + }); + await waitFor(() => expect(result.current.isLoading).toBe(true)); // Clean up — resolve the pending promise to avoid open handles diff --git a/ui/litellm-dashboard/tests/usePaginatedDailyActivity.test.ts b/ui/litellm-dashboard/tests/usePaginatedDailyActivity.test.ts index 8cf3e5ef497..e2a61c0f65e 100644 --- a/ui/litellm-dashboard/tests/usePaginatedDailyActivity.test.ts +++ b/ui/litellm-dashboard/tests/usePaginatedDailyActivity.test.ts @@ -1,21 +1,21 @@ import React from "react"; import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { renderHook, act, waitFor } from "@testing-library/react"; +import { renderHook, act } from "@testing-library/react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { usePaginatedDailyActivity } from "../src/components/UsagePage/hooks/usePaginatedDailyActivity"; function makeWrapper() { const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } }); - return ({ children }: { children: React.ReactNode }) => + + const Wrapper = ({ children }: { children: React.ReactNode }) => React.createElement(QueryClientProvider, { client: qc }, children); + + Wrapper.displayName = "QueryClientWrapper"; + return Wrapper; } /** Build a mock page response with controllable totals. */ -function mockPage( - page: number, - totalPages: number, - extra: Record = {}, -) { +function mockPage(page: number, totalPages: number, extra: Record = {}) { return { results: [{ date: `2025-01-0${page}`, spend: page }], metadata: {