diff --git a/e2e/helpers/auth.js b/e2e/helpers/auth.js index 82f580b..d85c110 100644 --- a/e2e/helpers/auth.js +++ b/e2e/helpers/auth.js @@ -1,36 +1,32 @@ /** * Login helpers using dev endpoints. - * These set real httpOnly JWT cookies so all middleware works naturally. - */ - -/** - * Login as admin via the dev test-login endpoint. - * Creates a test admin user if none exists and sets the auth cookie. - * Waits for networkidle so the client-side auth check (admin middleware + - * auth-init plugin) completes before the test navigates anywhere. + * + * Implementation note: hits the dev endpoints via the APIRequestContext + * (no page navigation). The Set-Cookie response writes auth-token to the + * BrowserContext's cookie jar, so any subsequent page.goto() is authed. + * Avoids the Nuxt-dev networkidle race that made page.goto-based login flaky. */ export async function loginAsAdmin(page) { - await page.goto('/api/dev/test-login', { waitUntil: 'domcontentloaded' }) - - // The endpoint sets the cookie and redirects to /admin. - // waitForURL fires as soon as the URL changes — not when JS finishes. - // waitForLoadState('networkidle') ensures the auth-init plugin and admin - // middleware have both completed their checkMemberStatus() calls before - // the test proceeds. - try { - await page.waitForURL(/\/admin/, { timeout: 15000 }) - await page.waitForLoadState('networkidle') - } catch { - // Cookie should be set even if redirect failed — navigate manually - await page.goto('/admin', { waitUntil: 'networkidle' }) - await page.waitForURL(/\/admin/) + const res = await page.context().request.get('/api/dev/test-login', { maxRedirects: 0 }) + if (res.status() !== 302) { + throw new Error(`/api/dev/test-login returned ${res.status()}; expected 302`) + } + const cookies = await page.context().cookies() + if (!cookies.find((c) => c.name === 'auth-token')) { + throw new Error('/api/dev/test-login did not set auth-token cookie') } } -/** - * Login as a specific member by email via the dev member-login endpoint. - */ export async function loginAsMember(page, email) { - await page.goto(`/api/dev/member-login?email=${encodeURIComponent(email)}`, { waitUntil: 'domcontentloaded' }) - await page.waitForURL(/\/member\//) + const res = await page.context().request.get( + `/api/dev/member-login?email=${encodeURIComponent(email)}`, + { maxRedirects: 0 } + ) + if (res.status() !== 302) { + throw new Error(`/api/dev/member-login returned ${res.status()}; expected 302`) + } + const cookies = await page.context().cookies() + if (!cookies.find((c) => c.name === 'auth-token')) { + throw new Error('/api/dev/member-login did not set auth-token cookie') + } } diff --git a/playwright.config.js b/playwright.config.js index 9cc1897..40d9cb4 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -7,10 +7,10 @@ export default defineConfig({ testDir: "./e2e", outputDir: "e2e/test-results", snapshotDir: "e2e/__screenshots__", - fullyParallel: true, + fullyParallel: false, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 1 : 0, - workers: process.env.CI ? 1 : undefined, + retries: process.env.CI ? 1 : 1, + workers: process.env.CI ? 1 : 4, reporter: "html", timeout: 60000, use: {