diff --git a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/AllModelsTab.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/AllModelsTab.test.tsx
index 813a365d36..34c1c3ca4b 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/AllModelsTab.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/AllModelsTab.test.tsx
@@ -1,5 +1,5 @@
import * as useAuthorizedModule from "@/app/(dashboard)/hooks/useAuthorized";
-import { render, screen, waitFor } from "@testing-library/react";
+import { renderWithProviders, screen, waitFor } from "../../../../../tests/test-utils";
import { beforeEach, describe, expect, it, vi } from "vitest";
import AllModelsTab from "./AllModelsTab";
@@ -116,7 +116,7 @@ describe("AllModelsTab", () => {
mockUseModelCostMap.mockReturnValueOnce(createModelCostMapMock({}));
- render();
+ renderWithProviders();
expect(screen.getByText("Current Team:")).toBeInTheDocument();
});
@@ -172,7 +172,7 @@ describe("AllModelsTab", () => {
mockUseModelsInfo.mockReturnValue({ data: modelData, isLoading: false, error: null });
- render();
+ renderWithProviders();
// Component shows API total_count (2), not filtered count
// Since default is "personal" team and models don't have direct_access, they're filtered out
@@ -233,7 +233,7 @@ describe("AllModelsTab", () => {
mockUseModelsInfo.mockReturnValue({ data: modelData, isLoading: false, error: null });
- render();
+ renderWithProviders();
// Component shows API total_count (2), not filtered count
// Since default is "personal" team and models don't have direct_access, they're filtered out
@@ -280,7 +280,7 @@ describe("AllModelsTab", () => {
mockUseModelsInfo.mockReturnValue({ data: modelData, isLoading: false, error: null });
- render();
+ renderWithProviders();
// Component shows API total_count (2), but only 1 model has direct_access
await waitFor(() => {
@@ -338,7 +338,7 @@ describe("AllModelsTab", () => {
mockUseModelsInfo.mockReturnValue({ data: modelData, isLoading: false, error: null });
- render();
+ renderWithProviders();
await waitFor(() => {
expect(screen.getByText("Config Model")).toBeInTheDocument();
@@ -380,7 +380,7 @@ describe("AllModelsTab", () => {
mockUseModelsInfo.mockReturnValue({ data: modelData, isLoading: false, error: null });
- render();
+ renderWithProviders();
await waitFor(() => {
expect(screen.getByText("Defined in config")).toBeInTheDocument();
@@ -426,7 +426,7 @@ describe("AllModelsTab", () => {
return { data: page1Data, isLoading: false, error: null };
});
- render();
+ renderWithProviders();
await waitFor(() => {
// Component calculates: ((1-1)*50)+1 = 1, Math.min(1*50, 2) = 2
@@ -479,7 +479,7 @@ describe("AllModelsTab", () => {
return { data: singlePageData, isLoading: false, error: null };
});
- render();
+ renderWithProviders();
await waitFor(() => {
expect(screen.getByText("Showing 1 - 1 of 1 results")).toBeInTheDocument();
diff --git a/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.test.tsx b/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.test.tsx
index 95120f6057..28991ebfa0 100644
--- a/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.test.tsx
+++ b/ui/litellm-dashboard/src/components/view_logs/GuardrailViewer/GuardrailViewer.test.tsx
@@ -19,68 +19,62 @@ describe("GuardrailViewer", () => {
vi.resetModules();
});
- it("shows header, status pill color, duration rounding, and time labels", () => {
+ it("shows header, status pill, and duration", () => {
const data = makeGuardrailInformation({ duration: 1.23456, guardrail_status: "success" });
renderWithProviders();
- expect(screen.getByText("Guardrail Information")).toBeInTheDocument();
- // header status pill (success => green)
- const statusBadges = screen.getAllByText("success");
- // there are two status locations: header chip and grid "Status"
- expect(statusBadges.length).toBeGreaterThanOrEqual(1);
- // Quick class assertion for at least one of them
- expect(statusBadges[0].className).toMatch(/bg-green-100/);
+ expect(screen.getByText("Guardrails & Policy Compliance")).toBeInTheDocument();
+ // header shows passed count
+ expect(screen.getByText(/1 Passed/)).toBeInTheDocument();
+ // The PASSED badge in the evaluation card
+ expect(screen.getByText("PASSED")).toBeInTheDocument();
- // duration displays with 4 decimals
- expect(screen.getByText(/1\.2346s/)).toBeInTheDocument();
-
- // time labels exist
- expect(screen.getByText("Start Time:")).toBeInTheDocument();
- expect(screen.getByText("End Time:")).toBeInTheDocument();
+ // duration displays in ms format: Math.round(1.23456 * 1000) = 1235
+ expect(screen.getByText("1235ms")).toBeInTheDocument();
});
- it("calculates and displays masked entity totals with pluralization", () => {
+ it("calculates and displays masked entity totals", async () => {
+ const user = userEvent.setup();
const data = makeGuardrailInformation({
masked_entity_count: { EMAIL_ADDRESS: 2, PHONE_NUMBER: 1 },
});
renderWithProviders();
- expect(screen.getByText("3 masked entities")).toBeInTheDocument();
- // summary chips for each entry
+ // In collapsed state, the match count badge is visible
+ expect(screen.getByText("3 matched")).toBeInTheDocument();
+
+ // Expand the evaluation card to see entity details
+ await user.click(screen.getByText("pii-rail"));
+ // summary chips for each entry inside expanded card
expect(screen.getByText("EMAIL_ADDRESS: 2")).toBeInTheDocument();
expect(screen.getByText("PHONE_NUMBER: 1")).toBeInTheDocument();
});
- it("hides masked badge & summary when count is zero/empty", () => {
+ it("hides matched badge when count is zero/empty", () => {
const data = makeGuardrailInformation({ masked_entity_count: {} });
renderWithProviders();
- expect(screen.queryByText(/masked entity/)).not.toBeInTheDocument();
- expect(screen.queryByText("Masked Entity Summary")).not.toBeInTheDocument();
+ expect(screen.queryByText(/matched/)).not.toBeInTheDocument();
});
- it("toggles main section open/closed and chevron rotation class", async () => {
+ it("toggles evaluation card open/closed on click", async () => {
const user = userEvent.setup();
- const data = makeGuardrailInformation();
- const { container } = renderWithProviders();
-
- const header = screen.getByText("Guardrail Information").closest(".ant-collapse-header")!;
- // Initially expanded (content is visible)
- expect(screen.getByText("Masked Entity Summary")).toBeInTheDocument();
-
- // Click to collapse
- await user.click(header);
- // Wait for collapse animation and content to be hidden
- await waitFor(() => {
- const contentBox = container.querySelector(".ant-collapse-content-box");
- expect(contentBox).not.toBeVisible();
+ const data = makeGuardrailInformation({
+ masked_entity_count: { EMAIL_ADDRESS: 2 },
});
+ renderWithProviders();
- // Click to expand again
- await user.click(header);
- // Wait for expand animation
+ // Initially collapsed — masked entity details not visible
+ expect(screen.queryByText("EMAIL_ADDRESS: 2")).not.toBeInTheDocument();
+
+ // Click to expand
+ await user.click(screen.getByText("pii-rail"));
+ expect(screen.getByText("EMAIL_ADDRESS: 2")).toBeInTheDocument();
+
+ // Click again to collapse
+ await user.click(screen.getByText("pii-rail"));
await waitFor(() => {
- expect(screen.getByText("Masked Entity Summary")).toBeVisible();
+ expect(screen.queryByText("EMAIL_ADDRESS: 2")).not.toBeInTheDocument();
});
});
@@ -97,6 +91,9 @@ describe("GuardrailViewer", () => {
});
renderWithProviders();
+ // Expand the card to see provider-specific content
+ const user = userEvent.setup();
+ await user.click(screen.getByText("pii-rail"));
expect(screen.getByTestId("presidio-mock")).toHaveTextContent("presidio 2");
});
@@ -112,6 +109,10 @@ describe("GuardrailViewer", () => {
guardrail_response: [makeEntity()],
});
renderWithProviders();
+
+ // Expand the card to see provider-specific content
+ const user = userEvent.setup();
+ await user.click(screen.getByText("pii-rail"));
expect(screen.getByTestId("presidio-mock")).toHaveTextContent("count:1");
});
@@ -127,22 +128,31 @@ describe("GuardrailViewer", () => {
guardrail_response: makeBedrockResponse({ action: "GUARDRAIL_INTERVENED" }),
});
renderWithProviders();
+
+ // Expand the card to see provider-specific content
+ const user = userEvent.setup();
+ await user.click(screen.getByText("pii-rail"));
expect(screen.getByTestId("bedrock-mock")).toHaveTextContent("GUARDRAIL_INTERVENED");
});
- it("unknown provider renders neither Presidio nor Bedrock details", () => {
+ it("unknown provider renders neither Presidio nor Bedrock details", async () => {
+ const user = userEvent.setup();
const data = makeGuardrailInformation({
guardrail_provider: "unknown",
});
renderWithProviders();
- // Summary still present
- expect(screen.getByText("Guardrail Information")).toBeInTheDocument();
- // No provider sections
+ // Header still present
+ expect(screen.getByText("Guardrails & Policy Compliance")).toBeInTheDocument();
+
+ // Expand the card
+ await user.click(screen.getByText("pii-rail"));
+ // No Presidio or Bedrock sections
expect(screen.queryByText(/Detected Entities/)).not.toBeInTheDocument();
expect(screen.queryByText(/Raw Bedrock Guardrail Response/)).not.toBeInTheDocument();
});
- it("integration: renders with real Bedrock details without mocks", () => {
+ it("integration: renders with real Bedrock details without mocks", async () => {
+ const user = userEvent.setup();
const data = makeGuardrailInformation({
guardrail_provider: "bedrock",
guardrail_response: makeBedrockResponse({
@@ -152,6 +162,9 @@ describe("GuardrailViewer", () => {
});
renderWithProviders();
+ // Expand the card to reveal Bedrock details
+ await user.click(screen.getByText("pii-rail"));
+
// Bedrock summary bits
expect(screen.getByText("Outputs")).toBeInTheDocument();
expect(screen.getByText("ok")).toBeInTheDocument();