import { test as setup, expect } from '@playwright/test'; const speakeasy = await import('speakeasy').then(m => m.default); const authFile = 'tests/.auth/user.json'; /** * Authentication setup * * This runs before all other tests to authenticate once and save the session state. * Other tests will reuse this authentication state instead of logging in each time. * * Setup: * 1. Create a test user in your database * 2. Enable TOTP for that user * 3. Set TEST_USER_EMAIL, TEST_USER_PASSWORD, and TEST_USER_TOTP_SECRET in .env */ setup('authenticate', async ({ page }) => { const email = process.env.TEST_USER_EMAIL || 'test@example.com'; const password = process.env.TEST_USER_PASSWORD || 'password'; const totpSecret = process.env.TEST_USER_TOTP_SECRET; if (!totpSecret) { throw new Error( 'TEST_USER_TOTP_SECRET is not set. ' + 'Create a test user with TOTP enabled and set the secret in .env' ); } console.log(`Authenticating as ${email}...`); // Navigate to login page await page.goto('/users/log-in'); // Fill in email and password (use the password form, not magic link) await page.locator('#user_email_password').fill(email); await page.getByLabel('Password').fill(password); // Submit login form await page.getByRole('button', { name: /log in/i }).click(); // Wait for TOTP page await page.waitForURL('**/users/log-in/totp'); // Generate TOTP code using speakeasy const token = speakeasy.totp({ secret: totpSecret, encoding: 'base32' }); console.log(`Generated TOTP token: ${token}`); // Fill in TOTP code await page.getByLabel(/authentication code|totp|code/i).fill(token); // Submit TOTP form await page.getByRole('button', { name: /verify|submit|continue/i }).click(); // Wait for redirect to dashboard await page.waitForURL('**/dashboard'); // Verify we're logged in by checking for navigation or user elements await expect(page.locator('body')).toContainText(/dashboard/i); console.log('Authentication successful!'); // Save authenticated state await page.context().storageState({ path: authFile }); });