|
5 | 5 | * Modify these values in one place to affect all tests. |
6 | 6 | */ |
7 | 7 |
|
| 8 | +/** |
| 9 | + * Load environment-specific credentials before any constant is evaluated. |
| 10 | + * |
| 11 | + * Placing dotenv loading here (rather than only in playwright.config.ts) ensures |
| 12 | + * that worker processes which import this module directly also pick up the .env |
| 13 | + * file, because module imports in playwright.config.ts are evaluated before the |
| 14 | + * dotenv.config() call in that file executes. |
| 15 | + * |
| 16 | + * Select environment with APP_ENV: |
| 17 | + * APP_ENV=dev → .env.dev (local development) |
| 18 | + * APP_ENV=prod → .env.prod (production) |
| 19 | + * (none) → .env (default) |
| 20 | + */ |
| 21 | +import dotenv from 'dotenv'; |
| 22 | +import path from 'path'; |
| 23 | + |
| 24 | +const _env = process.env.APP_ENV; |
| 25 | +const _envFile = _env ? `.env.${_env}` : '.env'; |
| 26 | +dotenv.config({ path: path.resolve(__dirname, '..', _envFile) }); |
| 27 | + |
| 28 | +/** |
| 29 | + * Test User Credentials |
| 30 | + * |
| 31 | + * Loaded from environment variables — never hardcoded. |
| 32 | + * Local dev: copy .env.example to .env and fill in values. |
| 33 | + * CI: injected automatically via GitHub Secrets. |
| 34 | + */ |
| 35 | +export const TEST_USERS = { |
| 36 | + employee: { |
| 37 | + username: process.env.TEST_USER_EMPLOYEE_USERNAME || '', |
| 38 | + password: process.env.TEST_USER_EMPLOYEE_PASSWORD || '', |
| 39 | + role: 'employee' as const, |
| 40 | + }, |
| 41 | + manager: { |
| 42 | + username: process.env.TEST_USER_MANAGER_USERNAME || '', |
| 43 | + password: process.env.TEST_USER_MANAGER_PASSWORD || '', |
| 44 | + role: 'manager' as const, |
| 45 | + }, |
| 46 | + hradmin: { |
| 47 | + username: process.env.TEST_USER_HRADMIN_USERNAME || '', |
| 48 | + password: process.env.TEST_USER_HRADMIN_PASSWORD || '', |
| 49 | + role: 'hradmin' as const, |
| 50 | + }, |
| 51 | +} as const; |
| 52 | + |
| 53 | +/** |
| 54 | + * Fail fast if credentials are missing — prevents cryptic login failures. |
| 55 | + */ |
| 56 | +export function assertCredentialsLoaded(): void { |
| 57 | + const missing = (Object.entries(TEST_USERS) as [string, { username: string; password: string }][]) |
| 58 | + .filter(([, u]) => !u.username || !u.password) |
| 59 | + .map(([role]) => role); |
| 60 | + if (missing.length > 0) { |
| 61 | + throw new Error( |
| 62 | + `Missing credentials for roles: ${missing.join(', ')}. ` + |
| 63 | + `Copy .env.example to .env and fill in values, or set GitHub Secrets for CI.` |
| 64 | + ); |
| 65 | + } |
| 66 | +} |
| 67 | + |
8 | 68 | /** |
9 | 69 | * Application URLs |
10 | 70 | */ |
@@ -192,3 +252,16 @@ export function getUrl(path: string): string { |
192 | 252 | export function getApiUrl(endpoint: string): string { |
193 | 253 | return `${APP_URLS.api}${endpoint}`; |
194 | 254 | } |
| 255 | + |
| 256 | +/** |
| 257 | + * Returns a RegExp that matches any URL on the Angular app host. |
| 258 | + * Use instead of hardcoded /localhost:4200/ so tests work across environments. |
| 259 | + * |
| 260 | + * @example |
| 261 | + * await expect(page).toHaveURL(getAngularUrlPattern()); |
| 262 | + * await page.waitForURL(getAngularUrlPattern()); |
| 263 | + */ |
| 264 | +export function getAngularUrlPattern(): RegExp { |
| 265 | + const host = new URL(APP_URLS.angular).host.replace(/\./g, '\\.'); |
| 266 | + return new RegExp(host); |
| 267 | +} |
0 commit comments