diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx index f6fcfb2fb74..462b0a3d99d 100644 --- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx @@ -113,7 +113,7 @@ describe("KeyLifecycleSettings", () => { renderWithProviders(); const input = screen.getByTestId("duration-input"); - expect(input).toHaveAttribute("placeholder", "e.g., 30d or -1 to never expire"); + expect(input).toHaveAttribute("placeholder", "e.g., 30d"); }); it("should show correct tooltip in create mode", () => { @@ -121,12 +121,12 @@ describe("KeyLifecycleSettings", () => { const tooltips = screen.getAllByTestId("tooltip"); const expiryTooltip = tooltips.find((tooltip) => - tooltip.getAttribute("title")?.includes("Leave empty to never expire") + tooltip.getAttribute("title")?.includes("Leave empty to keep the current expiry unchanged") ); expect(expiryTooltip).toBeInTheDocument(); expect(expiryTooltip).toHaveAttribute( "title", - "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to never expire." + "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to keep the current expiry unchanged." ); }); @@ -135,12 +135,12 @@ describe("KeyLifecycleSettings", () => { const tooltips = screen.getAllByTestId("tooltip"); const expiryTooltip = tooltips.find((tooltip) => - tooltip.getAttribute("title")?.includes("Use -1 to never expire") + tooltip.getAttribute("title")?.includes("Leave empty to keep the current expiry unchanged") ); expect(expiryTooltip).toBeInTheDocument(); expect(expiryTooltip).toHaveAttribute( "title", - "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Use -1 to never expire." + "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to keep the current expiry unchanged." ); }); diff --git a/ui/litellm-dashboard/src/components/leftnav.test.tsx b/ui/litellm-dashboard/src/components/leftnav.test.tsx index 09109300dce..c168ffa21e0 100644 --- a/ui/litellm-dashboard/src/components/leftnav.test.tsx +++ b/ui/litellm-dashboard/src/components/leftnav.test.tsx @@ -9,6 +9,7 @@ vi.mock("../utils/roles", () => { internalUserRoles: ["internal"], rolesWithWriteAccess: ["admin", "internal"], isAdminRole: (role: string) => role === "admin", + isUserTeamAdminForAnyTeam: () => false, }; }); @@ -41,6 +42,10 @@ vi.mock("@/app/(dashboard)/hooks/organizations/useOrganizations", () => ({ useOrganizations: mockUseOrganizations, })); +vi.mock("@/app/(dashboard)/hooks/teams/useTeams", () => ({ + useTeams: () => ({ data: [], isLoading: false, error: null }), +})); + vi.mock("@/app/(dashboard)/hooks/uiConfig/useUIConfig", () => { return { useUIConfig: () => ({ @@ -64,17 +69,22 @@ describe("Sidebar (leftnav)", () => { "Virtual Keys", "Playground", "Models + Endpoints", + "Agents", + "MCP Servers", + "Guardrails", + "Policies", + "Tools", "Usage", + "Logs", + "Guardrails Monitor", "Teams", - "Organizations", "Internal Users", + "Organizations", + "Access Groups", "Budgets", "API Reference", "AI Hub", - "Logs", - "Guardrails", - "MCP Servers", - "Tools", + "Learning Resources", "Experimental", "Settings", ]; diff --git a/ui/litellm-dashboard/src/components/navbar.test.tsx b/ui/litellm-dashboard/src/components/navbar.test.tsx index 125187e2340..9a3c781aaab 100644 --- a/ui/litellm-dashboard/src/components/navbar.test.tsx +++ b/ui/litellm-dashboard/src/components/navbar.test.tsx @@ -1,4 +1,5 @@ import userEvent from "@testing-library/user-event"; +import React, { useState } from "react"; import { describe, expect, it, vi } from "vitest"; import { renderWithProviders, screen, waitFor } from "../../tests/test-utils"; import Navbar from "./navbar"; @@ -6,8 +7,69 @@ import Navbar from "./navbar"; // Mock the hooks and utilities vi.mock("@/components/networking", () => ({ getProxyBaseUrl: vi.fn(() => "http://localhost:4000"), + serverRootPath: "", })); +vi.mock("@/app/(dashboard)/hooks/useDisableBouncingIcon", () => ({ + useDisableBouncingIcon: () => false, +})); + +vi.mock("./Navbar/BlogDropdown/BlogDropdown", () => ({ + BlogDropdown: () =>
Blog
, +})); + +const mockUserDropdownData = vi.hoisted(() => ({ + current: () => ({ + userId: "test-user", + userEmail: "test@example.com", + userRole: "Admin", + premiumUser: false, + }), +})); + +vi.mock("./Navbar/UserDropdown/UserDropdown", async (importOriginal) => { + const React = await import("react"); + const { useState } = React; + const localStorageUtils = await import("@/utils/localStorageUtils"); + return { + default: function MockUserDropdown({ onLogout }: { onLogout: () => void }) { + const { userId, userEmail, userRole, premiumUser } = mockUserDropdownData.current(); + const [open, setOpen] = useState(false); + return ( +
+ + {open && ( +
+ {userId} + {userRole} + {userEmail} + {premiumUser && Premium} + + +
+ )} +
+ ); + }, + }; +}); + vi.mock("@/utils/proxyUtils", () => ({ fetchProxySettings: vi.fn(), })); @@ -122,7 +184,8 @@ describe("Navbar", () => { it("should show premium user badge when premiumUser is true", async () => { const user = userEvent.setup(); - mockUseAuthorizedImpl = () => ({ + const originalCurrent = mockUserDropdownData.current; + mockUserDropdownData.current = () => ({ userId: "test-user", userEmail: "test@example.com", userRole: "Admin", @@ -137,12 +200,7 @@ describe("Navbar", () => { }); // Reset mock - mockUseAuthorizedImpl = () => ({ - userId: "test-user", - userEmail: "test@example.com", - userRole: "Admin", - premiumUser: false, - }); + mockUserDropdownData.current = originalCurrent; }); it("should show version badge when health data contains version", () => {