Add unit tests for 5 previously untested UI components

Tests for HelpLink, ScoreChart, AgentCard, ToolPoliciesView, and CostBreakdownViewer (33 tests total).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
yuneng-jiang
2026-03-13 22:48:50 -07:00
co-authored by Claude Opus 4.6
parent 6549b4583f
commit 1b0c4bdbb7
5 changed files with 440 additions and 0 deletions
@@ -0,0 +1,54 @@
import React from "react";
import { describe, it, expect, vi } from "vitest";
import { screen } from "@testing-library/react";
import { renderWithProviders } from "../../../tests/test-utils";
import { ScoreChart } from "./ScoreChart";
vi.mock("@tremor/react", async (importOriginal) => {
const actual = await importOriginal<typeof import("@tremor/react")>();
return {
...actual,
BarChart: ({ data, categories }: { data: any[]; categories: string[] }) => (
<div data-testid="bar-chart">
{data.map((d, i) => (
<span key={i}>
{d.date}: {categories.map((c) => `${c}=${d[c]}`).join(", ")}
</span>
))}
</div>
),
};
});
describe("ScoreChart", () => {
it("should render the title", () => {
renderWithProviders(<ScoreChart />);
expect(screen.getByText("Request Outcomes Over Time")).toBeInTheDocument();
});
it("should show empty state when no data is provided", () => {
renderWithProviders(<ScoreChart />);
expect(screen.getByText("No chart data for this period")).toBeInTheDocument();
});
it("should show empty state when data is an empty array", () => {
renderWithProviders(<ScoreChart data={[]} />);
expect(screen.getByText("No chart data for this period")).toBeInTheDocument();
});
it("should render the chart when data is provided", () => {
const data = [
{ date: "2026-03-01", passed: 10, blocked: 2 },
{ date: "2026-03-02", passed: 15, blocked: 1 },
];
renderWithProviders(<ScoreChart data={data} />);
expect(screen.queryByText("No chart data for this period")).not.toBeInTheDocument();
expect(screen.getByText(/2026-03-01/)).toBeInTheDocument();
expect(screen.getByText(/2026-03-02/)).toBeInTheDocument();
});
});
@@ -0,0 +1,117 @@
import React from "react";
import { describe, it, expect, vi } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../tests/test-utils";
import { HelpLink, HelpIcon, DocsMenu } from "./HelpLink";
describe("HelpLink", () => {
it("should render with default children and open in new tab", () => {
renderWithProviders(<HelpLink href="https://docs.example.com" />);
const link = screen.getByRole("link", { name: /learn more/i });
expect(link).toHaveAttribute("href", "https://docs.example.com");
expect(link).toHaveAttribute("target", "_blank");
expect(link).toHaveAttribute("rel", "noopener noreferrer");
});
it("should render custom children text", () => {
renderWithProviders(
<HelpLink href="https://docs.example.com">Custom docs link</HelpLink>
);
expect(screen.getByText("Custom docs link")).toBeInTheDocument();
});
it("should include a screen-reader-only label for accessibility", () => {
renderWithProviders(<HelpLink href="https://docs.example.com" />);
expect(screen.getByText("(opens in a new tab)")).toBeInTheDocument();
});
});
describe("HelpIcon", () => {
it("should render a help button with accessible label", () => {
renderWithProviders(<HelpIcon content="Some help text" />);
expect(screen.getByRole("button", { name: /help information/i })).toBeInTheDocument();
});
it("should show tooltip content on hover", async () => {
const user = userEvent.setup();
renderWithProviders(<HelpIcon content="Tooltip help text" />);
await user.hover(screen.getByRole("button", { name: /help information/i }));
expect(screen.getByText("Tooltip help text")).toBeInTheDocument();
});
it("should show learn more link when learnMoreHref is provided", async () => {
const user = userEvent.setup();
renderWithProviders(
<HelpIcon
content="Help text"
learnMoreHref="https://docs.example.com"
learnMoreText="Read docs"
/>
);
await user.hover(screen.getByRole("button", { name: /help information/i }));
const link = screen.getByRole("link", { name: /read docs/i });
expect(link).toHaveAttribute("href", "https://docs.example.com");
});
it("should not show learn more link when learnMoreHref is not provided", async () => {
const user = userEvent.setup();
renderWithProviders(<HelpIcon content="Help text" />);
await user.hover(screen.getByRole("button", { name: /help information/i }));
expect(screen.queryByRole("link")).not.toBeInTheDocument();
});
});
describe("DocsMenu", () => {
const items = [
{ label: "Custom pricing", href: "https://docs.example.com/pricing" },
{ label: "Cost tracking", href: "https://docs.example.com/cost" },
];
it("should render the menu button with default text", () => {
renderWithProviders(<DocsMenu items={items} />);
expect(screen.getByRole("button", { name: /docs/i })).toBeInTheDocument();
});
it("should show menu items when button is clicked", async () => {
const user = userEvent.setup();
renderWithProviders(<DocsMenu items={items} />);
await user.click(screen.getByRole("button", { name: /docs/i }));
expect(screen.getByText("Custom pricing")).toBeInTheDocument();
expect(screen.getByText("Cost tracking")).toBeInTheDocument();
});
it("should close the menu when an item is clicked", async () => {
const user = userEvent.setup();
renderWithProviders(<DocsMenu items={items} />);
await user.click(screen.getByRole("button", { name: /docs/i }));
await user.click(screen.getByText("Custom pricing"));
expect(screen.queryByText("Cost tracking")).not.toBeInTheDocument();
});
it("should set aria-expanded correctly based on menu state", async () => {
const user = userEvent.setup();
renderWithProviders(<DocsMenu items={items} />);
const button = screen.getByRole("button", { name: /docs/i });
expect(button).toHaveAttribute("aria-expanded", "false");
await user.click(button);
expect(button).toHaveAttribute("aria-expanded", "true");
});
});
@@ -0,0 +1,53 @@
import React from "react";
import { describe, it, expect, vi } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../tests/test-utils";
import ToolPoliciesView from "./ToolPoliciesView";
vi.mock("@/components/ToolDetail", () => ({
ToolDetail: ({ toolName, onBack }: { toolName: string; onBack: () => void }) => (
<div>
<span>Detail: {toolName}</span>
<button onClick={onBack}>Back</button>
</div>
),
}));
vi.mock("@/components/ToolPolicies", () => ({
ToolPolicies: ({ onSelectTool }: { onSelectTool: (name: string) => void }) => (
<div>
<span>Tool Policies Overview</span>
<button onClick={() => onSelectTool("my-tool")}>Select Tool</button>
</div>
),
}));
describe("ToolPoliciesView", () => {
it("should render the overview by default", () => {
renderWithProviders(<ToolPoliciesView accessToken="token" userRole="Admin" />);
expect(screen.getByText("Tool Policies Overview")).toBeInTheDocument();
});
it("should navigate to tool detail when a tool is selected", async () => {
const user = userEvent.setup();
renderWithProviders(<ToolPoliciesView accessToken="token" userRole="Admin" />);
await user.click(screen.getByRole("button", { name: /select tool/i }));
expect(screen.getByText("Detail: my-tool")).toBeInTheDocument();
expect(screen.queryByText("Tool Policies Overview")).not.toBeInTheDocument();
});
it("should navigate back to overview when back is clicked", async () => {
const user = userEvent.setup();
renderWithProviders(<ToolPoliciesView accessToken="token" userRole="Admin" />);
await user.click(screen.getByRole("button", { name: /select tool/i }));
await user.click(screen.getByRole("button", { name: /back/i }));
expect(screen.getByText("Tool Policies Overview")).toBeInTheDocument();
expect(screen.queryByText("Detail: my-tool")).not.toBeInTheDocument();
});
});
@@ -0,0 +1,99 @@
import React from "react";
import { describe, it, expect, vi } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import AgentCard from "./agent_card";
import type { Agent } from "./types";
const baseAgent: Agent = {
agent_id: "agent-123",
agent_name: "Test Agent",
litellm_params: { model: "gpt-4" },
agent_card_params: {
description: "A test agent for unit testing",
url: "https://agent.example.com",
},
};
const defaultProps = {
agent: baseAgent,
onAgentClick: vi.fn(),
accessToken: "token-123",
isAdmin: false,
onAgentUpdated: vi.fn(),
};
describe("AgentCard", () => {
it("should render the agent name and description", () => {
renderWithProviders(<AgentCard {...defaultProps} />);
expect(screen.getByText("Test Agent")).toBeInTheDocument();
expect(screen.getByText("A test agent for unit testing")).toBeInTheDocument();
});
it("should show 'No description' when agent has no description", () => {
const agent = { ...baseAgent, agent_card_params: {} };
renderWithProviders(<AgentCard {...defaultProps} agent={agent} />);
expect(screen.getByText("No description")).toBeInTheDocument();
});
it("should show the agent URL when provided", () => {
renderWithProviders(<AgentCard {...defaultProps} />);
expect(screen.getByText("https://agent.example.com")).toBeInTheDocument();
});
it("should show 'Needs Setup' badge when agent has no key", () => {
renderWithProviders(<AgentCard {...defaultProps} />);
expect(screen.getByText("Needs Setup")).toBeInTheDocument();
expect(screen.getByText("No key assigned")).toBeInTheDocument();
});
it("should show 'Active' badge and key info when agent has a key", () => {
const keyInfo = { has_key: true, key_alias: "my-key" };
renderWithProviders(<AgentCard {...defaultProps} keyInfo={keyInfo} />);
expect(screen.getByText("Active")).toBeInTheDocument();
expect(screen.getByText("my-key")).toBeInTheDocument();
});
it("should call onAgentClick when card is clicked", async () => {
const user = userEvent.setup();
const onAgentClick = vi.fn();
renderWithProviders(<AgentCard {...defaultProps} onAgentClick={onAgentClick} />);
await user.click(screen.getByText("Test Agent"));
expect(onAgentClick).toHaveBeenCalledWith("agent-123");
});
it("should show delete button only for admins", () => {
const onDeleteClick = vi.fn();
const { unmount } = renderWithProviders(
<AgentCard {...defaultProps} isAdmin={false} onDeleteClick={onDeleteClick} />
);
expect(screen.queryByRole("button", { name: /delete/i })).not.toBeInTheDocument();
unmount();
renderWithProviders(
<AgentCard {...defaultProps} isAdmin={true} onDeleteClick={onDeleteClick} />
);
expect(screen.getByRole("button", { name: /delete/i })).toBeInTheDocument();
});
it("should call onDeleteClick with agent id and name when delete is clicked", async () => {
const user = userEvent.setup();
const onDeleteClick = vi.fn();
renderWithProviders(
<AgentCard {...defaultProps} isAdmin={true} onDeleteClick={onDeleteClick} />
);
await user.click(screen.getByRole("button", { name: /delete/i }));
expect(onDeleteClick).toHaveBeenCalledWith("agent-123", "Test Agent");
});
});
@@ -0,0 +1,117 @@
import React from "react";
import { describe, it, expect } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../../tests/test-utils";
import { CostBreakdownViewer, CostBreakdown } from "./CostBreakdownViewer";
describe("CostBreakdownViewer", () => {
it("should render nothing when there is no meaningful data", () => {
const { container } = renderWithProviders(
<CostBreakdownViewer costBreakdown={null} totalSpend={0} />
);
expect(container.firstChild).toBeNull();
});
it("should render nothing when costBreakdown is undefined", () => {
const { container } = renderWithProviders(
<CostBreakdownViewer costBreakdown={undefined} totalSpend={0} />
);
expect(container.firstChild).toBeNull();
});
it("should render the collapse header with heading and total", () => {
const breakdown: CostBreakdown = {
input_cost: 0.001,
output_cost: 0.002,
total_cost: 0.003,
};
renderWithProviders(
<CostBreakdownViewer costBreakdown={breakdown} totalSpend={0.003} />
);
expect(screen.getByRole("heading", { name: "Cost Breakdown" })).toBeInTheDocument();
});
it("should show input and output costs when the panel is expanded", async () => {
const user = userEvent.setup();
const breakdown: CostBreakdown = {
input_cost: 0.001,
output_cost: 0.002,
};
renderWithProviders(
<CostBreakdownViewer
costBreakdown={breakdown}
totalSpend={0.003}
promptTokens={500}
completionTokens={200}
/>
);
await user.click(screen.getByRole("heading", { name: "Cost Breakdown" }));
expect(screen.getByText("Input Cost:")).toBeVisible();
expect(screen.getByText("Output Cost:")).toBeVisible();
expect(screen.getByText(/500 prompt tokens/)).toBeVisible();
expect(screen.getByText(/200 completion tokens/)).toBeVisible();
});
it("should show '(Cached)' in the header when cacheHit is true", () => {
const breakdown: CostBreakdown = {
input_cost: 0.001,
output_cost: 0.002,
total_cost: 0.003,
};
renderWithProviders(
<CostBreakdownViewer
costBreakdown={breakdown}
totalSpend={0}
cacheHit="true"
/>
);
expect(screen.getByText(/\(Cached\)/)).toBeInTheDocument();
});
it("should show discount label with percentage when panel is expanded", async () => {
const user = userEvent.setup();
const breakdown: CostBreakdown = {
input_cost: 0.01,
output_cost: 0.02,
discount_percent: 0.1,
discount_amount: 0.003,
};
renderWithProviders(
<CostBreakdownViewer costBreakdown={breakdown} totalSpend={0.027} />
);
await user.click(screen.getByRole("heading", { name: "Cost Breakdown" }));
expect(screen.getByText(/Discount \(10\.00%\)/)).toBeVisible();
});
it("should show margin label with percentage when panel is expanded", async () => {
const user = userEvent.setup();
const breakdown: CostBreakdown = {
input_cost: 0.01,
output_cost: 0.02,
margin_percent: 0.15,
margin_total_amount: 0.005,
};
renderWithProviders(
<CostBreakdownViewer costBreakdown={breakdown} totalSpend={0.035} />
);
await user.click(screen.getByRole("heading", { name: "Cost Breakdown" }));
expect(screen.getByText(/Margin \(15\.00%\)/)).toBeVisible();
expect(screen.getByText("Final Calculated Cost:")).toBeVisible();
});
});