test(ui): assert presence and state so dashboard tests fail when behaviour breaks

One test could not fail: it asserted on the Promise returned by an unawaited
findAllByText, and a pending Promise is always truthy, so the organization
detail view had no working coverage at all.

Rewrites 316 assertions across 128 files onto matchers that describe what the
user perceives, and awaits the queries that were being compared as Promises.

Most of this was mechanical, but the fixers behind these rules are not
trustworthy, so every site they damaged was repaired by hand. The quiet one
worth naming: prefer-to-have-text-content wraps strings in new RegExp() without
escaping, turning toContain("100K+ requests") into a pattern meaning "100
followed by one-or-more K". That compiles, lints clean, and keeps passing while
no longer asserting what it claims.
This commit is contained in:
Yuneng Jiang 2026-08-15 02:24:12 -07:00 committed by yuneng-jiang
parent 32e6346455
commit 6670061a33
128 changed files with 371 additions and 404 deletions

View file

@ -33,7 +33,7 @@ describe("AgentControlPlaneView iframe", () => {
expect(src).toBe("http://localhost:3300/");
expect(src).not.toContain("/sessions");
// title comes from the plugin's display_name, not a hardcoded label
expect(iframe!.getAttribute("title")).toBe("Chat UI");
expect(iframe!).toHaveAttribute("title", "Chat UI");
});
it("does not double the slash when the plugin url has a trailing slash", () => {
@ -43,7 +43,7 @@ describe("AgentControlPlaneView iframe", () => {
url: "http://localhost:3300/",
};
const { container } = render(<AgentControlPlaneView />);
expect(container.querySelector("iframe")!.getAttribute("src")).toBe("http://localhost:3300/");
expect(container.querySelector("iframe")!).toHaveAttribute("src", "http://localhost:3300/");
pluginModeValue.activePlugin = {
name: "litellm-platform-plugin",
display_name: "Chat UI",

View file

@ -101,8 +101,8 @@ describe("AgentsTable", () => {
);
const bodyRows = screen.getAllByRole("row").slice(1);
expect(bodyRows[0].textContent).toContain("Beta Agent");
expect(bodyRows[1].textContent).toContain("Alpha Agent");
expect(bodyRows[0]).toHaveTextContent(/Beta Agent/);
expect(bodyRows[1]).toHaveTextContent(/Alpha Agent/);
});
it("sorts agents with no created_at last, never ahead of dated ones", () => {
@ -118,9 +118,9 @@ describe("AgentsTable", () => {
);
const bodyRows = screen.getAllByRole("row").slice(1);
expect(bodyRows[0].textContent).toContain("Beta Agent");
expect(bodyRows[1].textContent).toContain("Alpha Agent");
expect(bodyRows[2].textContent).toContain("Undated Agent");
expect(bodyRows[0]).toHaveTextContent(/Beta Agent/);
expect(bodyRows[1]).toHaveTextContent(/Alpha Agent/);
expect(bodyRows[2]).toHaveTextContent(/Undated Agent/);
});
it("shows a rich empty state when there are no agents", () => {

View file

@ -196,12 +196,10 @@ describe("AgentCardDiscovery", () => {
);
expect(
(
screen.getByRole("button", {
name: /discover/i,
}) as HTMLButtonElement
).disabled,
).toBe(true);
screen.getByRole("button", {
name: /discover/i,
}),
).toBeDisabled();
expect(mockDiscover).not.toHaveBeenCalled();
});

View file

@ -16,7 +16,7 @@ describe("APIReferenceView", () => {
const { getAllByTestId } = render(<APIReferenceView proxySettings={{ LITELLM_UI_API_DOC_BASE_URL: apiDocUrl }} />);
const codeBlocks = getAllByTestId(codeBlockTestId);
expect(codeBlocks[0].textContent).toContain(apiDocUrl);
expect(codeBlocks[0]).toHaveTextContent(new RegExp(apiDocUrl));
});
it("falls back to the proxy base url when the docs url is missing", () => {
@ -24,7 +24,7 @@ describe("APIReferenceView", () => {
const { getAllByTestId } = render(<APIReferenceView proxySettings={{ PROXY_BASE_URL: proxyUrl }} />);
const codeBlocks = getAllByTestId(codeBlockTestId);
expect(codeBlocks[0].textContent).toContain(proxyUrl);
expect(codeBlocks[0]).toHaveTextContent(new RegExp(proxyUrl));
});
it("prefers the docs url when both urls are provided", () => {
@ -49,12 +49,12 @@ describe("APIReferenceView", () => {
it("renders the page title, blurb and docs link", () => {
render(<APIReferenceView proxySettings={{ PROXY_BASE_URL: "https://proxy.litellm.test" }} />);
expect(screen.getByText("OpenAI Compatible Proxy: API Reference")).toBeTruthy();
expect(screen.getByText(/LiteLLM is OpenAI Compatible/)).toBeTruthy();
expect(screen.getByText("OpenAI Compatible Proxy: API Reference")).toBeInTheDocument();
expect(screen.getByText(/LiteLLM is OpenAI Compatible/)).toBeInTheDocument();
const docsLink = screen.getByRole("link", { name: /API Reference Docs/ });
expect(docsLink.getAttribute("href")).toBe("https://docs.litellm.ai/docs/proxy/user_keys");
expect(docsLink.getAttribute("target")).toBe("_blank");
expect(docsLink).toHaveAttribute("href", "https://docs.litellm.ai/docs/proxy/user_keys");
expect(docsLink).toHaveAttribute("target", "_blank");
});
it("exposes the three SDK tabs with the first selected by default", () => {
@ -83,10 +83,10 @@ describe("APIReferenceView", () => {
await user.click(screen.getByRole("tab", { name: tabName }));
expect(screen.getByRole("tab", { name: tabName }).getAttribute("aria-selected")).toBe("true");
expect(screen.getByRole("tab", { name: tabName })).toHaveAttribute("aria-selected", "true");
const selectedPanel = screen.getByRole("tabpanel");
expect(selectedPanel.textContent).toContain(marker);
expect(selectedPanel.textContent).toContain(proxyUrl);
expect(selectedPanel).toHaveTextContent(new RegExp(marker));
expect(selectedPanel).toHaveTextContent(new RegExp(proxyUrl));
});
});

View file

@ -105,7 +105,7 @@ describe("BudgetTable", () => {
const list = makeList({ rows: [makeBudget({ budget_id: budgetId })] });
renderWithProviders(<BudgetTable {...defaultProps} list={list} />);
const idCell = screen.getByText(budgetId);
expect(idCell.className).not.toContain("truncate");
expect(idCell).not.toHaveClass("truncate");
expect(idCell.className).not.toMatch(/max-w-\[\d+(ch|rem|px)\]/);
});
@ -113,7 +113,7 @@ describe("BudgetTable", () => {
const budgetId = "ecc1869c-6231-4380-a56d-1a0be457477d";
const list = makeList({ rows: [makeBudget({ budget_id: budgetId })] });
renderWithProviders(<BudgetTable {...defaultProps} list={list} />);
expect(screen.getByText(budgetId).className).toContain("whitespace-nowrap");
expect(screen.getByText(budgetId)).toHaveClass("whitespace-nowrap");
});
it("should copy the budget id from the cell's copy button", async () => {

View file

@ -52,7 +52,7 @@ describe("CostOptimizationView daily activity", () => {
useAuthorizedMock.mockReturnValue({ accessToken: "test-token", userId: "u1", userRole: "proxy_admin" });
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
const { getByRole, getByTestId } = render(
const { getByRole, getByTestId, findByTestId } = render(
<QueryClientProvider client={queryClient}>
<CostOptimizationView accessToken="test-token" userId="u1" userRole="proxy_admin" />
</QueryClientProvider>,
@ -61,7 +61,7 @@ describe("CostOptimizationView daily activity", () => {
await waitFor(() => expect(mockUserDailyActivityCall).toHaveBeenCalledTimes(1));
fireEvent.click(getByRole("tab", { name: "Prompt Caching" }));
await waitFor(() => expect(getByTestId("caching-settings")).toBeInTheDocument());
await findByTestId("caching-settings");
expect(mockUserDailyActivityCall).toHaveBeenCalledTimes(1);
});

View file

@ -218,7 +218,7 @@ describe("UsageTab", () => {
// Per day switches to a bar chart of the unaccumulated daily savings, with no
// synthetic anchor prepended.
expect(queryByTestId("area-chart")).toBeNull();
expect(queryByTestId("area-chart")).not.toBeInTheDocument();
const series = readSeries(getByTestId("bar-chart"));
expect(series).toHaveLength(2);
expect(series[0]).toMatchObject({ Compression: 0.04, "Prompt caching": 0.006 });
@ -264,7 +264,7 @@ describe("UsageTab", () => {
await userEvent.click(getByRole("tab", { name: "Per day" }));
const bars = getByTestId("bar-chart");
expect(bars.getAttribute("data-stack")).toBe("false");
expect(bars).toHaveAttribute("data-stack", "false");
expect(readSeries(bars)[0]).toMatchObject({ "Auto-router": -0.05 });
});
@ -290,7 +290,7 @@ describe("UsageTab", () => {
expect(before.action.contains(getByRole("tablist"))).toBe(true);
// the subtitle lives outside that slot, so its length cannot reposition the controls
expect(before.action.contains(before.description)).toBe(false);
expect(before.description.textContent).toContain("Running total saved");
expect(before.description).toHaveTextContent(/Running total saved/);
await userEvent.click(getByRole("tab", { name: "Per day" }));
@ -298,8 +298,8 @@ describe("UsageTab", () => {
expect(after.action).toBe(before.action);
expect(after.cardHeader).toBe(before.cardHeader);
expect(after.action.contains(after.description)).toBe(false);
expect(after.description.textContent).toContain("Saved per day");
expect(container.textContent).toContain("Savings");
expect(after.description).toHaveTextContent(/Saved per day/);
expect(container).toHaveTextContent(/Savings/);
});
it("subtracts a losing auto-router route from the total and keeps it out of the donut", () => {
@ -319,7 +319,7 @@ describe("UsageTab", () => {
const slices = JSON.parse(getByTestId("donut-chart").getAttribute("data-slices") ?? "[]");
expect(slices.map((d: { driver: string }) => d.driver)).toEqual(["Compression", "Prompt caching"]);
expect(getByTestId("donut-chart").getAttribute("data-label")).toBe("$0.1200");
expect(getByTestId("donut-chart")).toHaveAttribute("data-label", "$0.1200");
});
it("carries auto-router savings into the summary card, donut slice, and cumulative series", () => {
@ -370,7 +370,7 @@ describe("UsageTab", () => {
expect(series[0]).toMatchObject({ tool_name: "search", spend: 4.0 });
// The 64px bar cap is this card's opt-in; the shared BarChart must not cap
// by default (other consumers keep their pre-existing geometry).
expect(bars[0].getAttribute("data-max-bar-size")).toBe("64");
expect(bars[0]).toHaveAttribute("data-max-bar-size", "64");
});
it("renders the tool legend once outside the charts, with both charts sharing the tool colors", async () => {
@ -387,8 +387,8 @@ describe("UsageTab", () => {
const bars = await findAllByTestId("bar-chart");
const [totalByTool, dailyByTool] = bars.slice(-2);
expect(dailyByTool.getAttribute("data-show-legend")).toBe("false");
expect(totalByTool.getAttribute("data-colors")).toBe(dailyByTool.getAttribute("data-colors"));
expect(dailyByTool).toHaveAttribute("data-show-legend", "false");
expect(totalByTool).toHaveAttribute("data-colors", dailyByTool.getAttribute("data-colors"));
const toolLegends = getAllByTestId("chart-legend").filter((legend) => legend.textContent === "search,read_file");
expect(toolLegends).toHaveLength(1);

View file

@ -67,7 +67,7 @@ describe("AddMarginForm", () => {
it("should enable the submit button when provider and percentage value are both provided", () => {
renderWithProviders(<AddMarginForm {...DEFAULT_PROPS} selectedProvider="OpenAI" percentageValue="10" />);
expect(screen.getByRole("button", { name: /add provider margin/i })).not.toBeDisabled();
expect(screen.getByRole("button", { name: /add provider margin/i })).toBeEnabled();
});
it("should disable the submit button in fixed mode when no fixed amount is provided", () => {
@ -81,7 +81,7 @@ describe("AddMarginForm", () => {
renderWithProviders(
<AddMarginForm {...DEFAULT_PROPS} selectedProvider="OpenAI" marginType="fixed" fixedAmountValue="0.001" />,
);
expect(screen.getByRole("button", { name: /add provider margin/i })).not.toBeDisabled();
expect(screen.getByRole("button", { name: /add provider margin/i })).toBeEnabled();
});
it("should call onAddProvider when the enabled submit button is clicked", async () => {

View file

@ -48,7 +48,7 @@ describe("AddProviderForm", () => {
it("should enable the submit button when both a provider and a discount value are provided", () => {
renderWithProviders(<AddProviderForm {...DEFAULT_PROPS} selectedProvider="OpenAI" newDiscount="5" />);
expect(screen.getByRole("button", { name: /add provider discount/i })).not.toBeDisabled();
expect(screen.getByRole("button", { name: /add provider discount/i })).toBeEnabled();
});
it("should call onAddProvider when the enabled submit button is clicked", async () => {
@ -71,7 +71,7 @@ describe("AddProviderForm", () => {
renderWithProviders(<AddProviderForm {...DEFAULT_PROPS} selectedProvider="OpenAI" />);
const logo = await screen.findByRole("img", { name: `${Providers.OpenAI} logo` });
expect(logo.getAttribute("src")).toBe(providerLogoMap[Providers.OpenAI]);
expect(logo).toHaveAttribute("src", providerLogoMap[Providers.OpenAI]);
});
it("falls back to a letter avatar for a selected provider that has no bundled logo", () => {

View file

@ -73,7 +73,7 @@ describe("CostTrackingSettings", () => {
const { container } = renderWithProviders(
<CostTrackingSettings userID="user-1" userRole="proxy_admin" accessToken={null} />,
);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should render the page title", () => {

View file

@ -32,7 +32,7 @@ describe("HowItWorks", () => {
it("should render the code block with a curl example", () => {
renderWithProviders(<HowItWorks />);
expect(screen.getByTestId("code-block")).toBeInTheDocument();
expect(screen.getByTestId("code-block").textContent).toContain("curl");
expect(screen.getByTestId("code-block")).toHaveTextContent(/curl/);
});
it("should show the response header names for discount verification", () => {

View file

@ -63,7 +63,7 @@ describe("MultiExportDropdown", () => {
it("should not render anything when no entries have results", () => {
const { container } = renderWithProviders(<MultiExportDropdown multiResult={makeMultiResult(false)} />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should render the Export button when at least one entry has a result", () => {

View file

@ -68,7 +68,7 @@ describe("ProviderMarginTable", () => {
/>,
);
const logo = screen.getByRole("img", { name: `${Providers.OpenAI} logo` });
expect(logo.getAttribute("src")).toBe(providerLogoMap[Providers.OpenAI]);
expect(logo).toHaveAttribute("src", providerLogoMap[Providers.OpenAI]);
});
it("should fall back to a letter avatar for a provider with no bundled logo", () => {

View file

@ -32,7 +32,7 @@ describe("GuardrailsMonitorView", () => {
render(<GuardrailsMonitorView accessToken="test-token" />, { wrapper });
expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeDefined();
expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeInTheDocument();
await waitFor(() => {
expect(mockGetGuardrailsUsageOverview).toHaveBeenCalled();
});
@ -40,6 +40,6 @@ describe("GuardrailsMonitorView", () => {
it("should render without crashing when accessToken is null", async () => {
render(<GuardrailsMonitorView accessToken={null} />, { wrapper });
expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeDefined();
expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeInTheDocument();
});
});

View file

@ -53,6 +53,6 @@ describe("AddGuardrailForm provider options", () => {
fireEvent.mouseDown(screen.getByLabelText("Guardrail Provider"));
const logo = await screen.findByAltText("Presidio PII logo");
expect(logo.getAttribute("src")).toContain("microsoft_azure.svg");
expect(logo).toHaveAttribute("src", expect.stringContaining("microsoft_azure.svg"));
});
});

View file

@ -124,7 +124,7 @@ describe("ContentFilterManager", () => {
expect(screen.queryByTestId("content-filter-config")).not.toBeInTheDocument();
expect(screen.queryByTestId("content-filter-display")).not.toBeInTheDocument();
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should render read-only display when isEditing is false", async () => {

View file

@ -56,7 +56,7 @@ describe("GuardrailCard", () => {
it("should render the logo through the shared Logo component with the card src", () => {
render(<GuardrailCard card={baseCard} onClick={vi.fn()} />);
const img = screen.getByAltText("Test Guardrail logo");
expect(img.getAttribute("src")).toContain("/logos/test.svg");
expect(img).toHaveAttribute("src", expect.stringContaining("/logos/test.svg"));
});
it("should pass a bundled static-import src through unchanged", () => {

View file

@ -109,7 +109,7 @@ describe("Guardrail Info", () => {
);
const logo = await findByAltText("Presidio PII logo");
expect(logo.getAttribute("src")).toContain("microsoft_azure.svg");
expect(logo).toHaveAttribute("src", expect.stringContaining("microsoft_azure.svg"));
});
it("should not render the edit button for config guardrails", async () => {

View file

@ -33,7 +33,7 @@ describe("GuardrailTable", () => {
it("renders the provider logo from the bundled guardrail logo map", () => {
render(<GuardrailTable guardrailsList={[makeGuardrail()]} {...baseProps} />);
const logo = screen.getByAltText("Presidio PII logo");
expect(logo.getAttribute("src")).toContain("microsoft_azure.svg");
expect(logo).toHaveAttribute("src", expect.stringContaining("microsoft_azure.svg"));
});
it("falls back to a letter avatar for an unknown provider slug", () => {

View file

@ -82,15 +82,15 @@ describe("(dashboard) Layout", () => {
</AuthProvider>,
);
await waitFor(() => expect(screen.getByTestId("loading-screen")).toBeTruthy());
expect(screen.queryByTestId("page-content")).toBeNull();
expect(screen.queryByTestId("dashboard-header")).toBeNull();
expect(await screen.findByTestId("loading-screen")).toBeInTheDocument();
expect(screen.queryByTestId("page-content")).not.toBeInTheDocument();
expect(screen.queryByTestId("dashboard-header")).not.toBeInTheDocument();
pendingUiConfig.resolve();
await waitFor(() => expect(screen.getByTestId("page-content")).toBeTruthy());
expect(screen.getByTestId("dashboard-header")).toBeTruthy();
expect(screen.queryByTestId("loading-screen")).toBeNull();
expect(await screen.findByTestId("page-content")).toBeInTheDocument();
expect(screen.getByTestId("dashboard-header")).toBeInTheDocument();
expect(screen.queryByTestId("loading-screen")).not.toBeInTheDocument();
});
it("redirects an invitation link to the onboarding route instead of rendering the dashboard shell", async () => {
@ -109,8 +109,8 @@ describe("(dashboard) Layout", () => {
await waitFor(() =>
expect(replaceMock).toHaveBeenCalledWith(expect.stringContaining("/onboarding?invitation_id=abc123")),
);
expect(screen.queryByTestId("page-content")).toBeNull();
expect(screen.queryByTestId("dashboard-header")).toBeNull();
expect(screen.queryByTestId("sidebar")).toBeNull();
expect(screen.queryByTestId("page-content")).not.toBeInTheDocument();
expect(screen.queryByTestId("dashboard-header")).not.toBeInTheDocument();
expect(screen.queryByTestId("sidebar")).not.toBeInTheDocument();
});
});

View file

@ -676,7 +676,7 @@ describe("CreateMCPServer", () => {
it("clears the DCR ref and the upstream warning when the modal closes so nothing leaks to the next session", async () => {
const { rerender } = render(<CreateMCPServer {...defaultProps} />);
await selectAntOption("Transport Type", "Streamable HTTP");
await waitFor(() => expect(screen.getByPlaceholderText("https://your-mcp-server.com")).toBeInTheDocument());
expect(await screen.findByPlaceholderText("https://your-mcp-server.com")).toBeInTheDocument();
const user = userEvent.setup({ delay: null });
await user.type(getServerNameInput(), "Leak_Server");
await user.type(screen.getByPlaceholderText("https://your-mcp-server.com"), "https://example.com/mcp");

View file

@ -69,6 +69,6 @@ describe("MCPLogoSelector", () => {
it("should preview a custom external URL untouched", () => {
render(<MCPLogoSelector value="https://cdn.example.com/logo.png" />);
expect(screen.getByAltText("Selected logo").getAttribute("src")).toBe("https://cdn.example.com/logo.png");
expect(screen.getByAltText("Selected logo")).toHaveAttribute("src", "https://cdn.example.com/logo.png");
});
});

View file

@ -48,7 +48,7 @@ describe("MCPPermissionManagement", () => {
// The first switch in the component is for allow_all_keys
const switches = screen.getAllByRole("switch");
const toggle = switches[0];
expect(toggle).toHaveAttribute("aria-checked", "false");
expect(toggle).not.toBeChecked();
});
const renderWithInitialValues = (initialValues: Record<string, unknown>, props = {}) => {
@ -122,9 +122,9 @@ describe("MCPPermissionManagement", () => {
// The first switch in the component is for allow_all_keys
const switches = screen.getAllByRole("switch");
const toggle = switches[0];
expect(toggle).toHaveAttribute("aria-checked", "true");
expect(toggle).toBeChecked();
await user.click(toggle);
expect(toggle).toHaveAttribute("aria-checked", "false");
expect(toggle).not.toBeChecked();
});
});

View file

@ -52,13 +52,13 @@ describe("MCPServerCard logo", () => {
it("passes an external logo_url through untouched", () => {
renderCard({ mcp_info: { server_name: "demo_server", logo_url: "https://cdn.example.com/logo.png" } });
expect(screen.getByAltText("demo_server logo").getAttribute("src")).toBe("https://cdn.example.com/logo.png");
expect(screen.getByAltText("demo_server logo")).toHaveAttribute("src", "https://cdn.example.com/logo.png");
});
it("prefixes a stored asset path with the server root path under a non-root mount", () => {
setServerRootPath("/litellm");
renderCard({ mcp_info: { server_name: "demo_server", logo_url: "/ui/assets/logos/github.svg" } });
expect(screen.getByAltText("demo_server logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg");
expect(screen.getByAltText("demo_server logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg");
});
it("renders a letter avatar when no logo_url is set", () => {

View file

@ -21,7 +21,7 @@ describe("MCPConnectionStatus", () => {
it("should render nothing when canFetchTools is false and no URL is set", () => {
const { container } = render(<MCPConnectionStatus {...defaultProps} formValues={{}} />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should show 'Complete required fields' message when URL is set but canFetchTools is false", () => {

View file

@ -1214,8 +1214,9 @@ describe("MCPServerEdit (tool list fetch)", () => {
);
await waitFor(() => {
expect(screen.getByTestId("mcp-tool-config").getAttribute("data-external-error")).toContain(
"Authorize with the upstream (browser-only",
expect(screen.getByTestId("mcp-tool-config")).toHaveAttribute(
"data-external-error",
expect.stringContaining("Authorize with the upstream (browser-only"),
);
});
expect(networking.listMCPTools).not.toHaveBeenCalled();
@ -1242,8 +1243,9 @@ describe("MCPServerEdit (tool list fetch)", () => {
const { rerender } = render(<MCPServerEdit {...props} />);
await waitFor(() => {
expect(screen.getByTestId("mcp-tool-config").getAttribute("data-external-error")).toContain(
"Authenticate with this server in the Tools tab",
expect(screen.getByTestId("mcp-tool-config")).toHaveAttribute(
"data-external-error",
expect.stringContaining("Authenticate with this server in the Tools tab"),
);
});
expect(networking.listMCPTools).not.toHaveBeenCalled();
@ -1277,8 +1279,9 @@ describe("MCPServerEdit (tool list fetch)", () => {
);
await waitFor(() => {
expect(screen.getByTestId("mcp-tool-config").getAttribute("data-external-error")).toContain(
"Authenticate with this server in the Tools tab",
expect(screen.getByTestId("mcp-tool-config")).toHaveAttribute(
"data-external-error",
expect.stringContaining("Authenticate with this server in the Tools tab"),
);
});
expect(networking.listMCPTools).not.toHaveBeenCalled();
@ -1657,9 +1660,7 @@ describe("MCPServerEdit (OAuth token persistence on save)", () => {
// Check "remove saved app" on server A.
fireEvent.click(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ }));
expect(
(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ }) as HTMLInputElement).checked,
).toBe(true);
expect(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ })).toBeChecked();
// Switch the panel to server B without unmounting.
rerender(
@ -1674,9 +1675,7 @@ describe("MCPServerEdit (OAuth token persistence on save)", () => {
);
// The checkbox must have reset, so saving server B does not send the explicit-null delete write.
expect(
(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ }) as HTMLInputElement).checked,
).toBe(false);
expect(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ })).not.toBeChecked();
await act(async () => {
fireEvent.click(screen.getAllByRole("button", { name: "Save Changes" })[0]);

View file

@ -76,14 +76,14 @@ describe("ModelsAndEndpointsPage", () => {
const { getByRole, getByTestId, queryByTestId } = renderPage();
await user.click(getByRole("tab", { name: "Health Status" }));
expect(getByTestId("panel-health")).toBeInTheDocument();
expect(queryByTestId("panel-all-models")).toBeNull();
expect(queryByTestId("panel-all-models")).not.toBeInTheDocument();
});
it("renders the model detail overlay from the ?model drill-in and hides the tabs", () => {
detailState.modelId = "abc-123";
const { getByTestId, queryByRole } = renderPage();
expect(getByTestId("model-info")).toHaveTextContent("model:abc-123");
expect(queryByRole("tab", { name: "All Models" })).toBeNull();
expect(queryByRole("tab", { name: "All Models" })).not.toBeInTheDocument();
});
it("renders the team detail overlay from the ?team drill-in", () => {
@ -95,8 +95,8 @@ describe("ModelsAndEndpointsPage", () => {
it("hides admin-only tabs for a non-admin user", () => {
mockUseAuthorized.mockReturnValue(NON_ADMIN);
const { queryByRole } = renderPage();
expect(queryByRole("tab", { name: "LLM Credentials" })).toBeNull();
expect(queryByRole("tab", { name: "Health Status" })).toBeNull();
expect(queryByRole("tab", { name: "LLM Credentials" })).not.toBeInTheDocument();
expect(queryByRole("tab", { name: "Health Status" })).not.toBeInTheDocument();
});
// Auto-routers are excluded from the All Models table, so this tab is their home: the only
@ -125,7 +125,7 @@ describe("ModelsAndEndpointsPage", () => {
mockUseAuthorized.mockReturnValue(NON_ADMIN);
const { queryByRole } = renderPage();
expect(queryByRole("tab", { name: /Auto-Routers/ })).toBeNull();
expect(queryByRole("tab", { name: /Auto-Routers/ })).not.toBeInTheDocument();
});
});
});

View file

@ -39,13 +39,13 @@ describe("AdditionalModelSettings", () => {
await waitFor(() => {
const sliders = screen.getAllByRole("slider");
expect(sliders.length).toBeGreaterThan(0);
expect(sliders[0]).not.toBeDisabled();
expect(sliders[0]).toBeEnabled();
});
const temperatureSlider = screen.getAllByRole("slider")[0];
const maxTokensSlider = screen.getAllByRole("slider")[1];
expect(temperatureSlider).not.toBeDisabled();
expect(maxTokensSlider).not.toBeDisabled();
expect(temperatureSlider).toBeEnabled();
expect(maxTokensSlider).toBeEnabled();
});
it("should not show Stream responses when onStreamingChange is not provided", () => {

View file

@ -132,7 +132,7 @@ describe("AgentBuilderView", () => {
expect(screen.getByRole("button", { name: "research-agent litellm_agent" })).toBeInTheDocument();
expect(screen.getByText("Agent Builder")).toBeInTheDocument();
await waitFor(() => expect(screen.getByDisplayValue("support-agent")).toBeInTheDocument());
expect(await screen.findByDisplayValue("support-agent")).toBeInTheDocument();
expect(screen.getByDisplayValue("Be helpful.")).toBeInTheDocument();
expect(screen.getByDisplayValue("0.3")).toBeInTheDocument();
});
@ -144,7 +144,7 @@ describe("AgentBuilderView", () => {
await user.click(screen.getByRole("button", { name: "research-agent litellm_agent" }));
await waitFor(() => expect(screen.getByDisplayValue("research-agent")).toBeInTheDocument());
expect(await screen.findByDisplayValue("research-agent")).toBeInTheDocument();
});
it("offers a blank draft and a save control for a new agent", async () => {

View file

@ -109,6 +109,6 @@ describe("ChatComposer", () => {
fireEvent.click(addonOf(container));
expect(document.activeElement).toBe(screen.getByTestId("chat-composer-input"));
expect(screen.getByTestId("chat-composer-input")).toHaveFocus();
});
});

View file

@ -148,10 +148,10 @@ describe("ChatUI", () => {
await waitFor(() => {
expect(screen.getAllByText("ChatModel").length).toBeGreaterThan(0);
expect(screen.getAllByText("NoModeModel").length).toBeGreaterThan(0);
expect(screen.queryByText("SpeechModel")).toBeNull();
expect(screen.queryByText("ImageModel")).toBeNull();
expect(screen.queryByText("ResponsesModel")).toBeNull();
expect(screen.queryByText("RealtimeModel")).toBeNull();
expect(screen.queryByText("SpeechModel")).not.toBeInTheDocument();
expect(screen.queryByText("ImageModel")).not.toBeInTheDocument();
expect(screen.queryByText("ResponsesModel")).not.toBeInTheDocument();
expect(screen.queryByText("RealtimeModel")).not.toBeInTheDocument();
});
});
@ -182,7 +182,7 @@ describe("ChatUI", () => {
await waitFor(() => {
expect(screen.getAllByText("RealtimeModel").length).toBeGreaterThan(0);
expect(screen.getAllByText("NoModeModel").length).toBeGreaterThan(0);
expect(screen.queryByText("ChatModel")).toBeNull();
expect(screen.queryByText("ChatModel")).not.toBeInTheDocument();
});
});
@ -234,7 +234,7 @@ describe("ChatUI", () => {
await selectComboboxOption("Select an endpoint", "/v1/chat/completions");
await waitFor(() => {
expect(mcpInput()).not.toBeDisabled();
expect(mcpInput()).toBeEnabled();
});
});
@ -432,7 +432,7 @@ describe("ChatUI", () => {
});
await waitFor(() => {
expect(screen.queryByText("Fill")).toBeNull();
expect(screen.queryByText("Fill")).not.toBeInTheDocument();
});
const customProxyInput = screen.getByPlaceholderText(
@ -461,7 +461,7 @@ describe("ChatUI", () => {
const mcpInput = screen.getByLabelText("Select MCP servers");
expect(mcpInput).toBeInTheDocument();
expect(mcpInput).not.toBeDisabled();
expect(mcpInput).toBeEnabled();
await user.click(mcpInput);
@ -521,7 +521,7 @@ describe("ChatUI", () => {
await waitFor(() => {
expect(screen.getAllByText("ChatModel").length).toBeGreaterThan(0);
});
expect(screen.queryByText("SpeechModel")).toBeNull();
expect(screen.queryByText("SpeechModel")).not.toBeInTheDocument();
});
it("should attach an audio file dropped on the transcription upload area", async () => {
@ -611,7 +611,7 @@ describe("ChatUI", () => {
await user.clear(keyField);
await waitFor(() => {
expect(screen.getByPlaceholderText("Select a Model")).not.toBeDisabled();
expect(screen.getByPlaceholderText("Select a Model")).toBeEnabled();
});
});
});

View file

@ -235,7 +235,7 @@ describe("CodeInterpreterOutput", () => {
it("should return null when no code and no annotations", () => {
const { container } = render(<CodeInterpreterOutput accessToken="test-token" />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should handle multiple image formats", async () => {

View file

@ -1,4 +1,4 @@
import { act, render, screen, waitFor } from "@testing-library/react";
import { act, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import RealtimePlayground from "./RealtimePlayground";
@ -261,7 +261,7 @@ describe("RealtimePlayground", () => {
await user.click(screen.getByRole("button", { name: /Disconnect/i }));
expect(socket.close).toHaveBeenCalled();
await waitFor(() => expect(screen.getByRole("button", { name: /Connect/i })).toBeInTheDocument());
expect(await screen.findByRole("button", { name: /Connect/i })).toBeInTheDocument();
expect(screen.queryByPlaceholderText("Type a message or use the mic...")).not.toBeInTheDocument();
});
});

View file

@ -138,14 +138,14 @@ describe("CompareUI", () => {
}
await waitFor(() => {
expect(queryByTestId("has-attachment")).toBeInTheDocument();
expect(getByTestId("has-attachment")).toBeInTheDocument();
});
const textarea = getByTestId("message-textarea");
await user.type(textarea, "Describe this image");
const sendButton = getByTestId("send-button");
expect(sendButton).not.toBeDisabled();
expect(sendButton).toBeEnabled();
await user.click(sendButton);
await waitFor(() => {

View file

@ -41,7 +41,7 @@ describe("MessageInput", () => {
render(<MessageInput value="hello" onChange={vi.fn()} onSend={onSend} />);
const send = screen.getByRole("button");
expect(send).not.toBeDisabled();
expect(send).toBeEnabled();
await user.click(send);
expect(onSend).toHaveBeenCalledTimes(1);
@ -63,7 +63,7 @@ describe("MessageInput", () => {
expect(screen.getByTestId("upload-component")).toBeInTheDocument();
const send = screen.getByRole("button");
expect(send).not.toBeDisabled();
expect(send).toBeEnabled();
await user.click(send);
expect(onSend).toHaveBeenCalledTimes(1);

View file

@ -135,9 +135,9 @@ describe("AttachmentTable", () => {
const attachment = makeAttachment({ attachment_id: "att-abcdef1234567" });
renderWithProviders(<AttachmentTable {...defaultProps} attachments={[attachment]} />);
const idElement = screen.getByText("att-abcdef1234567");
expect(idElement.className).toContain("font-mono");
expect(idElement.className).toContain("truncate");
expect(idElement.className).not.toContain("bg-blue-50");
expect(idElement).toHaveClass("font-mono");
expect(idElement).toHaveClass("truncate");
expect(idElement).not.toHaveClass("bg-blue-50");
});
it("should render model chips when the attachment has models", () => {

View file

@ -96,7 +96,7 @@ describe("AiSuggestionModal", () => {
expect(screen.getByRole("button", { name: "Suggest Policies" })).toBeDisabled();
await pickModel(user);
expect(screen.getByRole("button", { name: "Suggest Policies" })).not.toBeDisabled();
expect(screen.getByRole("button", { name: "Suggest Policies" })).toBeEnabled();
});
it("sends the examples, description and model to the suggest API", async () => {

View file

@ -156,8 +156,8 @@ describe("PoliciesPanel attachment delete", () => {
await waitFor(() => {
expect(networkingMocks.deletePolicyAttachmentCall).toHaveBeenCalledTimes(1);
expect(networkingMocks.deletePolicyAttachmentCall).toHaveBeenCalledWith("test-token", EXPECTED_ATTACHMENT_ID);
});
expect(networkingMocks.deletePolicyAttachmentCall).toHaveBeenCalledWith("test-token", EXPECTED_ATTACHMENT_ID);
});
it("should show mutation pending state while attachment delete is in flight", async () => {

View file

@ -95,7 +95,7 @@ describe("TemplateParameterModal", () => {
await user.type(screen.getByPlaceholderText("e.g. Contoso"), "Contoso");
expect(screen.getByRole("button", { name: "Continue" })).not.toBeDisabled();
expect(screen.getByRole("button", { name: "Continue" })).toBeEnabled();
});
it("hands the entered parameters back to the caller", async () => {
@ -181,7 +181,7 @@ describe("TemplateParameterModal", () => {
expect(await screen.findByText("Northwind")).toBeInTheDocument();
expect(screen.getByText("Fabrikam")).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByRole("button", { name: "Continue" })).not.toBeDisabled();
expect(screen.getByRole("button", { name: "Continue" })).toBeEnabled();
});
});

View file

@ -12,17 +12,20 @@ describe("SearchProviderLabel", () => {
it("renders the exa_ai logo file for the exa_ai slug", () => {
render(<SearchProviderLabel providerName="exa_ai" displayName="Exa AI" />);
const img = screen.getByRole("img", { name: "Exa AI logo" });
expect(img.getAttribute("src")).toContain("exa_ai.png");
expect(img).toHaveAttribute("src", expect.stringContaining("exa_ai.png"));
});
it("renders the google_pse logo file for the google_pse slug", () => {
render(<SearchProviderLabel providerName="google_pse" displayName="Google PSE" />);
expect(screen.getByRole("img", { name: "Google PSE logo" }).getAttribute("src")).toContain("google_pse.png");
expect(screen.getByRole("img", { name: "Google PSE logo" })).toHaveAttribute(
"src",
expect.stringContaining("google_pse.png"),
);
});
it("falls back to a letter avatar for a provider with no bundled logo", () => {
render(<SearchProviderLabel providerName="brave" displayName="Brave Search" />);
expect(screen.queryByRole("img")).toBeNull();
expect(screen.queryByRole("img")).not.toBeInTheDocument();
expect(screen.getByText("B")).toBeInTheDocument();
expect(screen.getByText("Brave Search")).toBeInTheDocument();
});

View file

@ -82,7 +82,7 @@ describe("SearchToolTester", () => {
const input = screen.getByPlaceholderText("Enter your search query...");
await user.type(input, "test query");
const searchButton = screen.getByRole("button", { name: /search/i });
expect(searchButton).not.toBeDisabled();
expect(searchButton).toBeEnabled();
});
it("should call searchToolQueryCall when search button is clicked", async () => {
@ -416,11 +416,9 @@ describe("SearchToolTester", () => {
await user.type(input, "test query");
const searchButton = screen.getByRole("button", { name: /search/i });
await user.click(searchButton);
await waitFor(() => {
const link = screen.getByRole("link", { name: "Test Result 1" });
expect(link).toHaveAttribute("href", "https://example.com/result1");
expect(link).toHaveAttribute("target", "_blank");
expect(link).toHaveAttribute("rel", "noopener noreferrer");
});
const link = await screen.findByRole("link", { name: "Test Result 1" });
expect(link).toHaveAttribute("href", "https://example.com/result1");
expect(link).toHaveAttribute("rel", "noopener noreferrer");
expect(link).toHaveAttribute("target", "_blank");
});
});

View file

@ -90,7 +90,7 @@ describe("AddPluginForm", () => {
await waitFor(() => {
expect(screen.getByText(/Git repo/)).toBeInTheDocument();
});
expect(screen.getByPlaceholderText(SUBPATH_PLACEHOLDER)).not.toBeDisabled();
expect(screen.getByPlaceholderText(SUBPATH_PLACEHOLDER)).toBeEnabled();
});
it("combines a repo URL with a subfolder into a git-subdir preview", async () => {

View file

@ -76,10 +76,10 @@ describe("TransformRequestPanel", () => {
});
const output = await screen.findByText(/api\.anthropic\.com\/v1\/messages/);
expect(output.textContent).toContain("curl -X POST");
expect(output.textContent).toContain("-H 'x-api-key: redacted'");
expect(output.textContent).toContain('"model": "claude-opus-4-8"');
expect(output.textContent).toContain('"max_tokens": 42');
expect(output).toHaveTextContent(/curl \-X POST/);
expect(output).toHaveTextContent(/\-H 'x\-api\-key: redacted'/);
expect(output).toHaveTextContent(/"model": "claude\-opus\-4\-8"/);
expect(output).toHaveTextContent(/"max_tokens": 42/);
expect(notify.success).toHaveBeenCalledWith("Request transformed successfully");
});

View file

@ -68,8 +68,8 @@ describe("EndpointUsageLineChart", () => {
const legend = container.querySelector(".recharts-legend-wrapper");
expect(legend).not.toBeNull();
expect(legend!.textContent).toContain("/chat/completions");
expect(legend!.textContent).toContain("/embeddings");
expect(legend!).toHaveTextContent(/\/chat\/completions/);
expect(legend!).toHaveTextContent(/\/embeddings/);
});
it("orders formatted dates oldest to newest on the x axis", () => {

View file

@ -838,7 +838,7 @@ describe("EntityUsage", () => {
const sectors = container.querySelectorAll(".recharts-pie-sector path");
expect(sectors).toHaveLength(1);
expect(sectors[0].getAttribute("fill")).toBe("var(--color-cyan-500, #06b6d4)");
expect(sectors[0]).toHaveAttribute("fill", "var(--color-cyan-500, #06b6d4)");
const centerLabels = Array.from(container.querySelectorAll("text.fill-foreground")).map((text) => text.textContent);
expect(centerLabels).toContain("$100.50");
@ -883,7 +883,7 @@ describe("EntityUsage", () => {
render(<EntityUsage {...defaultProps} />);
const logo = await screen.findByAltText("openai logo");
expect(logo.getAttribute("src")).toContain("openai_small");
expect(logo).toHaveAttribute("src", expect.stringContaining("openai_small"));
});
describe("capability gating", () => {

View file

@ -241,7 +241,7 @@ describe("UserEditView", () => {
await waitFor(() => {
const modelsSelect = screen.getByRole("combobox", { name: /select models/i });
expect(modelsSelect).not.toBeDisabled();
expect(modelsSelect).toBeEnabled();
});
});
@ -300,7 +300,7 @@ describe("UserEditView", () => {
await waitFor(() => {
const budgetInput = screen.getByRole("spinbutton", { name: /max budget/i });
expect(budgetInput).not.toBeDisabled();
expect(budgetInput).toBeEnabled();
});
});

View file

@ -273,7 +273,7 @@ describe("ViewUserDashboard", () => {
await user.click(screen.getByTestId("datatable-select-row-user-2"));
expect(screen.getByTestId("bulk-edit-users")).toHaveTextContent("Bulk Edit (1 selected)");
expect(screen.getByTestId("bulk-edit-users")).not.toBeDisabled();
expect(screen.getByTestId("bulk-edit-users")).toBeEnabled();
await user.click(screen.getByTestId("datatable-select-all"));
expect(screen.getByTestId("bulk-edit-users")).toHaveTextContent("Bulk Edit (2 selected)");

View file

@ -119,7 +119,7 @@ describe("UsersTable", () => {
"Created At",
"Updated At",
].forEach((header) => {
expect(headerRow.textContent).toContain(header);
expect(headerRow).toHaveTextContent(header);
});
});
@ -251,7 +251,7 @@ describe("UsersTable", () => {
await user.click(screen.getByTestId("datatable-select-row-user-1"));
expect(screen.getByTestId("datatable-select-all")).toHaveAttribute("aria-checked", "mixed");
expect(screen.getByTestId("datatable-select-all")).toBePartiallyChecked();
});
});

View file

@ -226,9 +226,9 @@ describe("CreateVectorStore", () => {
// Check if S3-specific fields are displayed
await waitFor(() => {
expect(screen.queryByText("Vector Bucket Name")).toBeInTheDocument();
expect(screen.queryByText("AWS Region")).toBeInTheDocument();
expect(screen.queryByText("Embedding Model")).toBeInTheDocument();
expect(screen.getByText("Vector Bucket Name")).toBeInTheDocument();
expect(screen.getByText("AWS Region")).toBeInTheDocument();
expect(screen.getByText("Embedding Model")).toBeInTheDocument();
});
});

View file

@ -87,7 +87,7 @@ describe("IndexesTable", () => {
it("should link created_by to the user detail deep link", () => {
render(<IndexesTable data={[newerIndex]} resolveVectorStoreId={noResolve} onViewVectorStore={vi.fn()} />);
const link = screen.getByRole("link", { name: "admin@example.com" });
expect(link.getAttribute("href")).toMatch(/\/users\?user=admin%40example\.com$/);
expect(link).toHaveAttribute("href", expect.stringMatching(/\/users\?user=admin%40example\.com$/));
});
it("should keep the dash fallback and render no link for a null created_by", () => {

View file

@ -29,6 +29,6 @@ describe("VectorStoreForm", () => {
renderForm();
const logo = screen.getByRole("img", { name: `${VectorStoreProviders.Bedrock} logo` });
expect(logo.getAttribute("src")).toBe(providerLogoMap[Providers.Bedrock]);
expect(logo).toHaveAttribute("src", providerLogoMap[Providers.Bedrock]);
});
});

View file

@ -69,7 +69,7 @@ const ON_TOTAL_LATENCY_INDEX = 24;
async function sendOneMessage(): Promise<void> {
render(<ChatConversationPage />);
await waitFor(() => expect(screen.getByRole("button", { name: /gpt-5\.4-mini/ })).toBeInTheDocument());
expect(await screen.findByRole("button", { name: /gpt-5\.4-mini/ })).toBeInTheDocument();
fireEvent.change(screen.getByPlaceholderText("How can I help you today?"), {
target: { value: "How much did this cost?" },
});
@ -98,7 +98,7 @@ describe("/ui/chat request metrics", () => {
await sendOneMessage();
await waitFor(() => expect(screen.getByLabelText("Total: 20")).toBeInTheDocument());
expect(await screen.findByLabelText("Total: 20")).toBeInTheDocument();
expect(screen.getByLabelText("TTFT: 0.25s")).toBeInTheDocument();
expect(screen.getByLabelText("Total Latency: 1.20s")).toBeInTheDocument();
expect(screen.getByLabelText("In: 12")).toBeInTheDocument();
@ -126,7 +126,7 @@ describe("/ui/chat request metrics", () => {
await sendOneMessage();
await waitFor(() => expect(screen.getByText("No usage here.")).toBeInTheDocument());
expect(await screen.findByText("No usage here.")).toBeInTheDocument();
expect(document.querySelector(".response-metrics")).toBeNull();
});
});

View file

@ -84,7 +84,7 @@ describe("UsefulLinksManagement", () => {
render(<UsefulLinksManagement accessToken="token" userRole="Admin" />);
await waitFor(() => expect(screen.getByText("First Link")).toBeInTheDocument());
expect(await screen.findByText("First Link")).toBeInTheDocument();
await user.click(screen.getByRole("button", { name: /rearrange order/i }));
@ -123,7 +123,7 @@ describe("UsefulLinksManagement", () => {
render(<UsefulLinksManagement accessToken="token" userRole="Admin" />);
await waitFor(() => expect(screen.getByText("Test Link")).toBeInTheDocument());
expect(await screen.findByText("Test Link")).toBeInTheDocument();
// Click edit button
const editButton = screen.getByTestId("edit-link-0-Test Link");
@ -147,7 +147,7 @@ describe("UsefulLinksManagement", () => {
render(<UsefulLinksManagement accessToken="token" userRole="Admin" />);
await waitFor(() => expect(screen.getByText("Test Link")).toBeInTheDocument());
expect(await screen.findByText("Test Link")).toBeInTheDocument();
// Click edit button
const editButton = screen.getByTestId("edit-link-0-Test Link");
@ -183,7 +183,7 @@ describe("UsefulLinksManagement", () => {
render(<UsefulLinksManagement accessToken="token" userRole="Admin" />);
await waitFor(() => expect(screen.getByText("Test Link")).toBeInTheDocument());
expect(await screen.findByText("Test Link")).toBeInTheDocument();
// Click edit button
const editButton = screen.getByTestId("edit-link-0-Test Link");
@ -216,7 +216,7 @@ describe("UsefulLinksManagement", () => {
render(<UsefulLinksManagement accessToken="token" userRole="Admin" />);
await waitFor(() => expect(screen.getByText("First Link")).toBeInTheDocument());
expect(await screen.findByText("First Link")).toBeInTheDocument();
// Enter rearrange mode
await user.click(screen.getByRole("button", { name: /rearrange order/i }));
@ -235,7 +235,7 @@ describe("UsefulLinksManagement", () => {
const user = userEvent.setup();
render(<UsefulLinksManagement accessToken="token" userRole="Admin" />);
await waitFor(() => expect(screen.getByText("Link Management")).toBeInTheDocument());
expect(await screen.findByText("Link Management")).toBeInTheDocument();
// Initially expanded
expect(screen.getByText("Manage Existing Links")).toBeInTheDocument();

View file

@ -74,7 +74,7 @@ describe("MakeAgentPublicForm", () => {
// Check that the Next button is enabled (agents are preselected)
const nextButton = screen.getByRole("button", { name: "Next" });
expect(nextButton).not.toBeDisabled();
expect(nextButton).toBeEnabled();
});
it("should handle agent selection and navigation", async () => {
@ -91,7 +91,7 @@ describe("MakeAgentPublicForm", () => {
// Verify Next button is enabled
const nextButton = screen.getByRole("button", { name: "Next" });
expect(nextButton).not.toBeDisabled();
expect(nextButton).toBeEnabled();
// Click Next
await act(async () => {

View file

@ -97,7 +97,7 @@ describe("MakeMCPPublicForm", () => {
// Check that the Next button is enabled (servers are preselected)
const nextButton = screen.getByRole("button", { name: "Next" });
expect(nextButton).not.toBeDisabled();
expect(nextButton).toBeEnabled();
});
it("should handle server selection and navigation", async () => {
@ -114,7 +114,7 @@ describe("MakeMCPPublicForm", () => {
// Verify Next button is enabled
const nextButton = screen.getByRole("button", { name: "Next" });
expect(nextButton).not.toBeDisabled();
expect(nextButton).toBeEnabled();
// Click Next
await act(async () => {

View file

@ -121,7 +121,7 @@ describe("MakeModelPublicForm", () => {
// Check that the Next button is enabled (models are preselected)
const nextButton = screen.getByRole("button", { name: "Next" });
expect(nextButton).not.toBeDisabled();
expect(nextButton).toBeEnabled();
});
it("should handle model selection and navigation", async () => {
@ -138,7 +138,7 @@ describe("MakeModelPublicForm", () => {
// Verify Next button is enabled
const nextButton = screen.getByRole("button", { name: "Next" });
expect(nextButton).not.toBeDisabled();
expect(nextButton).toBeEnabled();
// Click Next
await act(async () => {

View file

@ -47,7 +47,7 @@ describe("BetaBadge", () => {
const { container } = render(<BetaBadge />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should render badge with dot instead of text when dot prop is true", () => {

View file

@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { act, fireEvent, render, screen } from "@testing-library/react";
import { DashboardHeader } from "./DashboardHeader";
const { mockUsePluginMode, mockUseUISettings, state } = vi.hoisted(() => {
@ -44,7 +44,7 @@ describe("DashboardHeader breadcrumb", () => {
act(() => {
fireEvent.click(selector);
});
await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument());
expect(await screen.findByText("Chat")).toBeInTheDocument();
});
it("keeps the AI Gateway selector at the root even when there is nothing to switch to (discovery)", () => {

View file

@ -197,12 +197,10 @@ describe("BlogDropdown", () => {
await openDropdown();
await waitFor(() => {
const link = screen.getByRole("link", { name: /post one/i });
expect(link).toHaveAttribute("href", "https://example.com/1");
expect(link).toHaveAttribute("target", "_blank");
expect(link).toHaveAttribute("rel", "noopener noreferrer");
});
const link = await screen.findByRole("link", { name: /post one/i });
expect(link).toHaveAttribute("href", "https://example.com/1");
expect(link).toHaveAttribute("rel", "noopener noreferrer");
expect(link).toHaveAttribute("target", "_blank");
});
it("should render formatted post dates", async () => {
@ -226,12 +224,10 @@ describe("BlogDropdown", () => {
await openDropdown();
await waitFor(() => {
const viewAllLink = screen.getByRole("link", { name: /view all posts/i });
expect(viewAllLink).toHaveAttribute("href", "https://docs.litellm.ai/blog");
expect(viewAllLink).toHaveAttribute("target", "_blank");
expect(viewAllLink).toHaveAttribute("rel", "noopener noreferrer");
});
const viewAllLink = await screen.findByRole("link", { name: /view all posts/i });
expect(viewAllLink).toHaveAttribute("href", "https://docs.litellm.ai/blog");
expect(viewAllLink).toHaveAttribute("rel", "noopener noreferrer");
expect(viewAllLink).toHaveAttribute("target", "_blank");
});
});

View file

@ -1,5 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { act, fireEvent, render, screen } from "@testing-library/react";
import ViewSwitcher from "./ViewSwitcher";
const { mockUsePluginMode, mockUseUISettings, mockUsePathname, state } = vi.hoisted(() => {
@ -58,7 +58,7 @@ describe("ViewSwitcher", () => {
act(() => {
fireEvent.click(button);
});
await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument());
expect(await screen.findByText("Chat")).toBeInTheDocument();
expect(screen.getByText(/Admins can enable in Settings/i)).toBeInTheDocument();
act(() => {
@ -81,7 +81,7 @@ describe("ViewSwitcher", () => {
act(() => {
fireEvent.click(screen.getByRole("button"));
});
await waitFor(() => expect(screen.getByText("AI Gateway")).toBeInTheDocument());
expect(await screen.findByText("AI Gateway")).toBeInTheDocument();
expect(screen.getByText("Observability")).toBeInTheDocument();
});
@ -93,7 +93,7 @@ describe("ViewSwitcher", () => {
act(() => {
fireEvent.click(screen.getByRole("button"));
});
await waitFor(() => expect(screen.getByText("Chat UI")).toBeInTheDocument());
expect(await screen.findByText("Chat UI")).toBeInTheDocument();
act(() => {
fireEvent.click(screen.getByText("Chat UI"));
});
@ -108,7 +108,7 @@ describe("ViewSwitcher", () => {
act(() => {
fireEvent.click(screen.getByRole("button"));
});
await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument());
expect(await screen.findByText("Chat")).toBeInTheDocument();
expect(screen.queryByText(/Admins can enable in Settings/i)).not.toBeInTheDocument();
act(() => {
@ -127,7 +127,7 @@ describe("ViewSwitcher", () => {
act(() => {
fireEvent.click(screen.getByRole("button"));
});
await waitFor(() => expect(screen.getByText("AI Gateway")).toBeInTheDocument());
expect(await screen.findByText("AI Gateway")).toBeInTheDocument();
act(() => {
fireEvent.click(screen.getByText("AI Gateway"));
});
@ -143,7 +143,7 @@ describe("ViewSwitcher", () => {
act(() => {
fireEvent.click(screen.getByRole("button"));
});
await waitFor(() => expect(screen.getByText("Observability")).toBeInTheDocument());
expect(await screen.findByText("Observability")).toBeInTheDocument();
expect(screen.getByText("Chat")).toBeInTheDocument();
expect(screen.getByText(/Admins can enable in Settings/i)).toBeInTheDocument();

View file

@ -67,10 +67,8 @@ describe("SSOModals", () => {
const ssoProviderSelect = screen.getByLabelText("SSO Provider");
fireEvent.mouseDown(ssoProviderSelect);
// Wait for dropdown and select Google
await waitFor(() => {
const googleOption = screen.getByText("Google SSO");
fireEvent.click(googleOption);
});
const googleOption = await screen.findByText("Google SSO");
fireEvent.click(googleOption);
// Fill in the email field
const emailInput = screen.getByLabelText("Proxy Admin Email");
@ -119,10 +117,8 @@ describe("SSOModals", () => {
const ssoProviderSelect = screen.getByLabelText("SSO Provider");
fireEvent.mouseDown(ssoProviderSelect);
// Wait for dropdown and select Google
await waitFor(() => {
const googleOption = screen.getByText("Google SSO");
fireEvent.click(googleOption);
});
const googleOption = await screen.findByText("Google SSO");
fireEvent.click(googleOption);
// Fill in the email field
const emailInput = screen.getByLabelText("Proxy Admin Email");
@ -216,10 +212,8 @@ describe("SSOModals", () => {
const ssoProviderSelect = screen.getByLabelText("SSO Provider");
fireEvent.mouseDown(ssoProviderSelect);
// Wait for dropdown and select Google
await waitFor(() => {
const googleOption = screen.getByText("Google SSO");
fireEvent.click(googleOption);
});
const googleOption = await screen.findByText("Google SSO");
fireEvent.click(googleOption);
// Fill in the email field
const emailInput = screen.getByLabelText("Proxy Admin Email");

View file

@ -143,7 +143,7 @@ describe("MCPSemanticFilterSettings", () => {
await user.click(screen.getByRole("switch"));
expect(screen.getByRole("button", { name: /save settings/i })).not.toBeDisabled();
expect(screen.getByRole("button", { name: /save settings/i })).toBeEnabled();
});
it("should show an error alert when the mutation fails", async () => {

View file

@ -69,7 +69,7 @@ describe("MCPSemanticFilterTestPanel", () => {
it("should enable the Test Filter button when testQuery is set and filter is enabled", () => {
render(<MCPSemanticFilterTestPanel {...buildProps({ testQuery: "search query" })} />);
expect(screen.getByRole("button", { name: /test filter/i })).not.toBeDisabled();
expect(screen.getByRole("button", { name: /test filter/i })).toBeEnabled();
});
it("should call onTest when the Test Filter button is clicked", async () => {

View file

@ -39,10 +39,8 @@ describe("BaseSSOSettingsForm", () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const googleOption = screen.getByText(/google sso/i);
fireEvent.click(googleOption);
});
const googleOption = await screen.findByText(/google sso/i);
fireEvent.click(googleOption);
await waitFor(() => {
expect(screen.getByText("Google Client ID")).toBeInTheDocument();
@ -65,10 +63,8 @@ describe("BaseSSOSettingsForm", () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const oktaOption = screen.getByText(/okta/i);
fireEvent.click(oktaOption);
});
const oktaOption = await screen.findByText(/okta/i);
fireEvent.click(oktaOption);
await waitFor(() => {
expect(screen.getByText("Use Role Mappings")).toBeInTheDocument();
@ -132,10 +128,8 @@ describe("BaseSSOSettingsForm", () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const genericOption = screen.getByText(/generic sso/i);
fireEvent.click(genericOption);
});
const genericOption = await screen.findByText(/generic sso/i);
fireEvent.click(genericOption);
await waitFor(() => {
expect(screen.getByText("Use Role Mappings")).toBeInTheDocument();
@ -167,10 +161,8 @@ describe("BaseSSOSettingsForm", () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const oktaOption = screen.getByText(/okta/i);
fireEvent.click(oktaOption);
});
const oktaOption = await screen.findByText(/okta/i);
fireEvent.click(oktaOption);
await waitFor(() => {
expect(screen.getByText("Use Team Mappings")).toBeInTheDocument();
@ -192,10 +184,8 @@ describe("BaseSSOSettingsForm", () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const genericOption = screen.getByText(/generic sso/i);
fireEvent.click(genericOption);
});
const genericOption = await screen.findByText(/generic sso/i);
fireEvent.click(genericOption);
await waitFor(() => {
expect(screen.getByText("Use Team Mappings")).toBeInTheDocument();
@ -217,10 +207,8 @@ describe("BaseSSOSettingsForm", () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const oktaOption = screen.getByText(/okta/i);
fireEvent.click(oktaOption);
});
const oktaOption = await screen.findByText(/okta/i);
fireEvent.click(oktaOption);
await waitFor(() => {
expect(screen.getByText("Use Team Mappings")).toBeInTheDocument();
@ -251,10 +239,8 @@ describe("BaseSSOSettingsForm", () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const googleOption = screen.getByText(/google sso/i);
fireEvent.click(googleOption);
});
const googleOption = await screen.findByText(/google sso/i);
fireEvent.click(googleOption);
await waitFor(() => {
expect(screen.getByText("Google Client ID")).toBeInTheDocument();

View file

@ -26,7 +26,7 @@ describe("RoleMappings", () => {
it("should return null when roleMappings is undefined", () => {
const { container } = renderWithProviders(<RoleMappings roleMappings={undefined} />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should display Group Claim and Default Role with correct values and display names", () => {

View file

@ -189,7 +189,7 @@ describe("AddFallbacks", () => {
});
const saveButton = screen.getByRole("button", { name: /save all configurations/i });
expect(saveButton).not.toBeDisabled();
expect(saveButton).toBeEnabled();
await user.click(saveButton);
await waitFor(() => {

View file

@ -125,7 +125,7 @@ describe("Fallbacks", () => {
it("should not render when accessToken is null", () => {
const { container } = renderWithQueryClient(<Fallbacks {...defaultProps} accessToken={null} />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should fetch router settings on mount", async () => {

View file

@ -368,7 +368,7 @@ describe("TeamSSOSettings", () => {
await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i }));
const permissionComboboxes = screen.getAllByRole("combobox");
const permissionCombobox = permissionComboboxes[permissionComboboxes.length - 1];
expect(permissionCombobox).toBeDefined();
expect(permissionCombobox).toBeInTheDocument();
await userEvent.click(permissionCombobox!);
const deletePermissionOptions = await screen.findAllByText("/key/delete");
await userEvent.click(deletePermissionOptions[deletePermissionOptions.length - 1]);

View file

@ -151,7 +151,7 @@ describe("sort contract only backend-sortable columns are sortable", () => {
it("does not make Spend / Budget sortable (the backend rejects sort_by=spend)", () => {
renderTable();
expect(screen.getByText("Spend / Budget").closest("button")).toBeNull();
expect(screen.queryByText("Spend / Budget").closest("button")).toBeNull();
// Team and Created are the only sortable headers.
expect(screen.getByText("Team").closest("button")).not.toBeNull();
expect(screen.getByText("Created").closest("button")).not.toBeNull();

View file

@ -152,7 +152,7 @@ describe("TopKeyView", () => {
const bars = container.querySelectorAll("path.recharts-rectangle");
expect(bars).toHaveLength(1);
expect(bars[0].getAttribute("fill")).toBe("var(--color-cyan-500, #06b6d4)");
expect(bars[0]).toHaveAttribute("fill", "var(--color-cyan-500, #06b6d4)");
expect(screen.getAllByText("A Very Lon...").length).toBeGreaterThan(0);
fireEvent.click(bars[0]);

View file

@ -31,7 +31,7 @@ describe("KeyModelUsageView", () => {
it("should return null when topModels is empty", () => {
const { container } = render(<KeyModelUsageView topModels={[]} />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should display Model Usage title", () => {

View file

@ -339,13 +339,9 @@ it("emphasizes the active field in the Spend / Budget header so the sorted colum
await user.click(await screen.findByText("Budget descending"));
await waitFor(() => {
expect(screen.getByText("Budget", { selector: "[data-sort-field='max_budget']" }).className).toContain(
"font-semibold",
);
expect(screen.getByText("Budget", { selector: "[data-sort-field='max_budget']" })).toHaveClass("font-semibold");
});
expect(screen.getByText("Spend", { selector: "[data-sort-field='spend']" }).className).toContain(
"text-muted-foreground",
);
expect(screen.getByText("Spend", { selector: "[data-sort-field='spend']" })).toHaveClass("text-muted-foreground");
});
it("sorts by spend ascending when 'Spend ascending' is chosen from the Spend / Budget menu", async () => {
@ -537,7 +533,7 @@ describe("refresh button", () => {
const refresh = screen.getByTestId("datatable-refresh");
expect(refresh).toBeInTheDocument();
expect(refresh).not.toBeDisabled();
expect(refresh).toBeEnabled();
});
it("disables the refresh control while a fetch is in flight but keeps data visible", () => {

View file

@ -1,4 +1,4 @@
import { renderWithProviders, screen, waitFor } from "../../../tests/test-utils";
import { renderWithProviders, screen } from "../../../tests/test-utils";
import userEvent from "@testing-library/user-event";
import { vi } from "vitest";
import ClassifierPromptEditor from "./ClassifierPromptEditor";
@ -45,7 +45,7 @@ const openEditor = async ({
/>,
);
await userEvent.click(screen.getByRole("button", { name: /prompt/i }));
await waitFor(() => expect(screen.getByLabelText("Classifier system prompt")).toBeInTheDocument());
expect(await screen.findByLabelText("Classifier system prompt")).toBeInTheDocument();
return onChange;
};

View file

@ -455,7 +455,7 @@ describe("AddAutoRouterTab", () => {
const anthropicOption = optionByLabel("Anthropic Family")!;
expect(isOptionDisabled(anthropicOption)).toBe(true);
expect(anthropicOption.textContent).toContain("Checking model availability");
expect(anthropicOption).toHaveTextContent(/Checking model availability/);
// The dropdown is already open from above; polling re-reads its options in place rather than
// reopening (openTemplateDropdown toggles, so a second call here would close it instead).
@ -474,7 +474,7 @@ describe("AddAutoRouterTab", () => {
openTemplateDropdown();
const anthropicOption = optionByLabel("Anthropic Family")!;
expect(isOptionDisabled(anthropicOption)).toBe(true);
expect(anthropicOption.textContent).toContain("Cannot verify these models are available");
expect(anthropicOption).toHaveTextContent(/Cannot verify these models are available/);
});
it("keeps group-name presets selectable when only the deployment fetch fails", async () => {
@ -496,7 +496,7 @@ describe("AddAutoRouterTab", () => {
openTemplateDropdown();
await waitFor(() => {
expect(optionByLabel("Anthropic Family")!.textContent).toContain(`Missing: ${ANTHROPIC_ONLY_MODEL}`);
expect(optionByLabel("Anthropic Family")!).toHaveTextContent(new RegExp(`Missing: ${ANTHROPIC_ONLY_MODEL}`));
});
expect(isOptionDisabled(optionByLabel("Anthropic Family")!)).toBe(true);
});
@ -695,7 +695,7 @@ describe("AddAutoRouterTab", () => {
await waitFor(() => {
expect(isOptionDisabled(optionByLabel("Anthropic Family")!)).toBe(false);
});
expect(optionByLabel("Anthropic Family")!.textContent).toContain("Matches your deployments");
expect(optionByLabel("Anthropic Family")!).toHaveTextContent(/Matches your deployments/);
});
it("keeps detailed configuration open and prefills the admin's group names on apply", async () => {
@ -755,7 +755,7 @@ describe("AddAutoRouterTab", () => {
openTemplateDropdown();
await waitFor(() => {
expect(optionByLabel("OpenAI Family")!.textContent).toContain("Missing:");
expect(optionByLabel("OpenAI Family")!).toHaveTextContent(/Missing:/);
});
expect(isOptionDisabled(optionByLabel("OpenAI Family")!)).toBe(true);
});
@ -784,7 +784,7 @@ describe("AddAutoRouterTab", () => {
await waitFor(() => {
expect(isOptionDisabled(optionByLabel("Anthropic Family")!)).toBe(false);
});
expect(optionByLabel("Anthropic Family")!.textContent).toContain("Matches your deployments");
expect(optionByLabel("Anthropic Family")!).toHaveTextContent(/Matches your deployments/);
});
it("prefills the expanded group names and submits them", async () => {

View file

@ -44,7 +44,7 @@ describe("AutoRouterConnectionTest", () => {
renderWithProviders(<AutoRouterConnectionTest accessToken="sk-test" targets={targets} />);
await waitFor(() => expect(screen.getAllByTestId("test-status-success")).toHaveLength(3));
expect(screen.queryByTestId("test-status-error")).toBeNull();
expect(screen.queryByTestId("test-status-error")).not.toBeInTheDocument();
expect(screen.getByText("MEDIUM, COMPLEX")).toBeInTheDocument();
});
@ -60,7 +60,7 @@ describe("AutoRouterConnectionTest", () => {
renderWithProviders(<AutoRouterConnectionTest accessToken="sk-test" targets={targets} />);
await waitFor(() => expect(screen.getByTestId("test-error-message")).toBeInTheDocument());
expect(await screen.findByTestId("test-error-message")).toBeInTheDocument();
expect(screen.getByTestId("test-error-message")).toHaveTextContent("invalid api key");
expect(screen.getByTestId("test-error-message")).not.toHaveTextContent("litellm.AuthenticationError");
expect(screen.getAllByTestId("test-status-success")).toHaveLength(2);

View file

@ -25,6 +25,6 @@ describe("LitellmModelNameField", () => {
</Form>,
);
expect(getByPlaceholderText("my-deployment")).toBeInTheDocument();
expect(queryByPlaceholderText("gpt-3.5-turbo")).toBeNull();
expect(queryByPlaceholderText("gpt-3.5-turbo")).not.toBeInTheDocument();
});
});

View file

@ -150,17 +150,15 @@ describe("ProviderSpecificFields", () => {
</QueryClientProvider>,
);
await waitFor(() => {
const apiKeyLabel = screen.getByLabelText("OpenAI API Key");
expect(apiKeyLabel).toBeInTheDocument();
const apiKeyLabel = await screen.findByLabelText("OpenAI API Key");
expect(apiKeyLabel).toBeInTheDocument();
const apiBaseInput = screen.getByPlaceholderText("https://api.openai.com/v1");
expect(apiBaseInput).toBeInTheDocument();
expect(apiBaseInput).toHaveAttribute("type", "text");
const apiBaseInput = screen.getByPlaceholderText("https://api.openai.com/v1");
expect(apiBaseInput).toBeInTheDocument();
expect(apiBaseInput).toHaveAttribute("type", "text");
const orgInput = screen.getByPlaceholderText("[OPTIONAL] my-unique-org");
expect(orgInput).toBeInTheDocument();
});
const orgInput = screen.getByPlaceholderText("[OPTIONAL] my-unique-org");
expect(orgInput).toBeInTheDocument();
});
it("should render the provider specific fields for vLLM", async () => {
@ -173,14 +171,12 @@ describe("ProviderSpecificFields", () => {
</QueryClientProvider>,
);
await waitFor(() => {
const apiKeyLabel = screen.getByLabelText("vLLM API Key");
expect(apiKeyLabel).toBeInTheDocument();
const apiKeyLabel = await screen.findByLabelText("vLLM API Key");
expect(apiKeyLabel).toBeInTheDocument();
const apiBaseInput = screen.getByPlaceholderText("https://...");
expect(apiBaseInput).toBeInTheDocument();
expect(apiBaseInput).toHaveAttribute("type", "text");
});
const apiBaseInput = screen.getByPlaceholderText("https://...");
expect(apiBaseInput).toBeInTheDocument();
expect(apiBaseInput).toHaveAttribute("type", "text");
});
it("should render the provider specific fields for Azure", async () => {
@ -193,27 +189,25 @@ describe("ProviderSpecificFields", () => {
</QueryClientProvider>,
);
await waitFor(() => {
const apiKeyInput = screen.getByLabelText("Azure API Key");
expect(apiKeyInput).toBeInTheDocument();
expect(apiKeyInput).toHaveAttribute("type", "password");
expect(apiKeyInput).toHaveAttribute("placeholder", "Enter your Azure API Key");
const apiKeyInput = await screen.findByLabelText("Azure API Key");
expect(apiKeyInput).toBeInTheDocument();
expect(apiKeyInput).toHaveAttribute("type", "password");
expect(apiKeyInput).toHaveAttribute("placeholder", "Enter your Azure API Key");
const azureAdTokenInput = screen.getByLabelText("Azure AD Token");
expect(azureAdTokenInput).toBeInTheDocument();
expect(azureAdTokenInput).toHaveAttribute("type", "password");
expect(azureAdTokenInput).toHaveAttribute("placeholder", "Enter your Azure AD Token");
const azureAdTokenInput = screen.getByLabelText("Azure AD Token");
expect(azureAdTokenInput).toBeInTheDocument();
expect(azureAdTokenInput).toHaveAttribute("type", "password");
expect(azureAdTokenInput).toHaveAttribute("placeholder", "Enter your Azure AD Token");
const apiBaseInput = screen.getByPlaceholderText("https://...");
expect(apiBaseInput).toBeInTheDocument();
expect(apiBaseInput).toHaveAttribute("type", "text");
const apiBaseInput = screen.getByPlaceholderText("https://...");
expect(apiBaseInput).toBeInTheDocument();
expect(apiBaseInput).toHaveAttribute("type", "text");
const apiVersionInput = screen.getByPlaceholderText("2023-07-01-preview");
expect(apiVersionInput).toBeInTheDocument();
const apiVersionInput = screen.getByPlaceholderText("2023-07-01-preview");
expect(apiVersionInput).toBeInTheDocument();
const baseModelInput = screen.getByPlaceholderText("azure/gpt-3.5-turbo");
expect(baseModelInput).toBeInTheDocument();
});
const baseModelInput = screen.getByPlaceholderText("azure/gpt-3.5-turbo");
expect(baseModelInput).toBeInTheDocument();
});
it("sets Azure API version from the API base query parameter", async () => {

View file

@ -16,8 +16,8 @@ describe("ConnectFlowBanner", () => {
const { container } = render(<ConnectFlowBanner flowHandle="flow-handle-123" clientOrigin="https://claude.ai" />);
const form = container.querySelector("form")!;
expect(form.getAttribute("method")).toBe("POST");
expect(form.getAttribute("action")).toBe("https://gateway.example.com/authorize/complete");
expect(form).toHaveAttribute("method", "POST");
expect(form).toHaveAttribute("action", "https://gateway.example.com/authorize/complete");
const hidden = form.querySelector('input[name="flow"]') as HTMLInputElement;
expect(hidden.value).toBe("flow-handle-123");

View file

@ -58,8 +58,8 @@ describe("MCPAppsPanel logos", () => {
renderPanel();
expect(await screen.findByText("external_logo")).toBeInTheDocument();
expect(screen.getByAltText("external_logo logo").getAttribute("src")).toBe("https://cdn.example.com/ext.png");
expect(screen.getByAltText("local_logo logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg");
expect(screen.getByAltText("external_logo logo")).toHaveAttribute("src", "https://cdn.example.com/ext.png");
expect(screen.getByAltText("local_logo logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg");
});
it("renders a colored letter avatar for servers without logo_url", async () => {
@ -83,7 +83,7 @@ describe("MCPAppsPanel logos", () => {
fireEvent.click(await screen.findByText("local_logo"));
expect(await screen.findByRole("heading", { name: "local_logo" })).toBeInTheDocument();
expect(screen.getByAltText("local_logo logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg");
expect(screen.getByAltText("local_logo logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg");
});
});
@ -239,7 +239,7 @@ describe("MCPAppsPanel connected-app reachability (LIT-4861)", () => {
expect(onChange).not.toHaveBeenCalled();
expect(screen.queryByText("revoked_srv")).not.toBeInTheDocument();
expect(screen.getByText("Connected", { exact: false }).textContent).toBe("Connected");
expect(screen.getByText("Connected", { exact: false })).toHaveTextContent("Connected");
});
it("does not select a server when Connect resolves in the same tick the refetch drops it", async () => {

View file

@ -40,8 +40,8 @@ describe("MCPConnectPicker logos", () => {
render(<MCPConnectPicker accessToken="tok" selectedServers={[]} onChange={vi.fn()} />);
expect(await screen.findByText("external_logo")).toBeInTheDocument();
expect(screen.getByAltText("external_logo logo").getAttribute("src")).toBe("https://cdn.example.com/ext.png");
expect(screen.getByAltText("local_logo logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg");
expect(screen.getByAltText("external_logo logo")).toHaveAttribute("src", "https://cdn.example.com/ext.png");
expect(screen.getByAltText("local_logo logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg");
});
it("renders no logo at all for servers without logo_url", async () => {

View file

@ -22,6 +22,6 @@ describe("DefaultProxyAdminTag", () => {
it("should render empty text when userId is null", () => {
const { container } = render(<DefaultProxyAdminTag userId={null} />);
expect(screen.queryByText("Default Proxy Admin")).not.toBeInTheDocument();
expect(container.textContent).toBe("");
expect(container).toHaveTextContent("");
});
});

View file

@ -118,7 +118,7 @@ describe("DeleteResourceModal", () => {
const input = screen.getByPlaceholderText("DELETE");
await user.type(input, "DELETE");
const deleteButton = screen.getByRole("button", { name: /delete/i });
expect(deleteButton).not.toBeDisabled();
expect(deleteButton).toBeEnabled();
});
it("should reset requiredConfirmation input when modal opens", async () => {

View file

@ -144,7 +144,7 @@ describe("KeyLifecycleSettings", () => {
expect(screen.queryByText("Rotation Interval")).not.toBeInTheDocument();
await user.click(screen.getByRole("switch"));
await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument());
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
});
it("propagates a selected predefined interval", async () => {
@ -152,7 +152,7 @@ describe("KeyLifecycleSettings", () => {
renderWithProviders(<Harness />);
await user.click(screen.getByRole("switch"));
await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument());
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
await user.click(screen.getByRole("combobox"));
await user.click(await screen.findByText("90 days"));
@ -166,7 +166,7 @@ describe("KeyLifecycleSettings", () => {
renderWithProviders(<Harness />);
await user.click(screen.getByRole("switch"));
await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument());
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
await user.click(screen.getByRole("combobox"));
await user.click(await screen.findByText("Custom interval"));
@ -181,7 +181,7 @@ describe("KeyLifecycleSettings", () => {
renderWithProviders(<Harness />);
await user.click(screen.getByRole("switch"));
await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument());
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
await user.click(screen.getByRole("combobox"));
await user.click(await screen.findByText("Custom interval"));
@ -198,7 +198,7 @@ describe("KeyLifecycleSettings", () => {
renderWithProviders(<Harness />);
await user.click(screen.getByRole("switch"));
await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument());
expect(await screen.findByText("Rotation Interval")).toBeInTheDocument();
await user.click(screen.getByRole("combobox"));
await user.click(await screen.findByText("Custom interval"));

View file

@ -47,7 +47,7 @@ describe("NewBadge", () => {
const { container } = render(<NewBadge />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should render badge with dot when dot prop is true", () => {

View file

@ -46,7 +46,7 @@ describe("CustomTooltip", () => {
label: "2024-01-15",
};
const { container } = render(<CustomTooltip {...props} />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should return null when payload is empty", () => {
@ -56,7 +56,7 @@ describe("CustomTooltip", () => {
label: "2024-01-15",
};
const { container } = render(<CustomTooltip {...props} />);
expect(container.firstChild).toBeNull();
expect(container).toBeEmptyDOMElement();
});
it("should display formatted category names", () => {

View file

@ -58,8 +58,8 @@ describe("key router settings wiring, /key/info payload through to rendered outp
it("should not leak a field the accordion has no control for into the editor", async () => {
render(renderAccordion(KEY_INFO_ROUTER_SETTINGS));
await waitFor(() => expect(screen.getByTestId("loadbalancing")).toBeInTheDocument());
expect(screen.getByTestId("loadbalancing").textContent).not.toContain("tag_routing_prefix");
expect(await screen.findByTestId("loadbalancing")).toBeInTheDocument();
expect(screen.getByTestId("loadbalancing")).not.toHaveTextContent(/tag_routing_prefix/);
});
it("should render an empty editor for a key holding only fields it cannot show", async () => {

View file

@ -519,6 +519,7 @@ describe("EditAutoRouterModal custom classifier prompt and fallback", () => {
await user.click(await screen.findByText("Advanced: Classification Method"));
expect(await screen.findByRole("button", { name: "Edit custom prompt" })).toBeInTheDocument();
// eslint-disable-next-line jest-dom/prefer-checked -- antd sets the checked attribute without the DOM property, so toBeChecked reads false
expect(screen.getByRole("radio", { name: /Route to the default model/ })).toHaveAttribute("checked");
await user.click(screen.getByRole("button", { name: /save changes/i }));

View file

@ -101,13 +101,13 @@ describe("EmailSettings", () => {
renderWithProviders(<EmailSettings accessToken="sk-test" premiumUser={false} alerts={alerts} />);
expect(inputNamed("EMAIL_LOGO_URL")).toBeDisabled();
expect(inputNamed("SMTP_HOST")).not.toBeDisabled();
expect(inputNamed("SMTP_HOST")).toBeEnabled();
});
it("leaves the premium-only fields editable for premium users", () => {
renderWithProviders(<EmailSettings accessToken="sk-test" premiumUser alerts={alerts} />);
expect(inputNamed("EMAIL_LOGO_URL")).not.toBeDisabled();
expect(inputNamed("EMAIL_LOGO_URL")).toBeEnabled();
});
it("triggers a live email health check", async () => {

View file

@ -9,8 +9,8 @@ describe("BudgetFallbacksEditor", () => {
it("renders empty state with add button", () => {
const onChange = vi.fn();
render(<BudgetFallbacksEditor value={{}} onChange={onChange} availableModels={MODELS} />);
expect(screen.getByText("Add Budget Fallback")).toBeTruthy();
expect(screen.getByText(/reroute to fallback models/)).toBeTruthy();
expect(screen.getByText("Add Budget Fallback")).toBeInTheDocument();
expect(screen.getByText(/reroute to fallback models/)).toBeInTheDocument();
});
it("renders existing entries from value prop", () => {
@ -22,9 +22,9 @@ describe("BudgetFallbacksEditor", () => {
availableModels={MODELS}
/>,
);
expect(screen.getByText("IF BUDGET EXCEEDED, TRY")).toBeTruthy();
expect(screen.getByText("Primary Model")).toBeTruthy();
expect(screen.getByText("Fallback Models")).toBeTruthy();
expect(screen.getByText("IF BUDGET EXCEEDED, TRY")).toBeInTheDocument();
expect(screen.getByText("Primary Model")).toBeInTheDocument();
expect(screen.getByText("Fallback Models")).toBeInTheDocument();
});
it("adds a new empty entry when clicking add button", async () => {
@ -33,7 +33,7 @@ describe("BudgetFallbacksEditor", () => {
render(<BudgetFallbacksEditor value={{}} onChange={onChange} availableModels={MODELS} />);
await user.click(screen.getByText("Add Budget Fallback"));
expect(screen.getByText("Primary Model")).toBeTruthy();
expect(screen.getByText("Primary Model")).toBeInTheDocument();
expect(onChange).toHaveBeenCalledWith({});
});
@ -81,8 +81,8 @@ describe("BudgetFallbacksEditor", () => {
expect(screen.getAllByText("Primary Model").length).toBe(1);
rerender(<BudgetFallbacksEditor key={2} value={{}} onChange={onChange} availableModels={MODELS} />);
expect(screen.queryByText("Primary Model")).toBeNull();
expect(screen.getByText("Add Budget Fallback")).toBeTruthy();
expect(screen.queryByText("Primary Model")).not.toBeInTheDocument();
expect(screen.getByText("Add Budget Fallback")).toBeInTheDocument();
});
it("shows ordering hint when multiple fallback models are configured", () => {
@ -94,6 +94,6 @@ describe("BudgetFallbacksEditor", () => {
availableModels={MODELS}
/>,
);
expect(screen.getByText(/first model still within its own budget/)).toBeTruthy();
expect(screen.getByText(/first model still within its own budget/)).toBeInTheDocument();
});
});

View file

@ -456,8 +456,8 @@ describe("Sidebar (leftnav)", () => {
const costOptimization = container.querySelector('a[href*="cost-optimization"]');
expect(costOptimization).not.toBeNull();
expect(costOptimization!.textContent).toContain("Cost Optimization");
expect(costOptimization!.textContent).toContain("Beta");
expect(costOptimization!).toHaveTextContent(/Cost Optimization/);
expect(costOptimization!).toHaveTextContent(/Beta/);
expect(container.querySelector('a[href*="projects"]')).toBeNull();
});

View file

@ -34,7 +34,7 @@ describe("LoggingSettingsView logos", () => {
it("renders a letter avatar for the custom callback API, which has no bundled logo", () => {
render(<LoggingSettingsView disabledCallbacks={["custom_callback_api"]} />);
expect(screen.queryByAltText("Custom Callback API logo")).toBeNull();
expect(screen.queryByAltText("Custom Callback API logo")).not.toBeInTheDocument();
expect(screen.getByText("C")).toBeInTheDocument();
});
});

View file

@ -97,7 +97,7 @@ describe("CredentialModal", () => {
expect(screen.getByText("Add Credential")).toBeInTheDocument();
const nameInput = screen.getByLabelText("Credential Name:") as HTMLInputElement;
expect(nameInput.value).toBe("");
expect(nameInput.disabled).toBe(false);
expect(nameInput).toBeEnabled();
});
it("shows provider-specific fields for the selected provider", async () => {
@ -124,7 +124,7 @@ describe("CredentialModal", () => {
await waitFor(() => {
const nameInput = screen.getByLabelText("Credential Name:") as HTMLInputElement;
expect(nameInput.value).toBe("test-credential");
expect(nameInput.disabled).toBe(true);
expect(nameInput).toBeDisabled();
});
});
@ -134,7 +134,7 @@ describe("CredentialModal", () => {
existingCredential: { ...mockCredential, credential_name: "" },
});
expect((screen.getByLabelText("Credential Name:") as HTMLInputElement).disabled).toBe(true);
expect(screen.getByLabelText("Credential Name:")).toBeDisabled();
});
});
});

View file

@ -179,7 +179,7 @@ describe("HealthCheckComponent", () => {
await user.click(screen.getByTestId("datatable-select-row-id-alpha"));
await user.click(screen.getByTestId("clear-health-selection"));
expect(screen.getByTestId("datatable-select-row-id-alpha")).toHaveAttribute("aria-checked", "false");
expect(screen.getByTestId("datatable-select-row-id-alpha")).not.toBeChecked();
expect(screen.getByTestId("run-health-checks")).toHaveTextContent("Run All Checks");
});
@ -195,7 +195,7 @@ describe("HealthCheckComponent", () => {
await user.click(screen.getByTestId("pagination-next"));
expect(screen.queryByTestId("clear-health-selection")).not.toBeInTheDocument();
expect(screen.getByTestId("datatable-select-row-id-alpha")).toHaveAttribute("aria-checked", "false");
expect(screen.getByTestId("datatable-select-row-id-alpha")).not.toBeChecked();
});
});

View file

@ -955,8 +955,8 @@ describe("ModelInfoView", () => {
await waitFor(() => {
expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o-mini", "chat");
expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat");
});
expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat");
expect(mockTestConnectionRequest).not.toHaveBeenCalled();
});
@ -988,8 +988,8 @@ describe("ModelInfoView", () => {
await waitFor(() => {
expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o-mini", "chat");
expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat");
});
expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat");
});
it("does not duplicate the default model as a test target when it is already covered by a configured tier", async () => {
@ -1128,7 +1128,7 @@ describe("ModelInfoView", () => {
render(<ModelInfoView {...DEFAULT_ADMIN_PROPS} />, { wrapper });
const logo = await screen.findByAltText("openai logo");
expect(logo.getAttribute("src")).toContain("openai_small");
expect(logo).toHaveAttribute("src", expect.stringContaining("openai_small"));
});
it("renders a letter avatar instead of an img for an unknown provider slug", async () => {

View file

@ -16,8 +16,8 @@ describe("CostOptimizationFeedbackBanner", () => {
});
it("hides itself and persists the dismissal when the dismiss button is clicked", () => {
const { queryByText, getByLabelText } = render(<CostOptimizationFeedbackBanner />);
expect(queryByText("Help shape cost optimization")).toBeInTheDocument();
const { getByText, queryByText, getByLabelText } = render(<CostOptimizationFeedbackBanner />);
expect(getByText("Help shape cost optimization")).toBeInTheDocument();
fireEvent.click(getByLabelText("Dismiss banner"));

View file

@ -10,8 +10,8 @@ describe("Logo", () => {
it("renders the bundled logo untouched by the server root path for a known provider", () => {
render(<Logo provider="openai" />);
const img = screen.getByRole("img", { name: "openai logo" });
expect(img.getAttribute("src")).toBe(providerLogoMap[Providers.OpenAI]);
expect(img.getAttribute("src")).toContain("openai_small");
expect(img).toHaveAttribute("src", providerLogoMap[Providers.OpenAI]);
expect(img).toHaveAttribute("src", expect.stringContaining("openai_small"));
});
it("renders a letter avatar and no img for an unknown provider", () => {
@ -29,12 +29,12 @@ describe("Logo", () => {
it("resolves a backend asset path through the server root path in src mode", () => {
render(<Logo src="/ui/assets/logos/github.svg" label="GitHub" />);
const img = screen.getByRole("img", { name: "GitHub logo" });
expect(img.getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg");
expect(img).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg");
});
it("passes an external https URL through untouched in src mode", () => {
render(<Logo src="https://cdn.example.com/logo.png" label="Ext" />);
expect(screen.getByRole("img").getAttribute("src")).toBe("https://cdn.example.com/logo.png");
expect(screen.getByRole("img")).toHaveAttribute("src", "https://cdn.example.com/logo.png");
});
it("swaps to the letter avatar and warns with the failing URL on image error", () => {
@ -63,7 +63,7 @@ describe("Logo", () => {
rerender(<Logo src="/ui/assets/logos/github.svg" label="Agent" />);
const img = screen.getByRole("img", { name: "Agent logo" });
expect(img.getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg");
expect(img).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg");
rerender(<Logo src="/ui/assets/logos/broken.svg" label="Agent" />);
expect(screen.queryByRole("img")).not.toBeInTheDocument();

View file

@ -96,7 +96,7 @@ vi.mock("./Navbar/CommunityEngagementButtons/CommunityEngagementButtons", () =>
let mockUseThemeImpl = () => ({ logoUrl: null as string | null });
let mockUseHealthReadinessDetailsImpl = () => ({ data: null as any });
let mockGetLocalStorageItemImpl = (key: string) => null as string | null;
let mockUseAuthorizedImpl = () => ({
const mockUseAuthorizedImpl = () => ({
userId: "test-user",
userEmail: "test@example.com",
userRole: "Admin",

View file

@ -611,7 +611,7 @@ describe("CreateKey", () => {
});
await waitFor(() => {
expect(screen.getByTestId("org-dropdown")).not.toBeDisabled();
expect(screen.getByTestId("org-dropdown")).toBeEnabled();
});
});

View file

@ -124,9 +124,8 @@ test("renders organization view after loading data", async () => {
/>,
);
await waitFor(() => {
expect(findAllByText("Acme Corp")).toBeTruthy();
});
const [orgName] = await findAllByText("Acme Corp");
expect(orgName).toBeInTheDocument();
});
test("should display empty state when organization has no members", async () => {

View file

@ -117,8 +117,8 @@ describe("PerUserUsage", () => {
const xPositions = new Set(rectangles.map((rect) => rect.getAttribute("d")?.match(/^M\s*([\d.]+)/)?.[1]));
expect(xPositions.size).toBe(3);
expect(chart.textContent).toContain("curl/8.0");
expect(chart.textContent).toContain("Unknown");
expect(chart).toHaveTextContent("curl/8.0");
expect(chart).toHaveTextContent("Unknown");
for (const bucket of [
"1-9 requests",
"10-99 requests",
@ -127,7 +127,7 @@ describe("PerUserUsage", () => {
"10K-99.9K requests",
"100K+ requests",
]) {
expect(chart.textContent).toContain(bucket);
expect(chart).toHaveTextContent(bucket);
}
const tickTexts = Array.from(chart.querySelectorAll(".recharts-cartesian-axis-tick-value")).map(

Some files were not shown because too many files have changed in this diff Show more