Merge pull request #23891 from BerriAI/litellm_/mystifying-tereshkova

[Test] UI: Add unit tests for 10 untested components
This commit is contained in:
yuneng-jiang 2026-03-17 13:32:38 -07:00 committed by GitHub
commit 251c279b17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 556 additions and 0 deletions

View file

@ -0,0 +1,41 @@
import { renderWithProviders, screen } from "../../tests/test-utils";
import { vi } from "vitest";
import { DebugWarningBanner } from "./DebugWarningBanner";
vi.mock("@/app/(dashboard)/hooks/healthReadiness/useHealthReadiness", () => ({
useHealthReadiness: vi.fn(),
}));
import { useHealthReadiness } from "@/app/(dashboard)/hooks/healthReadiness/useHealthReadiness";
describe("DebugWarningBanner", () => {
it("should render", () => {
vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: true } } as any);
renderWithProviders(<DebugWarningBanner />);
expect(screen.getByRole("alert")).toBeInTheDocument();
});
it("should show warning when detailed debug mode is active", () => {
vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: true } } as any);
renderWithProviders(<DebugWarningBanner />);
expect(screen.getByText(/Performance Warning: Detailed Debug Mode Active/i)).toBeInTheDocument();
});
it("should mention LITELLM_LOG=DEBUG in the description", () => {
vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: true } } as any);
renderWithProviders(<DebugWarningBanner />);
expect(screen.getByText("LITELLM_LOG=DEBUG")).toBeInTheDocument();
});
it("should render nothing when is_detailed_debug is false", () => {
vi.mocked(useHealthReadiness).mockReturnValue({ data: { is_detailed_debug: false } } as any);
const { container } = renderWithProviders(<DebugWarningBanner />);
expect(container).toBeEmptyDOMElement();
});
it("should render nothing when health data is undefined", () => {
vi.mocked(useHealthReadiness).mockReturnValue({ data: undefined } as any);
const { container } = renderWithProviders(<DebugWarningBanner />);
expect(container).toBeEmptyDOMElement();
});
});

View file

@ -0,0 +1,20 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import { vi } from "vitest";
import ExportFormatSelector from "./ExportFormatSelector";
describe("ExportFormatSelector", () => {
it("should render", () => {
renderWithProviders(<ExportFormatSelector value="csv" onChange={vi.fn()} />);
expect(screen.getByText("Format")).toBeInTheDocument();
});
it("should display the current value", () => {
renderWithProviders(<ExportFormatSelector value="csv" onChange={vi.fn()} />);
expect(screen.getByText("CSV (Excel, Google Sheets)")).toBeInTheDocument();
});
it("should display JSON label when json is selected", () => {
renderWithProviders(<ExportFormatSelector value="json" onChange={vi.fn()} />);
expect(screen.getByText("JSON (includes metadata)")).toBeInTheDocument();
});
});

View file

@ -0,0 +1,59 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import ExportSummary from "./ExportSummary";
describe("ExportSummary", () => {
it("should render", () => {
const dateRange = {
from: new Date("2024-01-01"),
to: new Date("2024-01-31"),
};
const { container } = renderWithProviders(
<ExportSummary dateRange={dateRange} selectedFilters={[]} />
);
expect(container).not.toBeEmptyDOMElement();
});
it("should display the date range", () => {
const from = new Date(2024, 0, 1);
const to = new Date(2024, 0, 31);
const dateRange = { from, to };
renderWithProviders(
<ExportSummary dateRange={dateRange} selectedFilters={[]} />
);
expect(screen.getByText(new RegExp(from.toLocaleDateString()))).toBeInTheDocument();
expect(screen.getByText(new RegExp(to.toLocaleDateString()))).toBeInTheDocument();
});
it("should show filter count when filters are selected", () => {
const dateRange = {
from: new Date("2024-01-01"),
to: new Date("2024-01-31"),
};
renderWithProviders(
<ExportSummary dateRange={dateRange} selectedFilters={["team-a", "team-b", "team-c"]} />
);
expect(screen.getByText(/3 filters/)).toBeInTheDocument();
});
it("should show singular 'filter' for one filter", () => {
const dateRange = {
from: new Date("2024-01-01"),
to: new Date("2024-01-31"),
};
renderWithProviders(
<ExportSummary dateRange={dateRange} selectedFilters={["team-a"]} />
);
expect(screen.getByText(/1 filter$/)).toBeInTheDocument();
});
it("should not show filter count when no filters selected", () => {
const dateRange = {
from: new Date("2024-01-01"),
to: new Date("2024-01-31"),
};
renderWithProviders(
<ExportSummary dateRange={dateRange} selectedFilters={[]} />
);
expect(screen.queryByText(/filter/)).not.toBeInTheDocument();
});
});

View file

@ -0,0 +1,46 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import userEvent from "@testing-library/user-event";
import { vi } from "vitest";
import ExportTypeSelector from "./ExportTypeSelector";
describe("ExportTypeSelector", () => {
it("should render", () => {
renderWithProviders(
<ExportTypeSelector value="daily" onChange={vi.fn()} entityType="team" />
);
expect(screen.getByText("Export type")).toBeInTheDocument();
});
it("should display entity type in radio labels", () => {
renderWithProviders(
<ExportTypeSelector value="daily" onChange={vi.fn()} entityType="team" />
);
expect(screen.getByText(/Day-by-day breakdown by team$/)).toBeInTheDocument();
expect(screen.getByText(/Day-by-day breakdown by team and key/)).toBeInTheDocument();
expect(screen.getByText(/Day-by-day by team and model/)).toBeInTheDocument();
});
it("should display the correct entity type for different entities", () => {
renderWithProviders(
<ExportTypeSelector value="daily" onChange={vi.fn()} entityType="organization" />
);
expect(screen.getByText(/Day-by-day breakdown by organization$/)).toBeInTheDocument();
});
it("should call onChange when a radio option is selected", async () => {
const user = userEvent.setup();
const onChange = vi.fn();
renderWithProviders(
<ExportTypeSelector value="daily" onChange={onChange} entityType="team" />
);
await user.click(screen.getByRole("radio", { name: /Day-by-day breakdown by team and key/i }));
expect(onChange).toHaveBeenCalledWith("daily_with_keys");
});
it("should have the correct radio checked", () => {
renderWithProviders(
<ExportTypeSelector value="daily_with_models" onChange={vi.fn()} entityType="team" />
);
expect(screen.getByRole("radio", { name: /Day-by-day by team and model/i })).toBeChecked();
});
});

View file

@ -0,0 +1,49 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import React from "react";
import { MetricCard } from "./MetricCard";
describe("MetricCard", () => {
it("should render", () => {
renderWithProviders(<MetricCard label="Total Requests" value={1234} />);
expect(screen.getByText("Total Requests")).toBeInTheDocument();
});
it("should display the label and value", () => {
renderWithProviders(<MetricCard label="Success Rate" value="98.5%" />);
expect(screen.getByText("Success Rate")).toBeInTheDocument();
expect(screen.getByText("98.5%")).toBeInTheDocument();
});
it("should display numeric values", () => {
renderWithProviders(<MetricCard label="Count" value={42} />);
expect(screen.getByText("42")).toBeInTheDocument();
});
it("should render icon when provided", () => {
renderWithProviders(
<MetricCard
label="Metric"
value={100}
icon={<span data-testid="test-icon">icon</span>}
/>
);
expect(screen.getByTestId("test-icon")).toBeInTheDocument();
});
it("should not render icon container when no icon provided", () => {
renderWithProviders(<MetricCard label="Metric" value={100} />);
expect(screen.queryByTestId("test-icon")).not.toBeInTheDocument();
});
it("should render subtitle when provided", () => {
renderWithProviders(
<MetricCard label="Metric" value={100} subtitle="Last 24 hours" />
);
expect(screen.getByText("Last 24 hours")).toBeInTheDocument();
});
it("should not render subtitle when not provided", () => {
renderWithProviders(<MetricCard label="Metric" value={100} />);
expect(screen.queryByText("Last 24 hours")).not.toBeInTheDocument();
});
});

View file

@ -23,6 +23,11 @@ describe("HelpLink", () => {
expect(screen.getByText("Custom docs link")).toBeInTheDocument();
});
it("should have the correct href", () => {
renderWithProviders(<HelpLink href="https://docs.example.com/test" />);
expect(screen.getByRole("link")).toHaveAttribute("href", "https://docs.example.com/test");
});
it("should include a screen-reader-only label for accessibility", () => {
renderWithProviders(<HelpLink href="https://docs.example.com" />);
@ -46,7 +51,21 @@ describe("HelpIcon", () => {
expect(screen.getByText("Tooltip help text")).toBeInTheDocument();
});
it("should hide tooltip content when not hovered", () => {
renderWithProviders(<HelpIcon content="Hidden tooltip" />);
expect(screen.queryByText("Hidden tooltip")).not.toBeInTheDocument();
});
it("should show learn more link when learnMoreHref is provided", async () => {
const user = userEvent.setup();
renderWithProviders(
<HelpIcon content="Help text" learnMoreHref="https://docs.example.com" />
);
await user.hover(screen.getByRole("button", { name: /help information/i }));
expect(screen.getByText("Learn more")).toBeInTheDocument();
});
it("should use custom learn more text when provided", async () => {
const user = userEvent.setup();
renderWithProviders(
<HelpIcon
@ -84,6 +103,11 @@ describe("DocsMenu", () => {
expect(screen.getByRole("button", { name: /docs/i })).toBeInTheDocument();
});
it("should hide menu items initially", () => {
renderWithProviders(<DocsMenu items={items} />);
expect(screen.queryByText("Custom pricing")).not.toBeInTheDocument();
});
it("should show menu items when button is clicked", async () => {
const user = userEvent.setup();
renderWithProviders(<DocsMenu items={items} />);

View file

@ -0,0 +1,84 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import { vi } from "vitest";
import {
PolicySelect,
policyStyle,
INPUT_POLICY_OPTIONS,
OUTPUT_POLICY_OPTIONS,
} from "./PolicySelect";
describe("policyStyle", () => {
it("should return the matching option for a known policy", () => {
expect(policyStyle("trusted")).toEqual(INPUT_POLICY_OPTIONS[1]);
});
it("should return the matching option for blocked", () => {
expect(policyStyle("blocked")).toEqual(INPUT_POLICY_OPTIONS[2]);
});
it("should return the first option as fallback for unknown policy", () => {
expect(policyStyle("unknown")).toEqual(INPUT_POLICY_OPTIONS[0]);
});
});
describe("PolicySelect", () => {
it("should render", () => {
renderWithProviders(
<PolicySelect
value="untrusted"
toolName="test-tool"
saving={false}
onChange={vi.fn()}
/>
);
expect(screen.getByText("untrusted")).toBeInTheDocument();
});
it("should show the current policy value", () => {
renderWithProviders(
<PolicySelect
value="trusted"
toolName="test-tool"
saving={false}
onChange={vi.fn()}
/>
);
expect(screen.getByText("trusted")).toBeInTheDocument();
});
it("should be disabled when saving is true", () => {
renderWithProviders(
<PolicySelect
value="untrusted"
toolName="test-tool"
saving={true}
onChange={vi.fn()}
/>
);
expect(screen.getByRole("combobox")).toHaveAttribute("aria-expanded", "false");
expect(screen.getByRole("combobox").closest(".ant-select")).toHaveClass("ant-select-disabled");
});
it("should not be disabled when saving is false", () => {
renderWithProviders(
<PolicySelect
value="untrusted"
toolName="test-tool"
saving={false}
onChange={vi.fn()}
/>
);
expect(screen.getByRole("combobox").closest(".ant-select")).not.toHaveClass("ant-select-disabled");
});
});
describe("Policy option constants", () => {
it("should have 3 input policy options", () => {
expect(INPUT_POLICY_OPTIONS).toHaveLength(3);
});
it("should have 2 output policy options (no blocked)", () => {
expect(OUTPUT_POLICY_OPTIONS).toHaveLength(2);
expect(OUTPUT_POLICY_OPTIONS.map((o) => o.value)).toEqual(["untrusted", "trusted"]);
});
});

View file

@ -0,0 +1,82 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import { vi } from "vitest";
import ComplexityRouterConfig from "./ComplexityRouterConfig";
const mockModelInfo = [
{ model_group: "gpt-4" },
{ model_group: "gpt-3.5-turbo" },
{ model_group: "claude-3-opus" },
] as any[];
const defaultTiers = {
SIMPLE: "gpt-3.5-turbo",
MEDIUM: "gpt-3.5-turbo",
COMPLEX: "gpt-4",
REASONING: "claude-3-opus",
};
describe("ComplexityRouterConfig", () => {
it("should render", () => {
renderWithProviders(
<ComplexityRouterConfig
modelInfo={mockModelInfo}
value={defaultTiers}
onChange={vi.fn()}
/>
);
expect(screen.getByText("Complexity Tier Configuration")).toBeInTheDocument();
});
it("should display all four tier labels", () => {
renderWithProviders(
<ComplexityRouterConfig
modelInfo={mockModelInfo}
value={defaultTiers}
onChange={vi.fn()}
/>
);
expect(screen.getByText("Simple Tier")).toBeInTheDocument();
expect(screen.getByText("Medium Tier")).toBeInTheDocument();
expect(screen.getByText("Complex Tier")).toBeInTheDocument();
expect(screen.getByText("Reasoning Tier")).toBeInTheDocument();
});
it("should show example queries for each tier", () => {
renderWithProviders(
<ComplexityRouterConfig
modelInfo={mockModelInfo}
value={defaultTiers}
onChange={vi.fn()}
/>
);
expect(screen.getByText(/Hello!/)).toBeInTheDocument();
expect(screen.getByText(/Explain how REST APIs work/)).toBeInTheDocument();
expect(screen.getByText(/Design a microservices architecture/)).toBeInTheDocument();
expect(screen.getByText(/Think step by step/)).toBeInTheDocument();
});
it("should display the how classification works section", () => {
renderWithProviders(
<ComplexityRouterConfig
modelInfo={mockModelInfo}
value={defaultTiers}
onChange={vi.fn()}
/>
);
expect(screen.getByText("How Classification Works")).toBeInTheDocument();
});
it("should show score thresholds in the classification section", () => {
renderWithProviders(
<ComplexityRouterConfig
modelInfo={mockModelInfo}
value={defaultTiers}
onChange={vi.fn()}
/>
);
expect(screen.getByText(/Score < 0.15/)).toBeInTheDocument();
expect(screen.getByText(/Score 0.15 - 0.35/)).toBeInTheDocument();
expect(screen.getByText(/Score 0.35 - 0.60/)).toBeInTheDocument();
expect(screen.getByText(/Score > 0.60/)).toBeInTheDocument();
});
});

View file

@ -0,0 +1,90 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import { vi } from "vitest";
import AgentCardGrid from "./agent_card_grid";
import type { Agent, AgentKeyInfo } from "./types";
vi.mock("./agent_card", () => ({
default: ({ agent, onAgentClick }: any) => (
<div data-testid={`agent-card-${agent.agent_id}`} onClick={() => onAgentClick(agent.agent_id)}>
{agent.agent_name}
</div>
),
}));
const mockAgents: Agent[] = [
{
agent_id: "agent-1",
agent_name: "Test Agent 1",
litellm_params: { model: "gpt-4" },
agent_card_params: { description: "First agent" },
},
{
agent_id: "agent-2",
agent_name: "Test Agent 2",
litellm_params: { model: "claude-3" },
agent_card_params: { description: "Second agent" },
},
];
const mockKeyInfoMap: Record<string, AgentKeyInfo> = {
"agent-1": { has_key: true, key_alias: "key-1" },
"agent-2": { has_key: false },
};
const defaultProps = {
agentsList: mockAgents,
keyInfoMap: mockKeyInfoMap,
isLoading: false,
onDeleteClick: vi.fn(),
accessToken: "test-token",
onAgentUpdated: vi.fn(),
isAdmin: true,
onAgentClick: vi.fn(),
};
describe("AgentCardGrid", () => {
it("should render", () => {
renderWithProviders(<AgentCardGrid {...defaultProps} />);
expect(screen.getByText("Test Agent 1")).toBeInTheDocument();
});
it("should render all agent cards", () => {
renderWithProviders(<AgentCardGrid {...defaultProps} />);
expect(screen.getByText("Test Agent 1")).toBeInTheDocument();
expect(screen.getByText("Test Agent 2")).toBeInTheDocument();
});
it("should show loading skeletons when isLoading is true", () => {
renderWithProviders(<AgentCardGrid {...defaultProps} isLoading={true} />);
expect(screen.queryByText("Test Agent 1")).not.toBeInTheDocument();
});
it("should show admin empty state message when no agents and isAdmin", () => {
renderWithProviders(
<AgentCardGrid {...defaultProps} agentsList={[]} isAdmin={true} />
);
expect(
screen.getByText("No agents found. Create one to get started.")
).toBeInTheDocument();
});
it("should show non-admin empty state message when no agents and not admin", () => {
renderWithProviders(
<AgentCardGrid {...defaultProps} agentsList={[]} isAdmin={false} />
);
expect(
screen.getByText("No agents found. Contact an admin to create agents.")
).toBeInTheDocument();
});
it("should call onAgentClick when a card is clicked", async () => {
const onAgentClick = vi.fn();
renderWithProviders(
<AgentCardGrid {...defaultProps} onAgentClick={onAgentClick} />
);
const { default: userEvent } = await import("@testing-library/user-event");
const user = userEvent.setup();
await user.click(screen.getByTestId("agent-card-agent-1"));
expect(onAgentClick).toHaveBeenCalledWith("agent-1");
});
});

View file

@ -0,0 +1,61 @@
import { renderWithProviders, screen } from "../../../tests/test-utils";
import userEvent from "@testing-library/user-event";
import { vi } from "vitest";
import { Form } from "antd";
import React from "react";
import { RateLimitTypeFormItem } from "./RateLimitTypeFormItem";
const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<Form>{children}</Form>
);
describe("RateLimitTypeFormItem", () => {
it("should render", () => {
renderWithProviders(
<Wrapper>
<RateLimitTypeFormItem type="tpm" name="tpm_type" />
</Wrapper>
);
expect(screen.getByText(/TPM Rate Limit Type/)).toBeInTheDocument();
});
it("should display TPM label for tpm type", () => {
renderWithProviders(
<Wrapper>
<RateLimitTypeFormItem type="tpm" name="tpm_type" />
</Wrapper>
);
expect(screen.getByText(/TPM Rate Limit Type/)).toBeInTheDocument();
});
it("should display RPM label for rpm type", () => {
renderWithProviders(
<Wrapper>
<RateLimitTypeFormItem type="rpm" name="rpm_type" />
</Wrapper>
);
expect(screen.getByText(/RPM Rate Limit Type/)).toBeInTheDocument();
});
it("should show the select placeholder by default", () => {
renderWithProviders(
<Wrapper>
<RateLimitTypeFormItem type="tpm" name="tpm_type" />
</Wrapper>
);
expect(screen.getByText("Select rate limit type")).toBeInTheDocument();
});
it("should call onChange when provided", async () => {
const user = userEvent.setup();
const onChange = vi.fn();
renderWithProviders(
<Wrapper>
<RateLimitTypeFormItem type="tpm" name="tpm_type" onChange={onChange} />
</Wrapper>
);
await user.click(screen.getByRole("combobox"));
await user.click(screen.getByText("Guaranteed throughput"));
expect(onChange).toHaveBeenCalledWith("guaranteed_throughput");
});
});