diff --git a/gerbil-manager-web/e2e/fixtures.ts b/gerbil-manager-web/e2e/fixtures.ts index 358f507..60ea644 100644 --- a/gerbil-manager-web/e2e/fixtures.ts +++ b/gerbil-manager-web/e2e/fixtures.ts @@ -39,6 +39,17 @@ export function skipUnlessMock() { test.skip(LIVE, 'benötigt die Mock-Seed-Daten (läuft nicht im LIVE-Modus)') } +/** + * Test überspringen im Mock-Modus — nur im LIVE-Modus sinnvoll. + * Live-Tests MÜSSEN Ergebnisse assertieren (z. B. Liste nicht leer, + * konkreter Wert sichtbar), nicht nur HTTP-200. Lesson: der Mock spiegelt + * den Frontend-Code, nicht das echte Backend — ein Bug bleibt unsichtbar, + * wenn wir nur testen, ob die Seite lädt. + */ +export function skipUnlessLive() { + test.skip(!LIVE, 'nur im LIVE-Modus sinnvoll (E2E_BASE_URL setzen)') +} + /** * Zu einem Navigationsziel wechseln — auf dem Smartphone liegen Becken, * Kontakte und Statistik hinter dem „Mehr“-Blatt. diff --git a/gerbil-manager-web/e2e/live.spec.ts b/gerbil-manager-web/e2e/live.spec.ts new file mode 100644 index 0000000..ce495eb --- /dev/null +++ b/gerbil-manager-web/e2e/live.spec.ts @@ -0,0 +1,57 @@ +/** + * QA-2: Live-Modus-Smoke — läuft NUR gegen das echte Backend (E2E_BASE_URL). + * + * Lektion (aus dem Such-Bug): Mock-Tests spiegeln nur den Frontend-Code. + * Ein Backend-Bug (falscher Filter, leere Antwort, fehlende Migration) bleibt + * unsichtbar, wenn Live-Tests nur "Seite lädt" prüfen. Diese Tests assertieren + * ERGEBNISSE: Liste nicht leer, Suche liefert Treffer, Detail zeigt Stammdaten + * und Eltern-Links. + * + * Voraussetzung für den Eltern-Link-Test: Re-Import #2 durchgeführt + * (322 Tiere, 882 Würfe live; mindestens ein Wurf hat beide Eltern). + */ +import { de, expect, gotoSection, skipUnlessLive, test } from './fixtures' + +const t = de.pages.gerbils +const tl = de.pages.litters + +test('Live: Tiere-Liste enthält nach Re-Import mindestens 10 Einträge', async ({ page }) => { + skipUnlessLive() + await gotoSection(page, de.nav.gerbils) + await expect(page.getByRole('heading', { name: t.title, exact: true })).toBeVisible() + // Leere Liste = Backend-Bug (falscher Filter, fehlende DB-Migration o. ä.) + const rows = page.locator('.gerbil-row') + await expect(rows.first()).toBeVisible() + expect(await rows.count()).toBeGreaterThanOrEqual(10) +}) + +test('Live: Namenssuche gibt Treffer zurück — nicht nur HTTP 200', async ({ page }) => { + skipUnlessLive() + await gotoSection(page, de.nav.gerbils) + await expect(page.getByRole('heading', { name: t.title, exact: true })).toBeVisible() + // Kurzer Prefix: bei 322 Tieren mindestens 1 Treffer. Kein Treffer = Gridify-Bug. + await page.getByPlaceholder(t.searchPlaceholder).first().fill('a') + const rows = page.locator('.gerbil-row') + await expect(rows.first()).toBeVisible({ timeout: 10_000 }) + expect(await rows.count()).toBeGreaterThanOrEqual(1) +}) + +test('Live: Wurf-Detail zeigt Elterntier-Links (mindestens Vater oder Mutter)', async ({ + page, +}) => { + skipUnlessLive() + // Nach Re-Import #2 hat mindestens Gerbil C (Victoria) beide Eltern. + // Der Wurf-Detail ist die einfachste Ansicht, die Eltern-Links rendert. + await gotoSection(page, de.nav.litters) + await expect(page.getByRole('heading', { name: tl.title, exact: true })).toBeVisible() + + // Mindestens 1 Wurf in der Liste; ersten öffnen. + const firstLink = page.getByRole('link').filter({ hasText: /.+/ }).nth(1) + await expect(firstLink).toBeVisible() + await firstLink.click() + + // Detailseite: Elterntier-Abschnitt ist sichtbar + await expect(page.getByText(tl.detail.parents)).toBeVisible() + // Mindestens ein Link führt zu einem Tier — bei fehlendem Import fehlt dieser Link + await expect(page.locator('a[href*="/rennmaeuse/"]').first()).toBeVisible({ timeout: 5_000 }) +})