69 lines
2.1 KiB
TypeScript
69 lines
2.1 KiB
TypeScript
/**
|
|
* 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<Fixtures>({
|
|
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)}`
|