test(e2e): read the admin JWT from the cookie, not the login body (#1073)

Stable twin of #1071.

Three specs acquire an admin token with `const body = await res.json();
return body.token`. On this branch too the admin login sets the JWT as
the httpOnly `admin_token` cookie and responds with `res.json({ user })`
— verified in auth.js on stable, not assumed from main — so the token is
undefined and each spec fails at its first assertion, before exercising
anything it was written to cover.

Cookie and Authorization: Bearer are interchangeable server-side, so the
helpers read the value back out of the context cookie jar and keep
threading it as a Bearer. Every downstream call is unchanged.

Verification is weaker than the main twin's, deliberately: the three
spec files are byte-identical to the ones measured there (0 passed /
6 failed before, 3 passed / 3 failed after, against a live stack), and
they compile and enumerate on this branch. Standing up a full stable
compose stack to re-measure test-only changes was not worth it — say the
word if you want that done before merge.

The remaining failures are UI staleness, not auth, and are not addressed
here. No CI workflow runs tests/e2e on this branch either, which is why
this rotted unnoticed.

Claude-Session: https://claude.ai/code/session_01Ra4hcsYiKuQLbbRsg6EjAc

Co-authored-by: Paul Nothaft <[email protected]>
This commit is contained in:
Paul Nothaft
2026-08-18 22:14:15 +02:00
committed by GitHub
co-authored by Paul Nothaft
parent 10d5cf54a5
commit 84eab88801
3 changed files with 19 additions and 9 deletions
+3 -3
View File
@@ -18,9 +18,9 @@ async function createEventWithPhotos(page: Page, adminToken?: string, attempt =
}, },
}); });
expect(loginResponse.ok()).toBeTruthy(); expect(loginResponse.ok()).toBeTruthy();
const loginData = await loginResponse.json(); const cookies = await page.context().cookies();
token = loginData.token; token = cookies.find((c) => c.name === 'admin_token')?.value;
expect(token).toBeTruthy(); expect(token, 'admin_token cookie missing from the login response').toBeTruthy();
} }
const eventName = `Playwright Smoke ${Date.now()}`; const eventName = `Playwright Smoke ${Date.now()}`;
+8 -3
View File
@@ -40,9 +40,14 @@ async function adminLogin(page: Page): Promise<string> {
failOnStatusCode: false, failOnStatusCode: false,
}); });
expect(res.ok()).toBeTruthy(); expect(res.ok()).toBeTruthy();
const json = await res.json(); // The admin JWT is delivered as the httpOnly `admin_token` cookie, not in
expect(json.token).toBeTruthy(); // the response body. Server-side the cookie and an Authorization: Bearer
return json.token; // header are interchangeable, so read it back out of the context jar and
// keep threading it as a Bearer — every downstream call stays as it was.
const cookies = await page.context().cookies();
const token = cookies.find((c) => c.name === 'admin_token')?.value;
expect(token, 'admin_token cookie missing from the login response').toBeTruthy();
return token as string;
} }
async function setCustomerPortalEnabled(page: Page, adminToken: string, enabled: boolean) { async function setCustomerPortalEnabled(page: Page, adminToken: string, enabled: boolean) {
@@ -8,9 +8,14 @@ async function getAdminToken(page: Page): Promise<string> {
data: { username: ADMIN_EMAIL, password: ADMIN_PASSWORD }, data: { username: ADMIN_EMAIL, password: ADMIN_PASSWORD },
}); });
expect(res.ok()).toBeTruthy(); expect(res.ok()).toBeTruthy();
const body = await res.json(); // The admin JWT is delivered as the httpOnly `admin_token` cookie, not in
expect(body.token).toBeTruthy(); // the response body. Server-side the cookie and an Authorization: Bearer
return body.token; // header are interchangeable, so read it back out of the context jar and
// keep threading it as a Bearer — every downstream call stays as it was.
const cookies = await page.context().cookies();
const token = cookies.find((c) => c.name === 'admin_token')?.value;
expect(token, 'admin_token cookie missing from the login response').toBeTruthy();
return token as string;
} }
async function updateEventSettings( async function updateEventSettings(