import { test, expect, Page } from '@playwright/test'; import path from 'path'; const DEMO_ACCOUNTS = { admin: { email: 'admin@example.com', password: 'demo123' }, organizer: { email: 'organizer@example.com', password: 'demo123' }, staff: { email: 'staff@example.com', password: 'demo123' }, }; async function takeScreenshot(page: Page, name: string) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const fileName = `auth_${name}_${timestamp}.png`; await page.screenshot({ path: path.join('screenshots', fileName), fullPage: true }); return fileName; } async function clearAuthStorage(page: Page) { await page.evaluate(() => { localStorage.removeItem('bct_auth_user'); localStorage.removeItem('bct_auth_remember'); }); } test.describe('Authentication Flows', () => { test.beforeEach(async ({ page }) => { // Clear any existing auth state await clearAuthStorage(page); await page.goto('/'); }); test('should redirect to login when accessing protected route', async ({ page }) => { await page.goto('/dashboard'); // Should redirect to login page await expect(page).toHaveURL('/login'); await expect(page.locator('h1')).toContainText('Sign In'); await takeScreenshot(page, 'protected-route-redirect'); }); test('should login successfully with valid admin credentials', async ({ page }) => { await page.goto('/login'); await takeScreenshot(page, 'login-page-initial'); // Fill in admin credentials await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); await takeScreenshot(page, 'login-form-filled'); // Submit login form await page.click('[data-testid="login-button"]'); // Wait for loading state await expect(page.locator('[data-testid="login-button"]')).toBeDisabled(); await takeScreenshot(page, 'login-loading-state'); // Should redirect to dashboard await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); // Verify user is logged in await expect(page.locator('[data-testid="user-menu"]')).toBeVisible(); await expect(page.locator('[data-testid="user-name"]')).toContainText('Sarah Admin'); await takeScreenshot(page, 'dashboard-logged-in-admin'); }); test('should login successfully with organizer credentials', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.organizer.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.organizer.password); await page.click('[data-testid="login-button"]'); await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); await expect(page.locator('[data-testid="user-name"]')).toContainText('John Organizer'); await takeScreenshot(page, 'dashboard-logged-in-organizer'); }); test('should login successfully with staff credentials', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.staff.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.staff.password); await page.click('[data-testid="login-button"]'); await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); await expect(page.locator('[data-testid="user-name"]')).toContainText('Emma Staff'); await takeScreenshot(page, 'dashboard-logged-in-staff'); }); test('should show error for invalid credentials', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid="email-input"]', 'invalid@example.com'); await page.fill('[data-testid="password-input"]', 'wrongpassword'); await page.click('[data-testid="login-button"]'); // Should show error message await expect(page.locator('[data-testid="error-message"]')).toBeVisible(); await expect(page.locator('[data-testid="error-message"]')).toContainText('Invalid email or password'); // Should remain on login page await expect(page).toHaveURL('/login'); await takeScreenshot(page, 'login-error-state'); }); test('should show error for short password', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', '12'); // Too short await page.click('[data-testid="login-button"]'); await expect(page.locator('[data-testid="error-message"]')).toBeVisible(); await expect(page.locator('[data-testid="error-message"]')).toContainText('Invalid email or password'); await takeScreenshot(page, 'login-short-password-error'); }); test('should toggle password visibility', async ({ page }) => { await page.goto('/login'); const passwordInput = page.locator('[data-testid="password-input"]'); const toggleButton = page.locator('[data-testid="password-toggle"]'); // Password should be hidden initially await expect(passwordInput).toHaveAttribute('type', 'password'); await page.fill('[data-testid="password-input"]', 'testpassword'); await takeScreenshot(page, 'password-hidden'); // Click toggle to show password await toggleButton.click(); await expect(passwordInput).toHaveAttribute('type', 'text'); await takeScreenshot(page, 'password-visible'); // Click toggle to hide password again await toggleButton.click(); await expect(passwordInput).toHaveAttribute('type', 'password'); }); test('should remember login when remember me is checked', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); // Check remember me await page.check('[data-testid="remember-me"]'); await takeScreenshot(page, 'remember-me-checked'); await page.click('[data-testid="login-button"]'); await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); // Verify localStorage has auth data const authData = await page.evaluate(() => localStorage.getItem('bct_auth_user')); const rememberMe = await page.evaluate(() => localStorage.getItem('bct_auth_remember')); expect(authData).toBeTruthy(); expect(rememberMe).toBe('true'); // Refresh page - should stay logged in await page.reload(); await expect(page).toHaveURL('/dashboard'); await expect(page.locator('[data-testid="user-name"]')).toContainText('Sarah Admin'); await takeScreenshot(page, 'persistent-login-after-refresh'); }); test('should logout successfully', async ({ page }) => { // First login await page.goto('/login'); await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); await page.click('[data-testid="login-button"]'); await expect(page).toHaveURL('/dashboard', { timeout: 10000 }); // Open user menu and logout await page.click('[data-testid="user-menu"]'); await takeScreenshot(page, 'user-menu-open'); await page.click('[data-testid="logout-button"]'); // Should redirect to login await expect(page).toHaveURL('/login', { timeout: 10000 }); // Verify localStorage is cleared const authData = await page.evaluate(() => localStorage.getItem('bct_auth_user')); const rememberMe = await page.evaluate(() => localStorage.getItem('bct_auth_remember')); expect(authData).toBeNull(); expect(rememberMe).toBeNull(); await takeScreenshot(page, 'logout-complete'); }); test('should redirect back to intended route after login', async ({ page }) => { // Try to access events page directly await page.goto('/events'); // Should redirect to login with return URL await expect(page).toHaveURL('/login'); // Login await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); await page.click('[data-testid="login-button"]'); // Should redirect back to events page await expect(page).toHaveURL('/events', { timeout: 10000 }); await takeScreenshot(page, 'redirect-to-intended-route'); }); test('should handle form validation', async ({ page }) => { await page.goto('/login'); // Try to submit empty form await page.click('[data-testid="login-button"]'); // Should show validation errors await expect(page.locator('[data-testid="email-error"]')).toBeVisible(); await expect(page.locator('[data-testid="password-error"]')).toBeVisible(); await takeScreenshot(page, 'form-validation-errors'); // Fill invalid email await page.fill('[data-testid="email-input"]', 'invalidemail'); await page.click('[data-testid="login-button"]'); await expect(page.locator('[data-testid="email-error"]')).toContainText('Invalid email'); await takeScreenshot(page, 'invalid-email-error'); }); test('should handle network errors gracefully', async ({ page }) => { await page.goto('/login'); // Simulate network failure by blocking requests await page.route('**/api/**', route => route.abort()); await page.fill('[data-testid="email-input"]', DEMO_ACCOUNTS.admin.email); await page.fill('[data-testid="password-input"]', DEMO_ACCOUNTS.admin.password); await page.click('[data-testid="login-button"]'); // Should show network error await expect(page.locator('[data-testid="error-message"]')).toBeVisible(); await takeScreenshot(page, 'network-error-state'); }); });