/** * E2E tests for the authentication flow. * * Tests login via UI (not reusing stored auth state). * These tests use a fresh browser context per test. */ import { test, expect } from '@playwright/test'; import { LoginPage } from '../page-objects'; import { TEST_USERS } from '../fixtures/test-data'; // Don't use stored auth state — we're testing the login flow itself test.use({ storageState: { cookies: [], origins: [] } }); test.describe('Login Page', () => { let loginPage: LoginPage; test.beforeEach(async ({ page }) => { loginPage = new LoginPage(page); await loginPage.goto(); }); test('should display login form', async () => { await expect(loginPage.emailInput).toBeVisible(); await expect(loginPage.passwordInput).toBeVisible(); await expect(loginPage.signInButton).toBeVisible(); }); test('should show error for invalid credentials', async () => { await loginPage.login('invalid@example.com', 'WrongPassword!'); // Wait for the error alert to appear await loginPage.assertError(/invalid|unauthorized|failed/i); await loginPage.assertStillOnLogin(); }); test('should show validation error for empty fields', async ({ page }) => { // Try to submit with empty password await loginPage.emailInput.fill('test@example.com'); await loginPage.signInButton.click(); // Should remain on login page (Mantine form validation) await loginPage.assertStillOnLogin(); }); test('should login successfully with valid credentials', async () => { await loginPage.loginAndWaitForRedirect( TEST_USERS.treasurer.email, TEST_USERS.treasurer.password, ); // Should be redirected away from login await expect(loginPage.page).not.toHaveURL(/\/login/); }); test('should show register link', async () => { await expect(loginPage.registerLink).toBeVisible(); }); test('should redirect unauthenticated users to login', async ({ page }) => { // Try accessing a protected route directly await page.goto('/dashboard'); // Should be redirected to login await expect(page).toHaveURL(/\/login/); }); }); test.describe('Logout', () => { test('should clear auth state on logout', async ({ page }) => { // First login const loginPage = new LoginPage(page); await loginPage.goto(); await loginPage.loginAndWaitForRedirect( TEST_USERS.treasurer.email, TEST_USERS.treasurer.password, ); // Handle org selection if needed if (page.url().includes('/select-org')) { await page.getByRole('button').first().click(); await page.waitForURL(/\/dashboard/, { timeout: 10_000 }); } // Look for logout in user menu/settings const userMenu = page.locator('[class*="avatar"], [class*="Avatar"]').first(); if (await userMenu.isVisible({ timeout: 3_000 }).catch(() => false)) { await userMenu.click(); } const logoutButton = page.getByRole('button', { name: /logout|sign out/i }).first(); if (await logoutButton.isVisible({ timeout: 3_000 }).catch(() => false)) { await logoutButton.click(); await expect(page).toHaveURL(/\/login/); } }); });