diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/common/queryKeysFactory.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/common/queryKeysFactory.test.ts
new file mode 100644
index 0000000000..39afd04409
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/common/queryKeysFactory.test.ts
@@ -0,0 +1,34 @@
+import { describe, it, expect } from "vitest";
+import { createQueryKeys } from "./queryKeysFactory";
+
+describe("createQueryKeys", () => {
+ const keys = createQueryKeys("books");
+
+ it("should return the resource name as the base key", () => {
+ expect(keys.all).toEqual(["books"]);
+ });
+
+ it("should generate a lists key", () => {
+ expect(keys.lists()).toEqual(["books", "list"]);
+ });
+
+ it("should generate a list key with params", () => {
+ expect(keys.list({ page: 1, limit: 10 })).toEqual([
+ "books",
+ "list",
+ { params: { page: 1, limit: 10 } },
+ ]);
+ });
+
+ it("should generate a list key with undefined params when none provided", () => {
+ expect(keys.list()).toEqual(["books", "list", { params: undefined }]);
+ });
+
+ it("should generate a details key", () => {
+ expect(keys.details()).toEqual(["books", "detail"]);
+ });
+
+ it("should generate a detail key for a specific ID", () => {
+ expect(keys.detail("123")).toEqual(["books", "detail", "123"]);
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsHeaderTabs.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsHeaderTabs.test.tsx
new file mode 100644
index 0000000000..50a7f10f04
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsHeaderTabs.test.tsx
@@ -0,0 +1,54 @@
+import { render, screen } from "@testing-library/react";
+import React from "react";
+import { describe, expect, it, vi } from "vitest";
+import TeamsHeaderTabs from "./TeamsHeaderTabs";
+
+vi.mock("@tremor/react", () => ({
+ TabGroup: ({ children, ...props }: any) =>
{children}
,
+ TabList: ({ children, ...props }: any) => {children}
,
+ Tab: ({ children, ...props }: any) => ,
+ TabPanels: ({ children, ...props }: any) => {children}
,
+ Text: ({ children, ...props }: any) => {children},
+ Icon: ({ onClick, ...props }: any) => ,
+}));
+
+vi.mock("@heroicons/react/outline", () => ({
+ RefreshIcon: () => ,
+}));
+
+const renderTabs = (props: Partial[0]> = {}) => {
+ const defaults = {
+ lastRefreshed: "",
+ onRefresh: vi.fn(),
+ userRole: "Internal User",
+ children: Panel
,
+ };
+ return render();
+};
+
+describe("TeamsHeaderTabs", () => {
+ it("should render 'Your Teams' and 'Available Teams' tabs", () => {
+ renderTabs();
+
+ expect(screen.getByText("Your Teams")).toBeInTheDocument();
+ expect(screen.getByText("Available Teams")).toBeInTheDocument();
+ });
+
+ it("should render 'Default Team Settings' tab when user is Admin", () => {
+ renderTabs({ userRole: "Admin" });
+
+ expect(screen.getByText("Default Team Settings")).toBeInTheDocument();
+ });
+
+ it("should not render 'Default Team Settings' tab for non-admin users", () => {
+ renderTabs({ userRole: "Internal User" });
+
+ expect(screen.queryByText("Default Team Settings")).not.toBeInTheDocument();
+ });
+
+ it("should display last refreshed time when provided", () => {
+ renderTabs({ lastRefreshed: "2024-06-01 12:00:00" });
+
+ expect(screen.getByText("Last Refreshed: 2024-06-01 12:00:00")).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsTable/TeamsTable.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsTable/TeamsTable.test.tsx
new file mode 100644
index 0000000000..6b072ababb
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsTable/TeamsTable.test.tsx
@@ -0,0 +1,129 @@
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import React from "react";
+import { describe, expect, it, vi } from "vitest";
+import { Team } from "@/components/key_team_helpers/key_list";
+import TeamsTable from "./TeamsTable";
+
+vi.mock("@tremor/react", () => ({
+ Button: React.forwardRef(({ children, ...props }, ref) =>
+ React.createElement("button", { ...props, ref }, children),
+ ),
+ Icon: ({ onClick, ...props }: any) => ,
+ Table: ({ children }: any) => ,
+ TableHead: ({ children }: any) => {children},
+ TableBody: ({ children }: any) => {children},
+ TableRow: ({ children }: any) => {children}
,
+ TableHeaderCell: ({ children }: any) => {children} | ,
+ TableCell: ({ children, ...props }: any) => {children} | ,
+ Text: ({ children }: any) => {children},
+}));
+
+vi.mock("antd", () => ({
+ Tooltip: ({ children }: any) => <>{children}>,
+}));
+
+vi.mock("@heroicons/react/outline", () => ({
+ PencilAltIcon: () => ,
+ TrashIcon: () => ,
+}));
+
+vi.mock("@/utils/dataUtils", () => ({
+ formatNumberWithCommas: (val: number, decimals: number) =>
+ val != null ? val.toFixed(decimals) : "N/A",
+}));
+
+vi.mock("@/app/(dashboard)/teams/components/TeamsTable/ModelsCell", () => ({
+ default: ({ team }: any) => {team.models.join(",")} | ,
+}));
+
+vi.mock("@/app/(dashboard)/teams/components/TeamsTable/YourRoleCell/YourRoleCell", () => ({
+ default: ({ team }: any) => {team.team_id} | ,
+}));
+
+const makeTeam = (overrides: Partial = {}): Team => ({
+ team_id: "team-abc1234",
+ team_alias: "Platform",
+ models: ["gpt-4"],
+ max_budget: 500,
+ budget_duration: null,
+ tpm_limit: null,
+ rpm_limit: null,
+ organization_id: "org-1",
+ created_at: "2024-06-01T00:00:00Z",
+ keys: [],
+ members_with_roles: [],
+ spend: 123.4567,
+ ...overrides,
+});
+
+const defaultPerTeamInfo = {
+ "team-abc1234": {
+ keys: [{ token: "tok-1" } as any, { token: "tok-2" } as any],
+ team_info: {
+ members_with_roles: [{ user_id: "u1", role: "admin" } as any],
+ },
+ },
+};
+
+const renderTable = (overrides: Partial[0]> = {}) => {
+ const defaults = {
+ teams: [makeTeam()],
+ currentOrg: null,
+ perTeamInfo: defaultPerTeamInfo,
+ userRole: "Admin",
+ userId: "user-1",
+ setSelectedTeamId: vi.fn(),
+ setEditTeam: vi.fn(),
+ onDeleteTeam: vi.fn(),
+ };
+ return render();
+};
+
+describe("TeamsTable", () => {
+ it("should render table headers", () => {
+ renderTable();
+
+ expect(screen.getByText("Team Name")).toBeInTheDocument();
+ expect(screen.getByText("Team ID")).toBeInTheDocument();
+ expect(screen.getByText("Created")).toBeInTheDocument();
+ expect(screen.getByText("Spend (USD)")).toBeInTheDocument();
+ expect(screen.getByText("Budget (USD)")).toBeInTheDocument();
+ expect(screen.getByText("Models")).toBeInTheDocument();
+ expect(screen.getByText("Organization")).toBeInTheDocument();
+ expect(screen.getByText("Your Role")).toBeInTheDocument();
+ expect(screen.getByText("Info")).toBeInTheDocument();
+ });
+
+ it("should render team rows with team data", () => {
+ renderTable();
+
+ expect(screen.getByText("Platform")).toBeInTheDocument();
+ expect(screen.getByText("team-ab...")).toBeInTheDocument();
+ expect(screen.getByText("org-1")).toBeInTheDocument();
+ });
+
+ it("should show edit and delete icons for Admin users", () => {
+ renderTable({ userRole: "Admin" });
+
+ expect(screen.getAllByTestId("icon-btn").length).toBeGreaterThanOrEqual(2);
+ });
+
+ it("should not show edit and delete icons for non-Admin users", () => {
+ renderTable({ userRole: "Internal User" });
+
+ // Only the team ID button should be present, no icon-btn for edit/delete
+ const iconBtns = screen.queryAllByTestId("icon-btn");
+ expect(iconBtns).toHaveLength(0);
+ });
+
+ it("should call setSelectedTeamId when team ID button is clicked", async () => {
+ const user = userEvent.setup();
+ const setSelectedTeamId = vi.fn();
+ renderTable({ setSelectedTeamId });
+
+ await user.click(screen.getByText("team-ab..."));
+
+ expect(setSelectedTeamId).toHaveBeenCalledWith("team-abc1234");
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/onboarding/OnboardingForm.test.tsx b/ui/litellm-dashboard/src/app/onboarding/OnboardingForm.test.tsx
new file mode 100644
index 0000000000..d9e75388d1
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/onboarding/OnboardingForm.test.tsx
@@ -0,0 +1,95 @@
+import { render, screen } from "@testing-library/react";
+import React from "react";
+import { describe, expect, it, vi } from "vitest";
+import { OnboardingForm } from "./OnboardingForm";
+
+const mockUseOnboardingCredentials = vi.fn();
+const mockClaimToken = vi.fn();
+
+vi.mock("next/navigation", () => ({
+ useSearchParams: () => new URLSearchParams("invitation_id=inv-123"),
+}));
+
+vi.mock("jwt-decode", () => ({
+ jwtDecode: vi.fn(() => ({
+ user_email: "alice@example.com",
+ user_id: "user-1",
+ key: "access-tok",
+ })),
+}));
+
+vi.mock("@/app/(dashboard)/hooks/onboarding/useOnboarding", () => ({
+ useOnboardingCredentials: (...args: unknown[]) => mockUseOnboardingCredentials(...args),
+ useClaimOnboardingToken: () => ({ mutate: mockClaimToken, isPending: false }),
+}));
+
+vi.mock("@/components/networking", () => ({
+ getProxyBaseUrl: vi.fn(() => ""),
+}));
+
+vi.mock("./OnboardingLoadingView", () => ({
+ OnboardingLoadingView: () => Loading
,
+}));
+
+vi.mock("./OnboardingErrorView", () => ({
+ OnboardingErrorView: () => Error
,
+}));
+
+vi.mock("./OnboardingFormBody", () => ({
+ OnboardingFormBody: ({ variant, userEmail }: { variant: string; userEmail: string }) => (
+
+ Form Body
+
+ ),
+}));
+
+describe("OnboardingForm", () => {
+ it("should render loading view when credentials are loading", () => {
+ mockUseOnboardingCredentials.mockReturnValue({
+ data: undefined,
+ isLoading: true,
+ isError: false,
+ });
+
+ render();
+
+ expect(screen.getByTestId("loading-view")).toBeInTheDocument();
+ });
+
+ it("should render error view when credentials fail to load", () => {
+ mockUseOnboardingCredentials.mockReturnValue({
+ data: undefined,
+ isLoading: false,
+ isError: true,
+ });
+
+ render();
+
+ expect(screen.getByTestId("error-view")).toBeInTheDocument();
+ });
+
+ it("should render form body with decoded email when credentials are loaded", () => {
+ mockUseOnboardingCredentials.mockReturnValue({
+ data: { token: "fake-jwt-token" },
+ isLoading: false,
+ isError: false,
+ });
+
+ render();
+
+ expect(screen.getByTestId("form-body")).toBeInTheDocument();
+ expect(screen.getByTestId("form-body")).toHaveAttribute("data-email", "alice@example.com");
+ });
+
+ it("should pass variant prop to OnboardingFormBody", () => {
+ mockUseOnboardingCredentials.mockReturnValue({
+ data: { token: "fake-jwt-token" },
+ isLoading: false,
+ isError: false,
+ });
+
+ render();
+
+ expect(screen.getByTestId("form-body")).toHaveAttribute("data-variant", "reset_password");
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/key_team_helpers/filter_helpers.test.ts b/ui/litellm-dashboard/src/components/key_team_helpers/filter_helpers.test.ts
new file mode 100644
index 0000000000..e3f6a5989f
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/key_team_helpers/filter_helpers.test.ts
@@ -0,0 +1,90 @@
+import { describe, expect, it, vi } from "vitest";
+import { fetchTeamFilterOptions } from "./filter_helpers";
+
+const mockKeyListCall = vi.fn();
+
+vi.mock("@/components/networking", () => ({
+ keyListCall: (...args: unknown[]) => mockKeyListCall(...args),
+ teamListCall: vi.fn(),
+ organizationListCall: vi.fn(),
+}));
+
+describe("fetchTeamFilterOptions", () => {
+ it("should return empty arrays when accessToken is null", async () => {
+ const result = await fetchTeamFilterOptions(null, "team-1");
+
+ expect(result).toEqual({ keyAliases: [], organizationIds: [], userIds: [] });
+ expect(mockKeyListCall).not.toHaveBeenCalled();
+ });
+
+ it("should return empty arrays when teamId is empty", async () => {
+ const result = await fetchTeamFilterOptions("tok-123", "");
+
+ expect(result).toEqual({ keyAliases: [], organizationIds: [], userIds: [] });
+ expect(mockKeyListCall).not.toHaveBeenCalled();
+ });
+
+ it("should return sorted key aliases from fetched keys", async () => {
+ mockKeyListCall.mockResolvedValue({
+ keys: [
+ { key_alias: "zeta-key" },
+ { key_alias: "alpha-key" },
+ { key_alias: "mid-key" },
+ ],
+ total_pages: 1,
+ });
+
+ const result = await fetchTeamFilterOptions("tok-123", "team-1");
+
+ expect(result.keyAliases).toEqual(["alpha-key", "mid-key", "zeta-key"]);
+ });
+
+ it("should deduplicate organization IDs across pages", async () => {
+ mockKeyListCall
+ .mockResolvedValueOnce({
+ keys: [
+ { organization_id: "org-b" },
+ { organization_id: "org-a" },
+ ],
+ total_pages: 2,
+ })
+ .mockResolvedValueOnce({
+ keys: [
+ { organization_id: "org-a" },
+ { organization_id: "org-c" },
+ ],
+ total_pages: 2,
+ });
+
+ const result = await fetchTeamFilterOptions("tok-123", "team-1");
+
+ expect(result.organizationIds).toEqual(["org-a", "org-b", "org-c"]);
+ });
+
+ it("should map user IDs with email addresses", async () => {
+ mockKeyListCall.mockResolvedValue({
+ keys: [
+ { user_id: "u1", user: { user_email: "alice@example.com" } },
+ { user_id: "u2", user: { user_email: "bob@example.com" } },
+ ],
+ total_pages: 1,
+ });
+
+ const result = await fetchTeamFilterOptions("tok-123", "team-1");
+
+ expect(result.userIds).toEqual(
+ expect.arrayContaining([
+ { id: "u1", email: "alice@example.com" },
+ { id: "u2", email: "bob@example.com" },
+ ]),
+ );
+ });
+
+ it("should handle API errors gracefully and return empty arrays", async () => {
+ mockKeyListCall.mockRejectedValue(new Error("Network error"));
+
+ const result = await fetchTeamFilterOptions("tok-123", "team-1");
+
+ expect(result).toEqual({ keyAliases: [], organizationIds: [], userIds: [] });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/key_team_helpers/transform_key_info.test.ts b/ui/litellm-dashboard/src/components/key_team_helpers/transform_key_info.test.ts
new file mode 100644
index 0000000000..a1139addbf
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/key_team_helpers/transform_key_info.test.ts
@@ -0,0 +1,62 @@
+import { describe, it, expect } from "vitest";
+import { transformKeyInfo } from "./transform_key_info";
+
+describe("transformKeyInfo", () => {
+ it("should combine key and info fields into a single object", () => {
+ const apiResponse = {
+ key: "sk-abc123",
+ info: {
+ token_id: "tok_1",
+ key_name: "my-key",
+ spend: 10.5,
+ },
+ };
+ const result = transformKeyInfo(apiResponse);
+ expect(result).toEqual({
+ token: "sk-abc123",
+ token_id: "tok_1",
+ key_name: "my-key",
+ spend: 10.5,
+ });
+ });
+
+ it("should set the token field from the key property", () => {
+ const apiResponse = {
+ key: "sk-xyz789",
+ info: { key_name: "test" },
+ };
+ const result = transformKeyInfo(apiResponse);
+ expect(result.token).toBe("sk-xyz789");
+ });
+
+ it("should preserve all info fields in the result", () => {
+ const apiResponse = {
+ key: "sk-abc",
+ info: {
+ token_id: "tok_2",
+ key_name: "prod-key",
+ spend: 42,
+ models: ["gpt-4"],
+ team_id: "team-1",
+ metadata: { env: "production" },
+ },
+ };
+ const result = transformKeyInfo(apiResponse);
+ expect(result.token_id).toBe("tok_2");
+ expect(result.key_name).toBe("prod-key");
+ expect(result.spend).toBe(42);
+ expect(result.models).toEqual(["gpt-4"]);
+ expect(result.team_id).toBe("team-1");
+ expect(result.metadata).toEqual({ env: "production" });
+ });
+
+ it("should handle empty info object", () => {
+ const apiResponse = {
+ key: "sk-empty",
+ info: {},
+ };
+ const result = transformKeyInfo(apiResponse);
+ expect(result.token).toBe("sk-empty");
+ expect(Object.keys(result)).toContain("token");
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/CollapsibleMessage.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/CollapsibleMessage.test.tsx
new file mode 100644
index 0000000000..f07d186c04
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/CollapsibleMessage.test.tsx
@@ -0,0 +1,54 @@
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, it, expect } from "vitest";
+import { CollapsibleMessage } from "./CollapsibleMessage";
+
+describe("CollapsibleMessage", () => {
+ it("should return null when content is empty", () => {
+ const { container } = render(
+
+ );
+ expect(container.innerHTML).toBe("");
+ });
+
+ it("should return null when content is undefined", () => {
+ const { container } = render();
+ expect(container.innerHTML).toBe("");
+ });
+
+ it("should render the label and char count", () => {
+ render();
+ expect(screen.getByText("SYSTEM")).toBeInTheDocument();
+ expect(screen.getByText("(5 chars)")).toBeInTheDocument();
+ });
+
+ it("should show content when defaultExpanded is true", () => {
+ render(
+
+ );
+ expect(screen.getByText("Visible text")).toBeInTheDocument();
+ });
+
+ it("should toggle expanded state when header is clicked", async () => {
+ const user = userEvent.setup();
+ render(
+
+ );
+
+ // Content is rendered in DOM but collapsed by default
+ expect(screen.getByText("Toggle me")).toBeInTheDocument();
+
+ // Click the header to expand - should still show content
+ await user.click(screen.getByText("SYSTEM"));
+ expect(screen.getByText("Toggle me")).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/HistoryTree.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/HistoryTree.test.tsx
new file mode 100644
index 0000000000..f5eb1fcf8d
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/HistoryTree.test.tsx
@@ -0,0 +1,50 @@
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, it, expect } from "vitest";
+import { HistoryTree } from "./HistoryTree";
+import { ParsedMessage } from "./prettyMessagesTypes";
+
+describe("HistoryTree", () => {
+ it("should return null when messages array is empty", () => {
+ const { container } = render();
+ expect(container.innerHTML).toBe("");
+ });
+
+ it('should render message count with plural "messages" for multiple messages', () => {
+ const messages: ParsedMessage[] = [
+ { role: "user", content: "Hello" },
+ { role: "assistant", content: "Hi there" },
+ { role: "user", content: "How are you?" },
+ ];
+ render();
+ expect(
+ screen.getByText("HISTORY (3 messages)")
+ ).toBeInTheDocument();
+ });
+
+ it('should render message count with singular "message" for one message', () => {
+ const messages: ParsedMessage[] = [
+ { role: "user", content: "Hello" },
+ ];
+ render();
+ expect(
+ screen.getByText("HISTORY (1 message)")
+ ).toBeInTheDocument();
+ });
+
+ it("should expand and show messages when header is clicked", async () => {
+ const user = userEvent.setup();
+ const messages: ParsedMessage[] = [
+ { role: "user", content: "Hello" },
+ { role: "assistant", content: "Hi there" },
+ ];
+ render();
+
+ // Click to expand
+ await user.click(screen.getByText("HISTORY (2 messages)"));
+
+ expect(screen.getByText("Hello")).toBeInTheDocument();
+ expect(screen.getByText("Hi there")).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleMessageBlock.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleMessageBlock.test.tsx
new file mode 100644
index 0000000000..6483507938
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleMessageBlock.test.tsx
@@ -0,0 +1,55 @@
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import { describe, it, expect } from "vitest";
+import { SimpleMessageBlock } from "./SimpleMessageBlock";
+
+describe("SimpleMessageBlock", () => {
+ it("should render the label and content", () => {
+ render();
+ expect(screen.getByText("USER")).toBeInTheDocument();
+ expect(screen.getByText("Hello world")).toBeInTheDocument();
+ });
+
+ it("should return null when content is empty and no tool calls", () => {
+ const { container } = render(
+
+ );
+ expect(container.innerHTML).toBe("");
+ });
+
+ it('should return null when content is "null" string and no tool calls', () => {
+ const { container } = render(
+
+ );
+ expect(container.innerHTML).toBe("");
+ });
+
+ it("should render tool calls when present", () => {
+ render(
+
+ );
+ expect(screen.getByText("ASSISTANT")).toBeInTheDocument();
+ expect(screen.getByText("get_weather")).toBeInTheDocument();
+ });
+
+ it("should render content and tool calls together", () => {
+ render(
+
+ );
+ expect(
+ screen.getByText("Let me check the weather.")
+ ).toBeInTheDocument();
+ expect(screen.getByText("get_weather")).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleToolCallBlock.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleToolCallBlock.test.tsx
new file mode 100644
index 0000000000..33ff403090
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleToolCallBlock.test.tsx
@@ -0,0 +1,51 @@
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import { describe, it, expect } from "vitest";
+import { SimpleToolCallBlock } from "./SimpleToolCallBlock";
+
+describe("SimpleToolCallBlock", () => {
+ it("should render the tool name", () => {
+ render(
+
+ );
+ expect(screen.getByText("get_weather")).toBeInTheDocument();
+ });
+
+ it('should display "function" badge', () => {
+ render(
+
+ );
+ expect(screen.getByText("function")).toBeInTheDocument();
+ });
+
+ it("should render arguments when present", () => {
+ render(
+
+ );
+ expect(screen.getByText("city:")).toBeInTheDocument();
+ expect(screen.getByText('"London"')).toBeInTheDocument();
+ expect(screen.getByText("units:")).toBeInTheDocument();
+ expect(screen.getByText('"metric"')).toBeInTheDocument();
+ });
+
+ it("should not render arguments section when arguments are empty", () => {
+ const { container } = render(
+
+ );
+ // The tool name and "function" badge should be there, but no key: value pairs
+ expect(screen.getByText("get_weather")).toBeInTheDocument();
+ expect(screen.queryByText(/:$/)).not.toBeInTheDocument();
+ });
+});