{
expect(screen.getByRole("button", { name: /docs/i })).toBeInTheDocument();
});
+ it("should hide menu items initially", () => {
+ renderWithProviders();
+ expect(screen.queryByText("Custom pricing")).not.toBeInTheDocument();
+ });
+
it("should show menu items when button is clicked", async () => {
const user = userEvent.setup();
renderWithProviders();
diff --git a/ui/litellm-dashboard/src/components/ToolPolicies/PolicySelect.test.tsx b/ui/litellm-dashboard/src/components/ToolPolicies/PolicySelect.test.tsx
new file mode 100644
index 00000000000..cde59fe9c6d
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/ToolPolicies/PolicySelect.test.tsx
@@ -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(
+
+ );
+ expect(screen.getByText("untrusted")).toBeInTheDocument();
+ });
+
+ it("should show the current policy value", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("trusted")).toBeInTheDocument();
+ });
+
+ it("should be disabled when saving is true", () => {
+ renderWithProviders(
+
+ );
+ 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(
+
+ );
+ 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"]);
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/add_model/ComplexityRouterConfig.test.tsx b/ui/litellm-dashboard/src/components/add_model/ComplexityRouterConfig.test.tsx
new file mode 100644
index 00000000000..59d8721b143
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/add_model/ComplexityRouterConfig.test.tsx
@@ -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(
+
+ );
+ expect(screen.getByText("Complexity Tier Configuration")).toBeInTheDocument();
+ });
+
+ it("should display all four tier labels", () => {
+ renderWithProviders(
+
+ );
+ 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(
+
+ );
+ 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(
+
+ );
+ expect(screen.getByText("How Classification Works")).toBeInTheDocument();
+ });
+
+ it("should show score thresholds in the classification section", () => {
+ renderWithProviders(
+
+ );
+ 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();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx b/ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx
new file mode 100644
index 00000000000..c8a21d1b6e8
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx
@@ -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) => (
+ onAgentClick(agent.agent_id)}>
+ {agent.agent_name}
+
+ ),
+}));
+
+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 = {
+ "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();
+ expect(screen.getByText("Test Agent 1")).toBeInTheDocument();
+ });
+
+ it("should render all agent cards", () => {
+ renderWithProviders();
+ expect(screen.getByText("Test Agent 1")).toBeInTheDocument();
+ expect(screen.getByText("Test Agent 2")).toBeInTheDocument();
+ });
+
+ it("should show loading skeletons when isLoading is true", () => {
+ renderWithProviders();
+ expect(screen.queryByText("Test Agent 1")).not.toBeInTheDocument();
+ });
+
+ it("should show admin empty state message when no agents and isAdmin", () => {
+ renderWithProviders(
+
+ );
+ 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(
+
+ );
+ 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(
+
+ );
+ 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");
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/common_components/RateLimitTypeFormItem.test.tsx b/ui/litellm-dashboard/src/components/common_components/RateLimitTypeFormItem.test.tsx
new file mode 100644
index 00000000000..49b8028c510
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/common_components/RateLimitTypeFormItem.test.tsx
@@ -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 }) => (
+
+);
+
+describe("RateLimitTypeFormItem", () => {
+ it("should render", () => {
+ renderWithProviders(
+
+
+
+ );
+ expect(screen.getByText(/TPM Rate Limit Type/)).toBeInTheDocument();
+ });
+
+ it("should display TPM label for tpm type", () => {
+ renderWithProviders(
+
+
+
+ );
+ expect(screen.getByText(/TPM Rate Limit Type/)).toBeInTheDocument();
+ });
+
+ it("should display RPM label for rpm type", () => {
+ renderWithProviders(
+
+
+
+ );
+ expect(screen.getByText(/RPM Rate Limit Type/)).toBeInTheDocument();
+ });
+
+ it("should show the select placeholder by default", () => {
+ renderWithProviders(
+
+
+
+ );
+ expect(screen.getByText("Select rate limit type")).toBeInTheDocument();
+ });
+
+ it("should call onChange when provided", async () => {
+ const user = userEvent.setup();
+ const onChange = vi.fn();
+ renderWithProviders(
+
+
+
+ );
+ await user.click(screen.getByRole("combobox"));
+ await user.click(screen.getByText("Guaranteed throughput"));
+ expect(onChange).toHaveBeenCalledWith("guaranteed_throughput");
+ });
+});