From e232c9ec4c78c5ff0d545d7d89de4eb264c296e6 Mon Sep 17 00:00:00 2001 From: kimsehwan96 Date: Wed, 29 Apr 2026 07:44:09 +0900 Subject: [PATCH] [Test] UI - Cover proxy_admin_viewer access to /api-keys vitest: assert UserDashboard renders the keys table for both Admin Viewer and proxy_admin (no Access Denied). e2e: viewer sees seeded keys (admin scope), Create button is hidden, key detail view loads without Regenerate / Delete / Edit. --- .../api-keys-access.spec.ts | 45 +++++++++++++++++++ .../src/components/user_dashboard.test.tsx | 23 +++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 ui/litellm-dashboard/e2e_tests/tests/proxy-admin-viewer/api-keys-access.spec.ts diff --git a/ui/litellm-dashboard/e2e_tests/tests/proxy-admin-viewer/api-keys-access.spec.ts b/ui/litellm-dashboard/e2e_tests/tests/proxy-admin-viewer/api-keys-access.spec.ts new file mode 100644 index 00000000000..90b389fc62f --- /dev/null +++ b/ui/litellm-dashboard/e2e_tests/tests/proxy-admin-viewer/api-keys-access.spec.ts @@ -0,0 +1,45 @@ +import { test, expect } from "@playwright/test"; +import { + ADMIN_VIEWER_STORAGE_PATH, + E2E_INTERNAL_USER_KEY_ALIAS, +} from "../../constants"; +import { Page } from "../../fixtures/pages"; +import { navigateToPage } from "../../helpers/navigation"; + +test.describe("Proxy Admin Viewer - Keys (read-only)", () => { + test.use({ storageState: ADMIN_VIEWER_STORAGE_PATH }); + + test("Sees the keys table without an Access Denied gate", async ({ page }) => { + await navigateToPage(page, Page.ApiKeys); + + // Hard entry-level gate is gone. + await expect(page.getByText("Access Denied")).toHaveCount(0); + await expect( + page.getByText("Ask your proxy admin for access to create keys"), + ).toHaveCount(0); + + // Admin viewer has the same all-keys view as proxy admin + // (backend use_substring_matching path). + await expect(page.getByText(E2E_INTERNAL_USER_KEY_ALIAS)).toBeVisible({ timeout: 10_000 }); + + // rolesWithWriteAccess guard hides the create affordance. + await expect(page.getByRole("button", { name: /Create New Key/i })).toHaveCount(0); + }); + + test("Can open a key detail view but cannot regenerate / delete / edit", async ({ page }) => { + await navigateToPage(page, Page.ApiKeys); + + // Open the detail view of one of the seeded keys. + const keyRow = page.locator("tr", { hasText: E2E_INTERNAL_USER_KEY_ALIAS }); + await expect(keyRow).toBeVisible({ timeout: 10_000 }); + await keyRow.locator("button").first().click(); + + // Detail view loaded. + await expect(page.getByText("Back to Keys")).toBeVisible({ timeout: 10_000 }); + + // No write affordances on the detail view. + await expect(page.getByRole("button", { name: "Regenerate Key" })).toHaveCount(0); + await expect(page.getByRole("button", { name: "Delete Key" })).toHaveCount(0); + await expect(page.getByRole("button", { name: "Edit Settings" })).toHaveCount(0); + }); +}); diff --git a/ui/litellm-dashboard/src/components/user_dashboard.test.tsx b/ui/litellm-dashboard/src/components/user_dashboard.test.tsx index 4d4213b6805..61893064093 100644 --- a/ui/litellm-dashboard/src/components/user_dashboard.test.tsx +++ b/ui/litellm-dashboard/src/components/user_dashboard.test.tsx @@ -1,5 +1,5 @@ import { vi, describe, it, expect, beforeEach, afterEach } from "vitest"; -import { cleanup } from "@testing-library/react"; +import { cleanup, screen } from "@testing-library/react"; import React from "react"; import { renderWithProviders } from "../../tests/test-utils"; @@ -138,3 +138,24 @@ describe("UserDashboard beforeunload listener", () => { expect(removeCalls).toHaveLength(1); }); }); + +describe("UserDashboard role-based rendering", () => { + afterEach(() => { + cleanup(); + }); + + it("renders the keys page (no Access Denied screen) for proxy_admin_viewer", () => { + renderDashboard({ userRole: "Admin Viewer" }); + + expect(screen.queryByText("Access Denied")).toBeNull(); + expect(screen.queryByText("Ask your proxy admin for access to create keys")).toBeNull(); + expect(screen.getByTestId("virtual-keys-table-mock")).toBeInTheDocument(); + }); + + it("renders the keys page for proxy_admin", () => { + renderDashboard({ userRole: "Admin" }); + + expect(screen.queryByText("Access Denied")).toBeNull(); + expect(screen.getByTestId("virtual-keys-table-mock")).toBeInTheDocument(); + }); +});