QA-1: stateful in-memory mock API per route interception (DATA-2 contract: Gridify paging, camelCase DTOs, 409 delete-conflicts) + fixtures
This commit is contained in:
68
gerbil-manager-web/e2e/fixtures.ts
Normal file
68
gerbil-manager-web/e2e/fixtures.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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)}`
|
||||
Reference in New Issue
Block a user