diff --git a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.integration.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.integration.test.tsx
index bffc7b0fbc8..dad8599e967 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.integration.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.integration.test.tsx
@@ -5,6 +5,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
import AddAgentForm from "./add_agent_form";
import * as networking from "@/components/networking";
import type { AgentCreateInfo } from "@/components/networking";
+import { chooseSelectOption } from "../../../../../tests/test-utils";
vi.mock("@/components/networking", () => ({
createAgentCall: vi.fn(),
@@ -309,8 +310,7 @@ describe("AddAgentForm submit payload", () => {
await user.type(await screen.findByLabelText("Allowed Models"), "gpt-4o,");
await user.keyboard("{Escape}");
- await user.click(screen.getByLabelText("Allowed Agents (Sub-Agents)"));
- await user.click(await screen.findByTitle("Sub Agent One"));
+ await chooseSelectOption(user, screen.getByLabelText("Allowed Agents (Sub-Agents)"), "Sub Agent One");
await user.keyboard("{Escape}");
await user.click(screen.getByText(/Configure which models, agents, and MCP tools/));
await user.click(screen.getByRole("button", { name: /^Next/ }));
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/budget_modal.integration.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/budget_modal.integration.test.tsx
index bc920e55abd..17a297d203d 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/budget_modal.integration.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/budget_modal.integration.test.tsx
@@ -4,6 +4,7 @@ import React from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import BudgetModal from "./budget_modal";
+import { chooseSelectOption } from "../../../../../tests/test-utils";
const { createMock } = vi.hoisted(() => ({ createMock: vi.fn() }));
@@ -63,8 +64,7 @@ describe("BudgetModal", () => {
await openOptionalSettings(user);
fireEvent.change(screen.getByLabelText("Max Budget (USD)"), { target: { value: "42.567" } });
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("monthly"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "monthly");
await create(user);
@@ -80,8 +80,7 @@ describe("BudgetModal", () => {
await openOptionalSettings(user);
fireEvent.change(screen.getByLabelText("Max Budget (USD)"), { target: { value: "42.567" } });
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("monthly"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "monthly");
await user.click(screen.getByText("Optional Settings"));
await waitFor(() => expect(screen.queryByLabelText("Max Budget (USD)")).not.toBeInTheDocument());
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/edit_budget_modal.integration.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/edit_budget_modal.integration.test.tsx
index 3fa96b54f1d..fe0ecfc10dd 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/edit_budget_modal.integration.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/edit_budget_modal.integration.test.tsx
@@ -6,6 +6,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
import type { components } from "@/lib/http/schema";
import EditBudgetModal from "./edit_budget_modal";
+import { chooseSelectOption } from "../../../../../tests/test-utils";
const { updateMock } = vi.hoisted(() => ({ updateMock: vi.fn() }));
@@ -73,8 +74,7 @@ describe("EditBudgetModal", () => {
await user.clear(screen.getByLabelText("Max Budget (USD)"));
fireEvent.change(screen.getByLabelText("Max Budget (USD)"), { target: { value: "42.567" } });
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("monthly"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "monthly");
await save(user);
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/coordination_redis_settings/CoordinationRedisTypeSelector.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/coordination_redis_settings/CoordinationRedisTypeSelector.test.tsx
index 76287e6e724..563c684237a 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/coordination_redis_settings/CoordinationRedisTypeSelector.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/coordination_redis_settings/CoordinationRedisTypeSelector.test.tsx
@@ -5,6 +5,7 @@ import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "@/../tests/test-utils";
import CoordinationRedisTypeSelector from "./CoordinationRedisTypeSelector";
import { COORDINATION_REDIS_TYPE_DESCRIPTIONS } from "./coordinationRedisFields";
+import { chooseSelectOption } from "../../../../../../tests/test-utils";
describe("CoordinationRedisTypeSelector", () => {
it("labels the control and shows the current selection", () => {
@@ -36,8 +37,7 @@ describe("CoordinationRedisTypeSelector", () => {
const user = userEvent.setup();
renderWithProviders();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Cluster"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Cluster");
expect(onTypeChange).toHaveBeenCalledTimes(1);
expect(onTypeChange.mock.calls[0][0]).toBe("cluster");
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/ShadowEvalSection.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/ShadowEvalSection.test.tsx
index 64e03985f57..a1de608d0bb 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/ShadowEvalSection.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/ShadowEvalSection.test.tsx
@@ -97,6 +97,7 @@ import {
useStopShadowEval,
type ShadowEvalJob,
} from "./useShadowEval";
+import { chooseSelectOption } from "../../../../../tests/test-utils";
const job = (overrides: Partial = {}): ShadowEvalJob => ({
job_id: "job-1",
@@ -437,8 +438,7 @@ describe("ShadowEvalSection", () => {
await user.click(within(keyList).getByText("prod-alpha"));
await user.click(keyInput);
await user.click(within(keyList).getByText("staging-beta"));
- await user.click(screen.getByPlaceholderText("Select up to 4 auto-routers"));
- await user.click(await screen.findByText("gpt-auto"));
+ await chooseSelectOption(user, screen.getByPlaceholderText("Select up to 4 auto-routers"), "gpt-auto");
expect(screen.getByText("Start shadow eval")).toBeDisabled();
@@ -470,8 +470,7 @@ describe("ShadowEvalSection", () => {
await user.click(screen.getByPlaceholderText("Search teams by alias"));
const teamList = await screen.findByTestId("paginated-multi-select-list");
await user.click(within(teamList).getByText("engineering"));
- await user.click(screen.getByPlaceholderText("Select up to 4 auto-routers"));
- await user.click(await screen.findByText("gpt-auto"));
+ await chooseSelectOption(user, screen.getByPlaceholderText("Select up to 4 auto-routers"), "gpt-auto");
await user.click(screen.getByPlaceholderText("Select a judge model"));
await user.click(await screen.findByRole("option", { name: /anthropic\/claude-sonnet-5/ }));
await user.click(screen.getByText("Start shadow eval"));
@@ -502,8 +501,7 @@ describe("ShadowEvalSection", () => {
await user.click(screen.getByPlaceholderText("Search keys by alias"));
const keyList = await screen.findByTestId("paginated-multi-select-list");
await user.click(within(keyList).getByText("prod-alpha"));
- await user.click(screen.getByPlaceholderText("Select up to 4 auto-routers"));
- await user.click(await screen.findByText("gpt-auto"));
+ await chooseSelectOption(user, screen.getByPlaceholderText("Select up to 4 auto-routers"), "gpt-auto");
await user.click(screen.getByPlaceholderText("Select a judge model"));
await user.click(await screen.findByRole("option", { name: /anthropic\/claude-sonnet-5/ }));
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/ToolTestPanel.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/ToolTestPanel.test.tsx
index 26e66c8338c..81c55e7982a 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/ToolTestPanel.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/ToolTestPanel.test.tsx
@@ -6,6 +6,7 @@ import { describe, expect, it, vi } from "vitest";
import { ToolTestPanel } from "./ToolTestPanel";
import { InputSchema, MCPTool } from "@/components/mcp_tools/types";
+import { chooseSelectOption } from "../../../../../tests/test-utils";
const buildTool = (schema: InputSchema | string): MCPTool => ({
name: "demo-tool",
@@ -229,8 +230,7 @@ describe("ToolTestPanel argument payload", () => {
const onSubmit = await submitPanel(
{ type: "object", properties: { active: { type: "boolean", default: false } } },
async (user) => {
- await user.click(screen.getByLabelText("active"));
- await user.click(await screen.findByText("True"));
+ await chooseSelectOption(user, screen.getByLabelText("active"), "True");
},
);
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_test_panel.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_test_panel.test.tsx
index c8779be06c4..f23145a917a 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_test_panel.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_test_panel.test.tsx
@@ -5,6 +5,7 @@ import userEvent, { PointerEventsCheckLevel } from "@testing-library/user-event"
import { renderWithProviders } from "@/../tests/test-utils";
import * as networking from "@/components/networking";
import PolicyTestPanel from "./policy_test_panel";
+import { chooseSelectOption } from "../../../../../tests/test-utils";
vi.mock("@/components/networking");
@@ -24,8 +25,7 @@ const setup = () => {
};
const pickOption = async (user: ReturnType, label: string, option: string) => {
- await user.click(screen.getByLabelText(label));
- await user.click(await screen.findByTitle(option));
+ await chooseSelectOption(user, screen.getByLabelText(label), option);
};
const simulate = async (user: ReturnType) => {
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/index.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/index.test.tsx
index d6a4aaea2e1..3b0ee3a3ce2 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/index.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/index.test.tsx
@@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
import { deletePromptCall, getPromptsList } from "@/components/networking";
import PromptsPanel from "./index";
+import { chooseSelectOption } from "../../../../../tests/test-utils";
vi.mock("@/components/networking", () => ({
getPromptsList: vi.fn(),
@@ -118,8 +119,7 @@ describe("PromptsPanel toolbar", () => {
expect(screen.getByText("All Environments")).toBeInTheDocument();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Production"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Production");
await waitFor(() => expect(mockGetPromptsList).toHaveBeenLastCalledWith("sk-test", "production"));
});
@@ -131,12 +131,10 @@ describe("PromptsPanel toolbar", () => {
renderPanel("Admin");
await screen.findByText("table-loaded");
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Production"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Production");
await waitFor(() => expect(screen.getByRole("combobox")).toHaveTextContent("Production"));
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("All Environments"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "All Environments");
await waitFor(() => expect(screen.getByRole("combobox")).toHaveTextContent("All Environments"));
await waitFor(() => expect(mockGetPromptsList).toHaveBeenLastCalledWith("sk-test", undefined));
diff --git a/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx b/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx
index 9375673ba10..d3b9a55a7d5 100644
--- a/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx
+++ b/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx
@@ -2,7 +2,7 @@ import { fireEvent, screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, MockedFunction, vi } from "vitest";
-import { renderWithProviders } from "../../../tests/test-utils";
+import { chooseSelectOption, renderWithProviders } from "../../../tests/test-utils";
import { Team } from "../key_team_helpers/key_list";
import { TeamsResponse, useTeamsTable } from "@/app/(dashboard)/hooks/teams/useTeams";
import { TeamsTable } from "./TeamsTable";
@@ -243,8 +243,7 @@ describe("row actions", () => {
await user.click(await screen.findByText("Edit team"));
expect(onEditTeam).toHaveBeenCalledWith(expect.objectContaining({ team_id: "team-1" }));
- await user.click(screen.getByTestId("team-actions-team-1"));
- await user.click(await screen.findByText("Delete team"));
+ await chooseSelectOption(user, screen.getByTestId("team-actions-team-1"), "Delete team", "menuitem");
expect(onDeleteTeam).toHaveBeenCalledWith(expect.objectContaining({ team_id: "team-1" }));
});
diff --git a/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx b/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx
index d09ccbf8826..b06448912d0 100644
--- a/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx
+++ b/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx
@@ -2,7 +2,7 @@ import { screen, waitFor, within, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import type { OnUrlUpdateFunction } from "nuqs/adapters/testing";
import { vi, it, expect, beforeEach, describe, Mock, MockedFunction } from "vitest";
-import { renderWithProviders } from "../../../tests/test-utils";
+import { chooseSelectOption, renderWithProviders } from "../../../tests/test-utils";
import { VirtualKeysTable } from "./VirtualKeysTable";
import { KeyResponse, Team } from "../key_team_helpers/key_list";
import { useKeyInfo } from "@/app/(dashboard)/hooks/keys/useKeyInfo";
@@ -327,8 +327,7 @@ it("sorts by the backend max_budget field when 'Budget descending' is chosen fro
const user = userEvent.setup();
renderWithProviders();
- await user.click(screen.getByTestId("sort-trigger-spend"));
- await user.click(await screen.findByText("Budget descending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-spend"), "Budget descending", "menuitem");
await waitFor(() => {
expect(mockUseKeys).toHaveBeenLastCalledWith(
@@ -343,8 +342,7 @@ it("emphasizes the active field in the Spend / Budget header so the sorted colum
const user = userEvent.setup();
renderWithProviders();
- await user.click(screen.getByTestId("sort-trigger-spend"));
- await user.click(await screen.findByText("Budget descending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-spend"), "Budget descending", "menuitem");
await waitFor(() => {
expect(screen.getByText("Budget", { selector: "[data-sort-field='max_budget']" })).toHaveClass("font-semibold");
@@ -356,8 +354,7 @@ it("sorts by spend ascending when 'Spend ascending' is chosen from the Spend / B
const user = userEvent.setup();
renderWithProviders();
- await user.click(screen.getByTestId("sort-trigger-spend"));
- await user.click(await screen.findByText("Spend ascending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-spend"), "Spend ascending", "menuitem");
await waitFor(() => {
expect(mockUseKeys).toHaveBeenLastCalledWith(1, 50, expect.objectContaining({ sortBy: "spend", sortOrder: "asc" }));
diff --git a/ui/litellm-dashboard/src/components/add_pass_through.integration.test.tsx b/ui/litellm-dashboard/src/components/add_pass_through.integration.test.tsx
index df4dbff4111..daaacd7f0e2 100644
--- a/ui/litellm-dashboard/src/components/add_pass_through.integration.test.tsx
+++ b/ui/litellm-dashboard/src/components/add_pass_through.integration.test.tsx
@@ -1,6 +1,6 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import userEvent, { PointerEventsCheckLevel } from "@testing-library/user-event";
-import { fireEvent, renderWithProviders, screen, waitFor } from "../../tests/test-utils";
+import { chooseSelectOption, fireEvent, renderWithProviders, screen, waitFor } from "../../tests/test-utils";
import AddPassThroughEndpoint from "./add_pass_through";
const createPassThroughEndpoint = vi.fn();
@@ -153,8 +153,7 @@ describe("add_pass_through submit payload", () => {
await openModal(user);
await fillRequiredFields(user);
- await user.click(screen.getByLabelText(/HTTP Methods/));
- await user.click(await screen.findByTitle("POST"));
+ await chooseSelectOption(user, screen.getByLabelText(/HTTP Methods/), "POST");
await submit(user);
diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx
index 6e627e3b45c..df21444cbad 100644
--- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx
+++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx
@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import userEvent, { PointerEventsCheckLevel } from "@testing-library/user-event";
import { describe, expect, it, vi, beforeEach } from "vitest";
-import { fireEvent, renderWithProviders, screen, waitFor } from "../../../tests/test-utils";
+import { chooseSelectOption, fireEvent, renderWithProviders, screen, waitFor } from "../../../tests/test-utils";
import KeyLifecycleSettings from "./KeyLifecycleSettings";
const CREATE_PLACEHOLDER = "e.g., 30d or leave empty to never expire";
@@ -167,8 +167,7 @@ describe("KeyLifecycleSettings", () => {
await user.click(screen.getByRole("switch"));
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("90 days"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "90 days");
await waitFor(() => expect(screen.getAllByTitle("90 days").some(isRenderedSelection)).toBe(true));
expect(screen.getByTestId("rotation-interval-value")).toHaveTextContent("90d");
@@ -181,8 +180,7 @@ describe("KeyLifecycleSettings", () => {
await user.click(screen.getByRole("switch"));
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Custom interval"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Custom interval");
expect(await screen.findByPlaceholderText("e.g., 1s, 5m, 2h, 14d")).toBeInTheDocument();
expect(screen.getByText("Supported formats: seconds (s), minutes (m), hours (h), days (d)")).toBeInTheDocument();
@@ -196,8 +194,7 @@ describe("KeyLifecycleSettings", () => {
await user.click(screen.getByRole("switch"));
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Custom interval"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Custom interval");
const customInput = await screen.findByPlaceholderText("e.g., 1s, 5m, 2h, 14d");
fireEvent.change(customInput, { target: { value: "14d" } });
@@ -213,14 +210,12 @@ describe("KeyLifecycleSettings", () => {
await user.click(screen.getByRole("switch"));
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Custom interval"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Custom interval");
const customInput = await screen.findByPlaceholderText("e.g., 1s, 5m, 2h, 14d");
fireEvent.change(customInput, { target: { value: "14d" } });
await waitFor(() => expect(screen.getByTestId("rotation-interval-value")).toHaveTextContent("14d"));
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("7 days"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "7 days");
await waitFor(() => expect(screen.getByTestId("rotation-interval-value")).toHaveTextContent("7d"));
expect(screen.queryByPlaceholderText("e.g., 1s, 5m, 2h, 14d")).not.toBeInTheDocument();
diff --git a/ui/litellm-dashboard/src/components/common_components/ModelSelector.test.tsx b/ui/litellm-dashboard/src/components/common_components/ModelSelector.test.tsx
index bd7b56f1817..7a5db4667e9 100644
--- a/ui/litellm-dashboard/src/components/common_components/ModelSelector.test.tsx
+++ b/ui/litellm-dashboard/src/components/common_components/ModelSelector.test.tsx
@@ -2,6 +2,7 @@ import { act, fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, describe, expect, it, vi } from "vitest";
import ModelSelector from "./ModelSelector";
+import { chooseSelectOption } from "../../../tests/test-utils";
vi.mock("@/components/llm_calls/fetch_models", () => ({
fetchAvailableModels: vi.fn().mockResolvedValue([]),
@@ -9,8 +10,7 @@ vi.mock("@/components/llm_calls/fetch_models", () => ({
const openCustomModelInput = async () => {
const user = userEvent.setup();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Enter custom model"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Enter custom model");
return screen.getByPlaceholderText("Enter custom model name");
};
diff --git a/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx b/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx
index 7ead9bb64d4..f502ea77127 100644
--- a/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx
+++ b/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx
@@ -7,6 +7,7 @@ import { describe, expect, it, vi } from "vitest";
import { DataTable } from "./DataTable";
import { DataTableMultiSortHeader, DataTableSortHeader } from "./DataTableSortHeader";
import { DataTableViewOptions } from "./DataTableViewOptions";
+import { chooseSelectOption } from "../../../../tests/test-utils";
interface Person {
id: string;
@@ -176,16 +177,13 @@ describe("DataTable sorting", () => {
const user = userEvent.setup();
render();
- await user.click(screen.getByTestId("sort-trigger-name"));
- await user.click(await screen.findByText("Ascending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-name"), "Ascending", "menuitem");
expect(names()).toEqual(["Alice", "Bob", "Charlie"]);
- await user.click(screen.getByTestId("sort-trigger-name"));
- await user.click(await screen.findByText("Descending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-name"), "Descending", "menuitem");
expect(names()).toEqual(["Charlie", "Bob", "Alice"]);
- await user.click(screen.getByTestId("sort-trigger-name"));
- await user.click(await screen.findByText("Reset"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-name"), "Reset", "menuitem");
expect(names()).toEqual(["Charlie", "Alice", "Bob"]);
});
@@ -202,12 +200,10 @@ describe("DataTable sorting", () => {
/>,
);
- await user.click(screen.getByTestId("sort-trigger-spend"));
- await user.click(await screen.findByText("Budget descending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-spend"), "Budget descending", "menuitem");
expect(onSortingChange).toHaveBeenLastCalledWith([{ id: "max_budget", desc: true }]);
- await user.click(screen.getByTestId("sort-trigger-spend"));
- await user.click(await screen.findByText("Spend ascending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-spend"), "Spend ascending", "menuitem");
expect(onSortingChange).toHaveBeenLastCalledWith([{ id: "spend", desc: false }]);
});
diff --git a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx
index 70403ba2efe..aeb6fa44e91 100644
--- a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx
+++ b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx
@@ -13,6 +13,7 @@ import { useState } from "react";
import { describe, expect, it, vi } from "vitest";
import { DataTableSortHeader, type DataTableSortVariant } from "./DataTableSortHeader";
+import { chooseSelectOption } from "../../../../tests/test-utils";
interface Item {
name: string;
@@ -84,16 +85,13 @@ describe("DataTableSortHeader", () => {
const user = userEvent.setup();
render();
- await user.click(screen.getByTestId("sort-trigger-name"));
- await user.click(await screen.findByText("Descending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-name"), "Descending", "menuitem");
expect(screen.getByTestId("sort-trigger-name").querySelector('[data-sort-indicator="desc"]')).not.toBeNull();
- await user.click(screen.getByTestId("sort-trigger-name"));
- await user.click(await screen.findByText("Ascending"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-name"), "Ascending", "menuitem");
expect(screen.getByTestId("sort-trigger-name").querySelector('[data-sort-indicator="asc"]')).not.toBeNull();
- await user.click(screen.getByTestId("sort-trigger-name"));
- await user.click(await screen.findByText("Reset"));
+ await chooseSelectOption(user, screen.getByTestId("sort-trigger-name"), "Reset", "menuitem");
expect(screen.getByTestId("sort-trigger-name").querySelector('[data-sort-indicator="none"]')).not.toBeNull();
});
diff --git a/ui/litellm-dashboard/src/components/shared/PaginatedSearchSelect.test.tsx b/ui/litellm-dashboard/src/components/shared/PaginatedSearchSelect.test.tsx
index d248cf311cc..04c8d3e9012 100644
--- a/ui/litellm-dashboard/src/components/shared/PaginatedSearchSelect.test.tsx
+++ b/ui/litellm-dashboard/src/components/shared/PaginatedSearchSelect.test.tsx
@@ -5,6 +5,7 @@ import { describe, expect, it, vi } from "vitest";
import { PaginatedSearchSelect } from "./PaginatedSearchSelect";
import type { SearchSelectOption } from "./SearchSelect";
+import { chooseSelectOption } from "../../../tests/test-utils";
const OPTIONS: SearchSelectOption[] = [
{ label: "alias-alpha", value: "alias-alpha" },
@@ -63,8 +64,7 @@ describe("PaginatedSearchSelect", () => {
}
render();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("alias-beta"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "alias-beta");
expect(screen.getByRole("combobox")).toHaveValue("alias-beta");
await new Promise((resolve) => setTimeout(resolve, 400));
@@ -136,8 +136,7 @@ describe("PaginatedSearchSelect", () => {
const onValueChange = vi.fn();
renderSelect({ onValueChange });
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("alias-beta"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "alias-beta");
expect(onValueChange).toHaveBeenCalledWith("alias-beta");
});
@@ -255,8 +254,7 @@ describe("PaginatedSearchSelect", () => {
}
render();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Beta Team"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Beta Team");
await user.click(screen.getByRole("button", { name: "refetch" }));
expect(screen.getByRole("combobox")).toHaveValue("Beta Team");
diff --git a/ui/litellm-dashboard/src/components/shared/SearchSelect.test.tsx b/ui/litellm-dashboard/src/components/shared/SearchSelect.test.tsx
index c0b9bc7d8ae..62a510268dd 100644
--- a/ui/litellm-dashboard/src/components/shared/SearchSelect.test.tsx
+++ b/ui/litellm-dashboard/src/components/shared/SearchSelect.test.tsx
@@ -3,6 +3,7 @@ import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { SearchSelect } from "./SearchSelect";
+import { chooseSelectOption } from "../../../tests/test-utils";
const OPTIONS = [
{ label: "Acme Prod", value: "team-1" },
@@ -71,8 +72,7 @@ describe("SearchSelect", () => {
const onValueChange = vi.fn();
const user = userEvent.setup();
render();
- await user.click(screen.getByRole("combobox"));
- await user.click(await screen.findByText("Growth"));
+ await chooseSelectOption(user, screen.getByRole("combobox"), "Growth");
expect(onValueChange).toHaveBeenCalledWith("team-2");
});
diff --git a/ui/litellm-dashboard/src/components/view_logs/RequestLogsFilters.test.tsx b/ui/litellm-dashboard/src/components/view_logs/RequestLogsFilters.test.tsx
index e0ec66e1ae2..5a35c7ae16b 100644
--- a/ui/litellm-dashboard/src/components/view_logs/RequestLogsFilters.test.tsx
+++ b/ui/litellm-dashboard/src/components/view_logs/RequestLogsFilters.test.tsx
@@ -3,7 +3,7 @@ import userEvent from "@testing-library/user-event";
import { useState } from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
-import { renderWithProviders, testQueryClient } from "../../../tests/test-utils";
+import { chooseSelectOption, renderWithProviders, testQueryClient } from "../../../tests/test-utils";
import { ERROR_CODE_OPTIONS } from "./constants";
import { LOG_FILTER_IDS } from "./log_filter_logic";
import { RequestLogsFilters } from "./RequestLogsFilters";
@@ -125,8 +125,7 @@ describe("RequestLogsFilters", () => {
const user = userEvent.setup();
const { set } = renderFilters();
- await user.click(await screen.findByPlaceholderText("Search an internal user"));
- await user.click(await screen.findByText("alice@example.com"));
+ await chooseSelectOption(user, await screen.findByPlaceholderText("Search an internal user"), "alice@example.com");
expect(set).toHaveBeenCalledWith(LOG_FILTER_IDS.USER_ID, "alice@example.com");
});
diff --git a/ui/litellm-dashboard/tests/test-utils.tsx b/ui/litellm-dashboard/tests/test-utils.tsx
index 162b8a3df7b..31af51f3f32 100644
--- a/ui/litellm-dashboard/tests/test-utils.tsx
+++ b/ui/litellm-dashboard/tests/test-utils.tsx
@@ -45,19 +45,22 @@ const pointerBlocked = (element: HTMLElement): boolean => {
};
/**
- * Opens a Base UI Select and picks an option by its accessible name.
+ * Opens a Base UI popup and picks an entry by its accessible name.
*
- * The option is in the DOM one render before the popup finishes entering, and until then its
- * positioner still carries `pointer-events: none`, which user-event refuses to click. Waiting on
- * the option text alone is a race that React 19's flush timing loses.
+ * Querying the entry by text or by a title attribute matches the moment the node exists, which is
+ * one render before the popup finishes entering. Until then the positioner still carries
+ * `pointer-events: none` and user-event refuses to click, so that shape is a race a fast machine
+ * loses. The role query only matches once the popup is open to the accessibility tree, which is
+ * what makes this wait correct rather than lucky.
*/
export const chooseSelectOption = async (
user: Pick, "click">,
trigger: HTMLElement,
optionName: string | RegExp,
+ role: "option" | "menuitem" | "menuitemradio" = "option",
) => {
await user.click(trigger);
- const option = await screen.findByRole("option", { name: optionName });
+ const option = await screen.findByRole(role, { name: optionName });
await waitFor(() => expect(pointerBlocked(option)).toBe(false));
await user.click(option);
};