test(e2e/ui): give the logout specs their own admin session (#42930)

#42463 made Logout revoke the dashboard session key on the server. Both
logout specs ran on the shared ADMIN_STORAGE_PATH session that globalSetup
mints once, so clicking Logout revoked the key every later admin spec reuses.
The CircleCI run is serial, and from the auth/ folder on, every admin-session
spec failed with "Invalid proxy server token passed" (80 failures, up from 7)
while the internal-user, internal-viewer and team-admin specs kept passing.

Each logout spec now starts from an empty storage state and logs in through
the login page, so the session it revokes is its own. The login steps live in
a shared logInThroughLoginPage helper next to the other onboarding helpers.
This commit is contained in:
yuneng-jiang 2026-09-24 11:55:07 -07:00 • committed by GitHub
parent 12960f3edf
commit 259f954f56
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 24 additions and 6 deletions

View file

@ -57,3 +57,13 @@ export async function expectUnrestrictedDashboard(page: Page): Promise<void> {
expect(info.ok(), `Read own user with dashboard session: HTTP ${info.status()}`).toBe(true);
expect((await info.json()).user_id).toBe(session.user_id);
}
export async function logInThroughLoginPage(page: Page, email: string, password: string): Promise<void> {
await page.goto(`${rootPath()}/ui/login`);
await page.getByPlaceholder("Enter your username").fill(email);
await page.getByPlaceholder("Enter your password").fill(password);
await page.getByRole("button", { name: "Login", exact: true }).click();
await page.waitForURL((url) => url.pathname.startsWith(`${rootPath()}/ui`) && !url.pathname.includes("/login"), {
timeout: 30_000,
});
}

View file

@ -1,10 +1,14 @@
import { test, expect } from "@playwright/test";
import { ADMIN_STORAGE_PATH } from "../../constants";
import { Role, users } from "../../fixtures/users";
import { logInThroughLoginPage } from "../../helpers/userOnboarding";
test.describe("Logout", () => {
test.use({ storageState: ADMIN_STORAGE_PATH });
test.use({ storageState: { cookies: [], origins: [] } });
test("Clicking Logout clears the session and forces re-login on a protected page", async ({ page }) => {
const admin = users[Role.ProxyAdmin];
await logInThroughLoginPage(page, admin.email, admin.password);
await page.goto("/ui");
// Scope to the sidebar; the top-bar breadcrumb also shows "Virtual Keys".
await expect(page.getByRole("complementary").getByText("Virtual Keys")).toBeVisible({ timeout: 10_000 });

View file

@ -1,5 +1,6 @@
import { test, expect } from "@playwright/test";
import { ADMIN_STORAGE_PATH } from "../../constants";
import { Role, users } from "../../fixtures/users";
import { logInThroughLoginPage } from "../../helpers/userOnboarding";
/**
* Runs as part of the standard e2e suite: both `run_e2e.sh` and the CircleCI
@ -16,9 +17,12 @@ const LOGOUT_URL = process.env.PROXY_LOGOUT_URL ?? "";
test.skip(!LOGOUT_URL, "Requires PROXY_LOGOUT_URL env var");
test.describe("PROXY_LOGOUT_URL redirect", () => {
test.use({ storageState: ADMIN_STORAGE_PATH });
test.use({ storageState: { cookies: [], origins: [] } });
test("Logout clears the session and redirects to PROXY_LOGOUT_URL", async ({ page }) => {
const admin = users[Role.ProxyAdmin];
await logInThroughLoginPage(page, admin.email, admin.password);
const target = new URL(LOGOUT_URL);
// Stub the external logout destination so the assertion doesn't depend on
@ -46,8 +50,8 @@ test.describe("PROXY_LOGOUT_URL redirect", () => {
await expect(page.getByRole("complementary").getByText("Virtual Keys")).toBeVisible({ timeout: 15_000 });
await settingsLoaded;
// Pre-condition: we start authenticated. The admin storage state carries a
// `token` cookie, so a real logout has something to tear down.
// Pre-condition: we start authenticated. The fresh login set a `token`
// cookie, so a real logout has something to tear down.
const tokensBefore = (await page.context().cookies()).filter((c) => c.name === "token");
expect(tokensBefore.length, "should start logged in with a token cookie").toBeGreaterThan(0);