mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-29 18:21:26 +00:00
test(ui): e2e cover team model edit + admin identity in navbar (#28652)
* test(ui): e2e cover team model edit + admin identity in navbar
Adds two Playwright tests as part of the manual-QA → e2e migration:
"Edit team model selection" exercises the Settings tab Models multi-select
+ Save Changes flow on a seeded team, and the existing login test now
opens the User dropdown and asserts the role and User ID render — guarding
against regressions where login succeeds but the auth context is empty.
Resolves LIT-3093
* test(ui): restore seeded models in team-edit test so retries don't fail
The 'Edit team model selection' test removed fake-anthropic-claude from
E2E_TEAM_CRUD_ID without restoring it. CI runs with retries: 2 and the seed
script runs once before the suite, so a flake on this test would fail the
retry at the "tag is visible" assertion. Wrap the test in try/finally and
restore the seeded models via /team/update before and after.
* test(e2e): fail loudly if team/update restore call fails
Surfaces the real cause when the master key is wrong or the proxy is
unreachable, instead of silently leaving the team in a stale state and
failing later on the visibility assertion.
* fix(e2e): match navbar account button by aria-label, not non-existent "User" text
The previous trigger filter (hasText: /^User$/) didn't match the rendered
UserDropdown button — its text is the displayName ("Account" for the
master-key admin, an email for SSO users), never "User". The evaluate
call then timed out after 15s in CI. Use the stable aria-label prefix
the component always emits, and click directly since the dropdown is
configured trigger=["click"] (the synthetic hover was unnecessary).
This commit is contained in:
@@ -10,4 +10,21 @@ test("user can log in", async ({ page }) => {
|
||||
await expect(loginButton).toBeEnabled();
|
||||
await loginButton.click();
|
||||
await expect(page.getByText("Virtual Keys")).toBeVisible();
|
||||
|
||||
// Match the navbar account button by its stable aria-label (UserDropdown.tsx
|
||||
// emits "Account menu — <role> — signed in as <email|id>"). Earlier this used
|
||||
// `hasText: /^User$/`, which never matched the rendered button (text is
|
||||
// displayName = "Account" for the master-key admin), so the trigger evaluate
|
||||
// would time out in CI.
|
||||
const userTrigger = page.locator('button[aria-label^="Account menu"]').first();
|
||||
await userTrigger.click();
|
||||
|
||||
// Filter by the popupRender wrapper class to disambiguate from other
|
||||
// ant-dropdown popups.
|
||||
const popup = page.locator(".ant-dropdown:visible").filter({
|
||||
has: page.locator(".bg-white.rounded-lg.shadow-lg"),
|
||||
}).first();
|
||||
await expect(popup).toBeVisible({ timeout: 5_000 });
|
||||
await expect(popup.getByText("Admin", { exact: true })).toBeVisible({ timeout: 5_000 });
|
||||
await expect(popup.getByText("default_user_id", { exact: true })).toBeVisible({ timeout: 5_000 });
|
||||
});
|
||||
|
||||
@@ -131,4 +131,49 @@ test.describe("Proxy Admin - Teams", () => {
|
||||
|
||||
await expect(page.getByText(/updated|success/i).first()).toBeVisible({ timeout: 10_000 });
|
||||
});
|
||||
|
||||
test("Edit team model selection", async ({ page, request }) => {
|
||||
// Restore the seeded models via API in case a prior run (or a CI retry)
|
||||
// left this team mutated — the assertion below requires fake-anthropic-claude
|
||||
// to be present.
|
||||
const masterKey = process.env.LITELLM_MASTER_KEY || "sk-1234";
|
||||
const seededModels = ["fake-openai-gpt-4", "fake-anthropic-claude"];
|
||||
const restore = async () => {
|
||||
const res = await request.post("http://localhost:4000/team/update", {
|
||||
headers: { Authorization: `Bearer ${masterKey}` },
|
||||
data: { team_id: E2E_TEAM_CRUD_ID, models: seededModels },
|
||||
});
|
||||
expect(res.ok(), `restore failed: ${res.status()} ${await res.text()}`).toBeTruthy();
|
||||
};
|
||||
await restore();
|
||||
|
||||
try {
|
||||
await navigateToPage(page, Page.Teams);
|
||||
await dismissFeedbackPopup(page);
|
||||
|
||||
await clickTeamId(page, E2E_TEAM_CRUD_ID);
|
||||
|
||||
await page.getByRole("tab", { name: "Settings" }).click();
|
||||
await page.getByRole("button", { name: "Edit Settings" }).click();
|
||||
|
||||
// Remove the anthropic tag — other tests against this team use "All Team
|
||||
// Models" so they pick up whatever remains.
|
||||
const modelsSelect = page.locator("[data-testid='models-select']");
|
||||
await expect(modelsSelect).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
const anthropicTag = modelsSelect
|
||||
.locator(".ant-select-selection-item")
|
||||
.filter({ hasText: "fake-anthropic-claude" });
|
||||
await expect(anthropicTag).toBeVisible({ timeout: 5_000 });
|
||||
await anthropicTag.locator(".ant-select-selection-item-remove").click();
|
||||
|
||||
await page.getByRole("button", { name: "Save Changes" }).click();
|
||||
|
||||
await expect(page.getByText(/Team settings updated|updated successfully/i).first())
|
||||
.toBeVisible({ timeout: 10_000 });
|
||||
} finally {
|
||||
// Leave the team in its seeded state for any subsequent test or rerun.
|
||||
await restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user