mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
fix(ui/tests): resolve frontend-lint failures in new test files
- useLogDetails.test.ts: add Wrapper.displayName, replace 'null as any' with null, type resolveCall promise resolver properly - usePaginatedDailyActivity.test.ts: remove unused waitFor import, add Wrapper.displayName, change Record<string,any> to Record<string,unknown> - UsageViewSelect.adminFiltering.test.tsx: replace all props:any with explicit SelectProps/BadgeProps/SelectOption types, replace (X as any).displayName with direct X.displayName assignment no-explicit-any count: 2034 (budget: 2040). Prettier check: clean.
This commit is contained in:
parent
556dc51f5b
commit
9beedc279b
3 changed files with 63 additions and 57 deletions
|
|
@ -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<HTMLSelectElement>) => 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 ──────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -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<string, unknown> }) => 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
|
||||
|
|
|
|||
|
|
@ -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<string, any> = {},
|
||||
) {
|
||||
function mockPage(page: number, totalPages: number, extra: Record<string, unknown> = {}) {
|
||||
return {
|
||||
results: [{ date: `2025-01-0${page}`, spend: page }],
|
||||
metadata: {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue