/** * E2E test: Registration flow. * * Validates the full magic-link registration process: * 1. Call the registration API directly (bypasses Turnstile DOM issues) * 2. Insert a known magic link token into the DB * 3. Navigate to the verify URL * 4. Assert redirect to home with user email visible * * NOTE: The Cloudflare Turnstile script causes continuous DOM mutations that * prevent Playwright from interacting with elements on the login/register * pages. The backend runs in test mode where Turnstile verification is * bypassed, so we call the API directly with a dummy token. */ import { test, expect } from '@playwright/test'; import { createHash } from 'node:crypto'; import { createDbClient } from '../helpers/auth'; test.describe('Registration flow', () => { test('should register a new user and verify via magic link', async ({ page, request, }) => { test.setTimeout(60_000); const uniqueEmail = `e2e-reg-${Date.now()}@test.local`; // Step 1: Register via the API directly. // The backend is in test mode (TURNSTILE_SECRET_KEY = "test-turnstile-secret-always-pass") // so any turnstile_token value is accepted. const registerResp = await request.post('/api/v1/auth/register', { headers: { 'X-Requested-With': 'XMLHttpRequest', }, data: { email: uniqueEmail, display_name: 'E2E Test User', turnstile_token: 'mock-token', }, }); expect(registerResp.ok()).toBe(true); // Step 2: Insert a known magic token in the DB for verification const knownRawToken = `e2e-reg-token-${Date.now()}`; const knownTokenHash = createHash('sha256') .update(knownRawToken) .digest('hex'); const expiresAt = new Date(Date.now() + 15 * 60 * 1000).toISOString(); const client = createDbClient(); await client.connect(); try { await client.query( `INSERT INTO magic_tokens (email, token_hash, expires_at, used) VALUES ($1, $2, $3, false)`, [uniqueEmail.toLowerCase(), knownTokenHash, expiresAt], ); } finally { await client.end(); } // Step 3: Navigate to the GET verify endpoint with the raw token. // This endpoint verifies the token, creates a session, sets the cookie, // and redirects to APP_URL. await page.goto(`/api/v1/auth/verify?token=${knownRawToken}`, { waitUntil: 'domcontentloaded' }); // The verify endpoint redirects to the app URL. Wait for the home page. await page.waitForURL('**/', { timeout: 15_000 }); // Step 4: Assert the user email is visible in the navbar await expect(page.getByText(uniqueEmail)).toBeVisible({ timeout: 15_000 }); }); });