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>
128 lines
3.2 KiB
TypeScript
128 lines
3.2 KiB
TypeScript
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',
|
|
},
|
|
}),
|
|
});
|