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:
127
playwright.config.ts
Normal file
127
playwright.config.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Playwright configuration for HOA LedgerIQ E2E + API regression tests.
|
||||
*
|
||||
* Architecture: Docker Compose (nginx :80 -> backend :3000 + frontend :5173)
|
||||
* - Local dev: `docker-compose up` then `npm run test:e2e`
|
||||
* - CI: starts Docker services automatically
|
||||
* - Production: set BASE_URL to skip webServer start
|
||||
*/
|
||||
|
||||
// Load test-specific env from .env.test (falls back to .env)
|
||||
require('dotenv').config({ path: path.resolve(__dirname, '.env.test') });
|
||||
|
||||
const BASE_URL = process.env.BASE_URL || 'http://localhost';
|
||||
const IS_CI = !!process.env.CI;
|
||||
|
||||
// Skip auto-starting services when pointing at an external URL
|
||||
const isExternalTarget =
|
||||
BASE_URL !== 'http://localhost' && BASE_URL !== 'http://localhost:80';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
testMatch: ['**/*.spec.ts'],
|
||||
|
||||
/* Run tests in parallel where safe */
|
||||
fullyParallel: true,
|
||||
|
||||
/* Fail CI builds if test.only was left in */
|
||||
forbidOnly: IS_CI,
|
||||
|
||||
/* Retry on CI to handle transient failures */
|
||||
retries: IS_CI ? 2 : 0,
|
||||
|
||||
/* Limit parallel workers on CI */
|
||||
workers: IS_CI ? 1 : undefined,
|
||||
|
||||
/* Reporter configuration */
|
||||
reporter: IS_CI
|
||||
? [['github'], ['html', { open: 'never' }]]
|
||||
: [['list'], ['html', { open: 'on-failure' }]],
|
||||
|
||||
/* Shared settings for all projects */
|
||||
use: {
|
||||
baseURL: BASE_URL,
|
||||
|
||||
/* Collect trace on first retry for debugging */
|
||||
trace: 'on-first-retry',
|
||||
|
||||
/* Screenshot on failure */
|
||||
screenshot: 'only-on-failure',
|
||||
|
||||
/* Video on failure in CI */
|
||||
video: IS_CI ? 'on-first-retry' : 'off',
|
||||
|
||||
/* Default timeout for actions (click, fill, etc.) */
|
||||
actionTimeout: 10_000,
|
||||
|
||||
/* Navigation timeout */
|
||||
navigationTimeout: 30_000,
|
||||
},
|
||||
|
||||
/* Global test timeout */
|
||||
timeout: 60_000,
|
||||
|
||||
/* Assertion timeout */
|
||||
expect: {
|
||||
timeout: 10_000,
|
||||
toHaveScreenshot: {
|
||||
maxDiffPixelRatio: 0.02,
|
||||
},
|
||||
},
|
||||
|
||||
/* Browser projects */
|
||||
projects: [
|
||||
/* Auth setup — runs once, stores auth state for other tests */
|
||||
{
|
||||
name: 'auth-setup',
|
||||
testMatch: /auth\.setup\.ts/,
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
{
|
||||
name: 'chromium',
|
||||
use: {
|
||||
...devices['Desktop Chrome'],
|
||||
storageState: 'tests/.auth/user.json',
|
||||
},
|
||||
dependencies: ['auth-setup'],
|
||||
},
|
||||
{
|
||||
name: 'firefox',
|
||||
use: {
|
||||
...devices['Desktop Firefox'],
|
||||
storageState: 'tests/.auth/user.json',
|
||||
},
|
||||
dependencies: ['auth-setup'],
|
||||
},
|
||||
{
|
||||
name: 'webkit',
|
||||
use: {
|
||||
...devices['Desktop Safari'],
|
||||
storageState: 'tests/.auth/user.json',
|
||||
},
|
||||
dependencies: ['auth-setup'],
|
||||
},
|
||||
/* API tests — no browser needed, runs in chromium for request context */
|
||||
{
|
||||
name: 'api',
|
||||
testMatch: ['**/api/**/*.spec.ts'],
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
dependencies: [],
|
||||
},
|
||||
],
|
||||
|
||||
/* Start Docker services before tests when running locally */
|
||||
...(!isExternalTarget && {
|
||||
webServer: {
|
||||
command: 'docker-compose up -d && sleep 5 && docker-compose exec backend echo "ready"',
|
||||
url: BASE_URL,
|
||||
reuseExistingServer: !IS_CI,
|
||||
timeout: 120_000,
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
},
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user