[Fix] Update UI tests for GuardrailViewer rewrite and AllModelsTab QueryClient

GuardrailViewer was rewritten from ant-design Collapse to a custom card
layout. Tests now match the new component: updated header text, ms-based
duration, expand-to-reveal provider details, and removed ant-collapse
references.

AllModelsTab tests failed because ModelSettingsModal now uses useMutation
via useStoreModelInDB. Switched from bare render() to renderWithProviders()
which wraps in QueryClientProvider.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
yuneng-jiang
2026-02-20 17:25:36 -08:00
co-authored by Claude Opus 4.6
parent ed4b654934
commit e5619c39a0
2 changed files with 65 additions and 52 deletions
@@ -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(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
expect(screen.getByText("Current Team:")).toBeInTheDocument();
});
@@ -172,7 +172,7 @@ describe("AllModelsTab", () => {
mockUseModelsInfo.mockReturnValue({ data: modelData, isLoading: false, error: null });
render(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
// 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(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
// 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(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
// 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(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
await waitFor(() => {
expect(screen.getByText("Config Model")).toBeInTheDocument();
@@ -380,7 +380,7 @@ describe("AllModelsTab", () => {
mockUseModelsInfo.mockReturnValue({ data: modelData, isLoading: false, error: null });
render(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
await waitFor(() => {
expect(screen.getByText("Defined in config")).toBeInTheDocument();
@@ -426,7 +426,7 @@ describe("AllModelsTab", () => {
return { data: page1Data, isLoading: false, error: null };
});
render(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
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(<AllModelsTab {...defaultProps} />);
renderWithProviders(<AllModelsTab {...defaultProps} />);
await waitFor(() => {
expect(screen.getByText("Showing 1 - 1 of 1 results")).toBeInTheDocument();
@@ -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(<GuardrailViewer data={data} />);
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(<GuardrailViewer data={data} />);
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(<GuardrailViewer data={data} />);
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(<GuardrailViewer data={data} />);
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(<GuardrailViewer data={data} />);
// 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(<Component data={data} />);
// 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(<Component data={data} />);
// 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(<Component data={data} />);
// 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(<GuardrailViewer data={data} />);
// 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(<GuardrailViewer data={data} />);
// 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();