diff --git a/ui/litellm-dashboard/src/components/view_logs/ConfigInfoMessage.test.tsx b/ui/litellm-dashboard/src/components/view_logs/ConfigInfoMessage.test.tsx
new file mode 100644
index 00000000000..9e28b27cece
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/ConfigInfoMessage.test.tsx
@@ -0,0 +1,41 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import userEvent from "@testing-library/user-event";
+import { ConfigInfoMessage } from "./ConfigInfoMessage";
+
+describe("ConfigInfoMessage", () => {
+ it("should render the info message when show is true", () => {
+ render();
+ expect(screen.getByText("Request/Response Data Not Available")).toBeInTheDocument();
+ });
+
+ it("should render nothing when show is false", () => {
+ const { container } = render();
+ expect(container.innerHTML).toBe("");
+ });
+
+ it("should display the YAML config snippet", () => {
+ render();
+ expect(screen.getByText(/store_prompts_in_spend_logs: true/)).toBeInTheDocument();
+ });
+
+ it("should render the settings button when onOpenSettings is provided", () => {
+ render( {}} />);
+ expect(screen.getByText("open the settings")).toBeInTheDocument();
+ });
+
+ it("should not render the settings button when onOpenSettings is omitted", () => {
+ render();
+ expect(screen.queryByText("open the settings")).not.toBeInTheDocument();
+ });
+
+ it("should call onOpenSettings when the settings button is clicked", async () => {
+ const user = userEvent.setup();
+ const onOpenSettings = vi.fn();
+
+ render();
+ await user.click(screen.getByText("open the settings"));
+
+ expect(onOpenSettings).toHaveBeenCalledOnce();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/ErrorViewer.test.tsx b/ui/litellm-dashboard/src/components/view_logs/ErrorViewer.test.tsx
new file mode 100644
index 00000000000..64d020b61c7
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/ErrorViewer.test.tsx
@@ -0,0 +1,87 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import userEvent from "@testing-library/user-event";
+import { ErrorViewer } from "./ErrorViewer";
+
+const basicError = {
+ error_class: "NotFoundError",
+ error_message: "Model gpt-5 not found",
+};
+
+const errorWithTraceback = {
+ error_class: "AuthenticationError",
+ error_message: "Invalid API key",
+ traceback: `Traceback (most recent call last):
+ File "/app/main.py", line 42, in handle_request
+ result = await client.chat(model="gpt-4")
+ File "/app/llms/openai.py", line 100, in chat
+ response = self._make_request(payload)
+ File "/app/llms/base.py", line 55, in _make_request
+ raise AuthenticationError("Invalid API key")`,
+};
+
+describe("ErrorViewer", () => {
+ it("should render error type and message", () => {
+ render();
+ expect(screen.getByText("NotFoundError")).toBeInTheDocument();
+ expect(screen.getByText("Model gpt-5 not found")).toBeInTheDocument();
+ });
+
+ it("should show 'Unknown Error' when error_class is missing", () => {
+ render();
+ expect(screen.getByText("Unknown Error")).toBeInTheDocument();
+ });
+
+ it("should show 'Unknown error occurred' when error_message is missing", () => {
+ render();
+ expect(screen.getByText("Unknown error occurred")).toBeInTheDocument();
+ });
+
+ it("should render traceback frames when traceback is present", () => {
+ render();
+ expect(screen.getByText("Traceback")).toBeInTheDocument();
+ expect(screen.getByText("main.py")).toBeInTheDocument();
+ expect(screen.getByText("openai.py")).toBeInTheDocument();
+ expect(screen.getByText("base.py")).toBeInTheDocument();
+ });
+
+ it("should expand a frame when clicked", async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.click(screen.getByText("main.py"));
+
+ expect(
+ screen.getByText("result = await client.chat(model=\"gpt-4\")")
+ ).toBeInTheDocument();
+ });
+
+ it("should expand all frames when 'Expand All' is clicked", async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.click(screen.getByText("Expand All"));
+
+ expect(screen.getByText("Collapse All")).toBeInTheDocument();
+ });
+
+ it("should copy traceback to clipboard when copy button is clicked", async () => {
+ const user = userEvent.setup();
+ const mockWriteText = vi.fn().mockResolvedValue(undefined);
+ Object.defineProperty(navigator, "clipboard", {
+ value: { writeText: mockWriteText },
+ writable: true,
+ configurable: true,
+ });
+
+ render();
+
+ await user.click(screen.getByTitle("Copy traceback"));
+ expect(mockWriteText).toHaveBeenCalledWith(errorWithTraceback.traceback);
+ });
+
+ it("should not render traceback section when traceback is absent", () => {
+ render();
+ expect(screen.queryByText("Traceback")).not.toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/TruncatedValue.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/TruncatedValue.test.tsx
new file mode 100644
index 00000000000..0da1f2cc3ab
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/TruncatedValue.test.tsx
@@ -0,0 +1,32 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import { TruncatedValue } from "./TruncatedValue";
+
+describe("TruncatedValue", () => {
+ it("should render the value text", () => {
+ render();
+ expect(screen.getByText("chatcmpl-abc123")).toBeInTheDocument();
+ });
+
+ it("should render a dash when value is undefined", () => {
+ render();
+ expect(screen.getByText("-")).toBeInTheDocument();
+ });
+
+ it("should render a dash when value is empty string", () => {
+ render();
+ expect(screen.getByText("-")).toBeInTheDocument();
+ });
+
+ it("should apply the default maxWidth when not specified", () => {
+ render();
+ const el = screen.getByText("some-long-id-value");
+ expect(el).toHaveStyle({ maxWidth: "180px" });
+ });
+
+ it("should apply custom maxWidth when provided", () => {
+ render();
+ const el = screen.getByText("test-value");
+ expect(el).toHaveStyle({ maxWidth: "300px" });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/TypeBadges.test.tsx b/ui/litellm-dashboard/src/components/view_logs/TypeBadges.test.tsx
new file mode 100644
index 00000000000..e3467310265
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/TypeBadges.test.tsx
@@ -0,0 +1,46 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import { LlmBadge, McpBadge, AgentBadge } from "./TypeBadges";
+
+describe("TypeBadges", () => {
+ describe("LlmBadge", () => {
+ it("should render with default 'LLM' text when no count is provided", () => {
+ render();
+ expect(screen.getByText("LLM")).toBeInTheDocument();
+ });
+
+ it("should render the count when provided", () => {
+ render();
+ expect(screen.getByText("5")).toBeInTheDocument();
+ });
+
+ it("should render count of 0 instead of default text", () => {
+ render();
+ expect(screen.getByText("0")).toBeInTheDocument();
+ });
+ });
+
+ describe("McpBadge", () => {
+ it("should render with default 'MCP' text when no count is provided", () => {
+ render();
+ expect(screen.getByText("MCP")).toBeInTheDocument();
+ });
+
+ it("should render the count when provided", () => {
+ render();
+ expect(screen.getByText("3")).toBeInTheDocument();
+ });
+ });
+
+ describe("AgentBadge", () => {
+ it("should render with default 'Agent' text when no count is provided", () => {
+ render();
+ expect(screen.getByText("Agent")).toBeInTheDocument();
+ });
+
+ it("should render the count when provided", () => {
+ render();
+ expect(screen.getByText("12")).toBeInTheDocument();
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/view_logs/time_cell.test.tsx b/ui/litellm-dashboard/src/components/view_logs/time_cell.test.tsx
new file mode 100644
index 00000000000..95a8b43b2c1
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/time_cell.test.tsx
@@ -0,0 +1,36 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import { TimeCell, getTimeZone } from "./time_cell";
+
+describe("TimeCell", () => {
+ it("should render a formatted time string", () => {
+ render();
+ // The global toLocaleString mock in setupTests returns "YYYY-MM-DD HH:MM:SS"
+ expect(screen.getByText(/2025/)).toBeInTheDocument();
+ });
+
+ it("should render 'Error converting time' for invalid dates", () => {
+ // toLocaleString on an Invalid Date returns "Invalid Date", not throwing,
+ // but the component catches exceptions. Force an error by passing something
+ // that causes Date constructor to produce NaN.
+ render();
+ // The mock returns "NaN-NaN-NaN NaN:NaN:NaN" for invalid dates
+ // The component has a try/catch that returns "Error converting time" on exception
+ const el = screen.getByText(/NaN|Error/);
+ expect(el).toBeInTheDocument();
+ });
+
+ it("should render with monospace font", () => {
+ render();
+ const span = screen.getByText(/2025/);
+ expect(span).toHaveStyle({ fontFamily: "monospace" });
+ });
+});
+
+describe("getTimeZone", () => {
+ it("should return a non-empty timezone string", () => {
+ const tz = getTimeZone();
+ expect(typeof tz).toBe("string");
+ expect(tz.length).toBeGreaterThan(0);
+ });
+});