/** * QA-1: Test-Fixtures. * * - MOCK-Modus (Standard): installiert vor jedem Test den In-Memory-Mock * (frischer Datenbestand pro Test). * - LIVE-Modus (E2E_BASE_URL gesetzt): kein Mock; fixture-gebundene Tests * überspringen sich über `skipUnlessMock()`. * * Deutsche Oberflächen-Texte werden DIREKT aus src/strings/de.ts importiert — * die Suite bleibt damit automatisch synchron zur App. */ import { test as base, expect, type Page } from '@playwright/test' import { de } from '../src/strings/de' import { installMockApi } from './mock-api' import type { MockDb } from './mock-data' export const LIVE = Boolean(process.env.E2E_BASE_URL) export { expect } export { de } interface Fixtures { /** Im Mock-Modus der pro Test frische Datenbestand, sonst null. */ mockDb: MockDb | null } export const test = base.extend({ mockDb: [ async ({ page }, use) => { const db = LIVE ? null : await installMockApi(page) await use(db) }, { auto: true }, ], }) /** Test überspringen, wenn er Seed-Daten des Mocks voraussetzt. */ export function skipUnlessMock() { test.skip(LIVE, 'benötigt die Mock-Seed-Daten (läuft nicht im LIVE-Modus)') } /** * Zu einem Navigationsziel wechseln — auf dem Smartphone liegen Becken, * Kontakte und Statistik hinter dem „Mehr“-Blatt. */ export async function gotoSection(page: Page, label: string) { const nav = page.getByRole('navigation') // App noch nicht geladen (about:blank) -> erst zur Startseite if (!(await nav.isVisible())) { await page.goto('/') await expect(nav).toBeVisible() } const link = nav.getByRole('link', { name: label }) if (!(await link.isVisible())) { await nav.getByRole('button', { name: de.nav.more }).click() await expect(link).toBeVisible() } await link.click() } /** window.confirm des nächsten Dialogs annehmen. */ export function acceptNextDialog(page: Page) { page.once('dialog', (d) => void d.accept()) } /** Eindeutiger Name für LIVE-taugliche Create-Flows. */ export const uniqueName = (prefix: string) => `${prefix} E2E ${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`