Spaces:
Sleeping
Sleeping
| import { test as setup, expect } from '@playwright/test' | |
| // Relative to the config dir (client/), matching `storageState` in | |
| // playwright.config.ts. Playwright runs from the client workspace root. | |
| const stateFile = 'e2e/.tmp/state.json' | |
| // Credentials match e2e/server-launch.mjs (ADMIN_EMAIL/ADMIN_PASSWORD). The | |
| // seeded admin is created with must_change_password=1, so the first login goes | |
| // through the forced change-password step before reaching the dashboard. | |
| const EMAIL = 'e2e@trek.local' | |
| const SEED_PW = 'E2eTest12345!' | |
| const NEW_PW = 'E2eChanged12345!' | |
| setup('authenticate the seeded admin (incl. forced password change)', async ({ page }) => { | |
| await page.goto('/login') | |
| await page.locator('input[type="email"]').fill(EMAIL) | |
| await page.locator('input[type="password"]').fill(SEED_PW) | |
| await page.locator('button[type="submit"]').click() | |
| // must_change_password=1 → the change-password step renders two password | |
| // fields (new + confirm). Selector-agnostic of the UI language. | |
| const pw = page.locator('input[type="password"]') | |
| await expect(pw).toHaveCount(2) | |
| await pw.nth(0).fill(NEW_PW) | |
| await pw.nth(1).fill(NEW_PW) | |
| await page.locator('button[type="submit"]').click() | |
| await page.waitForURL('**/dashboard', { timeout: 30_000 }) | |
| // Dismiss the first-run "Welcome to TREK" system-notice modal(s). It renders | |
| // asynchronously (after the notices fetch), so wait for it before clicking. | |
| // Dismissal is recorded server-side against this user, so clearing it here | |
| // keeps it cleared for every authenticated flow in the run (shared test DB). | |
| const ok = page.getByRole('button', { name: 'OK', exact: true }) | |
| await ok.waitFor({ state: 'visible', timeout: 10_000 }).catch(() => {}) | |
| for (let i = 0; i < 8 && (await ok.isVisible().catch(() => false)); i++) { | |
| await ok.click() | |
| await page.waitForTimeout(400) | |
| } | |
| await page.context().storageState({ path: stateFile }) | |
| }) | |