/** * Shared registration/onboarding steps for specs that need a brand-new, * empty account rather than the shared demo workspace (`global-setup.ts`'s * seeded data) — e.g. because the gesture under test needs a clean * calendar, or because the demo user's own balance is deliberately drained * (see `backend/scripts/seed_demo.py`'s "near-drained FP pool" for Alex, * which a fresh drag-created period pinned to the logged-in parent would * otherwise fail to fund). * * Every date here is derived from "today", never a hardcoded year. */ import type { Page } from '@playwright/test' import { expect } from '@playwright/test' import { toIsoDate, addDays } from './dates' export function uniqueEmail(tag: string): string { return `e2e-${tag}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}@example.com` } export const ONBOARDING_PASSWORD = 'E2ePassOnboard123!' /** Registers a brand-new account through the real UI and waits for the * onboarding wizard's first step. */ export async function registerAndReachOnboarding(page: Page, email: string, displayName: string): Promise { await page.goto('/auth') await page.getByRole('button', { name: 'Skapa konto' }).click() await page.getByPlaceholder('Namn').fill(displayName) await page.getByTestId('auth-email').fill(email) await page.getByTestId('auth-password').fill(ONBOARDING_PASSWORD) await page.getByTestId('auth-submit').click() await expect(page.getByTestId('onboarding')).toBeVisible({ timeout: 15_000 }) await expect(page.getByTestId('onboarding-step-child')).toBeVisible() } /** Step 1 of the wizard: add the child, landing on step 2 (family). */ export async function fillChildStep(page: Page, childName: string): Promise { // Safely in the past relative to "today", regardless of when this runs. const birthDate = toIsoDate(addDays(new Date(), -400)) await page.getByLabel('Barnets namn').fill(childName) await page.getByTestId('birth-date-input').fill(birthDate) await page.getByRole('button', { name: 'Lägg till barn' }).click() await expect(page.getByTestId('onboarding-step-family')).toBeVisible() } /** From step 2 (family) — "Bara jag" is selected by default, so this just * continues to step 3 (balances) and presses "Klar" without filling * anything in — landing on the Dashboard with the statutory-assumption * balance (no manual fetch, no drained pool). */ export async function continueSoloAndSkipBalances(page: Page): Promise { await page.getByRole('button', { name: 'Fortsätt' }).click() await expect(page.getByTestId('onboarding-step-balances')).toBeVisible() await page.getByTestId('onboarding-finish').click() await expect(page.getByTestId('dashboard')).toBeVisible({ timeout: 15_000 }) } /** From step 2 (family), selects "Vi är två föräldrar", fills in the other * parent's name and continues — landing on step 3 (balances) with both * parents' cards visible. */ export async function chooseTwoParents(page: Page, partnerName: string): Promise { await page.getByTestId('onboarding-family-couple').click() await page.getByLabel('Den andra förälderns namn').fill(partnerName) await page.getByRole('button', { name: 'Fortsätt' }).click() await expect(page.getByTestId('onboarding-step-balances')).toBeVisible() } /** In step 3 (balances), opens "Ange själv" on the parent card matching * `name` and fills in + saves the three balance fields shown there. */ export async function enterBalancesFor( page: Page, name: string, balances: { sjukpenning: number; lagsta: number; dubbeldagar: number }, ): Promise { const card = page.getByTestId('onboarding-parent-card').filter({ hasText: name }) await card.getByRole('button', { name: 'Ange själv' }).click() await page.getByLabel(/Sjukpenningnivå/).fill(String(balances.sjukpenning)) await page.getByLabel(/Lägstanivå/).fill(String(balances.lagsta)) await page.getByLabel(/Dubbeldagar/).fill(String(balances.dubbeldagar)) await page.getByRole('button', { name: 'Spara' }).click() }