feat: add Playwright E2E and API regression test suite
Production-ready test infrastructure with Page Object Model pattern, reusable fixtures for auth/DB/test-data, and example tests covering login flow, dashboard, accounts CRUD API, and visual regression. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
50
tests/auth.setup.ts
Normal file
50
tests/auth.setup.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Auth setup project — runs ONCE before all browser-based tests.
|
||||
*
|
||||
* Logs in via the UI, then saves the authenticated browser state
|
||||
* (cookies + localStorage) to tests/.auth/user.json so that every
|
||||
* subsequent test starts already logged in.
|
||||
*
|
||||
* This matches Playwright's recommended "global setup via project
|
||||
* dependencies" pattern.
|
||||
*/
|
||||
|
||||
import { test as setup, expect } from '@playwright/test';
|
||||
import { TEST_USERS } from './fixtures/test-data';
|
||||
import path from 'path';
|
||||
|
||||
const authFile = path.join(__dirname, '.auth', 'user.json');
|
||||
|
||||
setup('authenticate as test treasurer', async ({ page }) => {
|
||||
// Navigate to login page
|
||||
await page.goto('/login');
|
||||
|
||||
// Fill login form — uses Mantine component labels
|
||||
await page.getByLabel('Email').fill(TEST_USERS.treasurer.email);
|
||||
await page.getByLabel('Password').fill(TEST_USERS.treasurer.password);
|
||||
|
||||
// Submit
|
||||
await page.getByRole('button', { name: 'Sign in' }).click();
|
||||
|
||||
// Wait for redirect away from login page.
|
||||
// After login, the app redirects to /select-org (multi-org) or /dashboard.
|
||||
await page.waitForURL(/\/(select-org|dashboard|admin|onboarding)/, {
|
||||
timeout: 15_000,
|
||||
});
|
||||
|
||||
// If we land on org selection, pick the first org
|
||||
if (page.url().includes('/select-org')) {
|
||||
// Click the first organization card/button
|
||||
const orgButton = page.getByRole('button').first();
|
||||
if (await orgButton.isVisible({ timeout: 3_000 }).catch(() => false)) {
|
||||
await orgButton.click();
|
||||
await page.waitForURL(/\/dashboard/, { timeout: 10_000 });
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we're authenticated — page should not be on /login
|
||||
expect(page.url()).not.toContain('/login');
|
||||
|
||||
// Save authenticated state
|
||||
await page.context().storageState({ path: authFile });
|
||||
});
|
||||
Reference in New Issue
Block a user