diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/AddSSOSettingsModal.test.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/AddSSOSettingsModal.test.tsx
index aae28191031..e5a5af6cba6 100644
--- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/AddSSOSettingsModal.test.tsx
+++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/AddSSOSettingsModal.test.tsx
@@ -1,5 +1,6 @@
-import { render, screen } from "@testing-library/react";
+import { screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
+import { renderWithProviders } from "../../../../../../tests/test-utils";
import AddSSOSettingsModal from "./AddSSOSettingsModal";
// Mock networking functions
@@ -12,12 +13,30 @@ vi.mock("@/components/shared/errorUtils", () => ({
parseErrorMessage: vi.fn((error) => error?.message || "Unknown error"),
}));
+// Mock the useAuthorized hook
+vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
+ default: () => ({
+ accessToken: "test-access-token",
+ userId: "test-user-id",
+ userEmail: "test@example.com",
+ userRole: "admin",
+ }),
+}));
+
+// Mock NotificationsManager
+vi.mock("@/components/molecules/notifications_manager", () => ({
+ default: {
+ success: vi.fn(),
+ fromBackend: vi.fn(),
+ },
+}));
+
describe("AddSSOSettingsModal", () => {
it("should render", () => {
const onCancel = vi.fn();
const onSuccess = vi.fn();
- render();
+ renderWithProviders();
expect(screen.getByText("SSO Provider")).toBeInTheDocument();
expect(screen.getByText("Cancel")).toBeInTheDocument();
diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RedactableField.test.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RedactableField.test.tsx
new file mode 100644
index 00000000000..a047d7aea4f
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RedactableField.test.tsx
@@ -0,0 +1,108 @@
+import { render, screen, fireEvent } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import RedactableField from "./RedactableField";
+
+describe("RedactableField", () => {
+ describe("when value is null", () => {
+ it("should display 'Not configured' text", () => {
+ render();
+
+ expect(screen.getByText("Not configured")).toBeInTheDocument();
+ });
+
+ it("should not display toggle button", () => {
+ render();
+
+ // There should be no button elements
+ const buttons = screen.queryAllByRole("button");
+ expect(buttons).toHaveLength(0);
+ });
+ });
+
+ describe("when value is provided", () => {
+ const testValue = "secret-password";
+
+ it("should be hidden by default and show redacted dots", () => {
+ render();
+
+ // Should show dots equal to the length of the value
+ expect(screen.getByText("•".repeat(testValue.length))).toBeInTheDocument();
+ expect(screen.queryByText(testValue)).not.toBeInTheDocument();
+ });
+
+ it("should show actual value when defaultHidden is false", () => {
+ render();
+
+ expect(screen.getByText(testValue)).toBeInTheDocument();
+ expect(screen.queryByText("•".repeat(testValue.length))).not.toBeInTheDocument();
+ });
+
+ it("should display toggle button with eye icon when hidden", () => {
+ render();
+
+ const button = screen.getByRole("button");
+ expect(button).toBeInTheDocument();
+
+ // Check that the Eye icon is rendered (we can check by title or by the presence of the icon)
+ // The button should contain the Eye icon when hidden
+ const eyeIcon = button.querySelector("svg");
+ expect(eyeIcon).toBeInTheDocument();
+ });
+
+ it("should display toggle button with eye-off icon when shown", () => {
+ render();
+
+ const button = screen.getByRole("button");
+ expect(button).toBeInTheDocument();
+
+ // The button should contain the EyeOff icon when shown
+ const eyeOffIcon = button.querySelector("svg");
+ expect(eyeOffIcon).toBeInTheDocument();
+ });
+
+ it("should toggle visibility when button is clicked", () => {
+ render();
+
+ // Initially hidden
+ expect(screen.getByText("•".repeat(testValue.length))).toBeInTheDocument();
+ expect(screen.queryByText(testValue)).not.toBeInTheDocument();
+
+ // Click to show
+ const button = screen.getByRole("button");
+ fireEvent.click(button);
+
+ // Should now show the actual value
+ expect(screen.getByText(testValue)).toBeInTheDocument();
+ expect(screen.queryByText("•".repeat(testValue.length))).not.toBeInTheDocument();
+
+ // Click again to hide
+ fireEvent.click(button);
+
+ // Should be hidden again
+ expect(screen.getByText("•".repeat(testValue.length))).toBeInTheDocument();
+ expect(screen.queryByText(testValue)).not.toBeInTheDocument();
+ });
+
+ it("should handle empty string value", () => {
+ render();
+
+ // Empty string should show "Not configured" since value is falsy
+ expect(screen.getByText("Not configured")).toBeInTheDocument();
+
+ // No toggle button for empty string
+ const buttons = screen.queryAllByRole("button");
+ expect(buttons).toHaveLength(0);
+ });
+
+ it("should handle different value lengths correctly", () => {
+ const shortValue = "hi";
+ const longValue = "this-is-a-very-long-secret-value";
+
+ const { rerender } = render();
+ expect(screen.getByText("••")).toBeInTheDocument();
+
+ rerender();
+ expect(screen.getByText("•".repeat(longValue.length))).toBeInTheDocument();
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx
index 975a3bc7d78..d339f6d0e36 100644
--- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx
+++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx
@@ -2,15 +2,15 @@
import { useSSOSettings, type SSOSettingsValues } from "@/app/(dashboard)/hooks/sso/useSSOSettings";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
-import { Badge, Button, Card, Descriptions, Space, Typography } from "antd";
-import { Shield, Trash2, Edit } from "lucide-react";
+import { Button, Card, Descriptions, Space, Typography } from "antd";
+import { Edit, Shield, Trash2 } from "lucide-react";
import { useState } from "react";
import AddSSOSettingsModal from "./Modals/AddSSOSettingsModal";
import DeleteSSOSettingsModal from "./Modals/DeleteSSOSettingsModal";
import EditSSOSettingsModal from "./Modals/EditSSOSettingsModal";
-import SSOSettingsEmptyPlaceholder from "./SSOSettingsEmptyPlaceholder";
import RedactableField from "./RedactableField";
-import { ssoProviderLogoMap, ssoProviderDisplayNames } from "./constants";
+import SSOSettingsEmptyPlaceholder from "./SSOSettingsEmptyPlaceholder";
+import { ssoProviderDisplayNames, ssoProviderLogoMap } from "./constants";
const { Title, Text } = Typography;