diff --git a/gerbil-manager-web/e2e/abgabe.spec.ts b/gerbil-manager-web/e2e/abgabe.spec.ts index 8834292..b62487c 100644 --- a/gerbil-manager-web/e2e/abgabe.spec.ts +++ b/gerbil-manager-web/e2e/abgabe.spec.ts @@ -2,37 +2,36 @@ * QA-2: Abgabe-Wizard (FEAT-12a + FEAT-13) — Abgabetiere gruppieren, * KI-Inserat generieren, und Vertrag-Handoff via ?tiere= Query-Parameter. * - * Mock-gebunden (Seed: 2 ForSale-Tiere im Großbecken) → skipUnlessMock. + * Mock-gebunden (Seed: 2 ForSale-Tiere im Quarantänebecken) → skipUnlessMock. */ -import { acceptNextDialog, de, expect, gotoSection, skipUnlessMock, test } from './fixtures' +import { de, expect, gotoSection, skipUnlessMock, test } from './fixtures' const ta = de.pages.abgabe const tw = de.pages.vertraege.wizard -const tk = de.pages.kontakte test.describe('Abgabe', () => { - test('Abgabe-Seite zeigt ForSale-Tiere gruppiert nach Becken', async ({ page }) => { + test('Abgabe-Seite zeigt ForSale-Tiere und Inserat-Vorschau', async ({ page }) => { skipUnlessMock() await gotoSection(page, de.nav.forSale) await expect(page.getByRole('heading', { name: ta.title, exact: true })).toBeVisible() await expect(page.getByText(ta.grouping.title)).toBeVisible() - // Die beiden ForSale-Tiere müssen sichtbar sein - await expect(page.getByText('Balu Abgabe')).toBeVisible() - await expect(page.getByText('Benny Abgabe')).toBeVisible() + // Die beiden ForSale-Tiere müssen als Tiername (strong-Element im Komposer) sichtbar sein + await expect(page.locator('.group-composer__animal-head strong').filter({ hasText: 'Balu Abgabe' })).toBeVisible() + await expect(page.locator('.group-composer__animal-head strong').filter({ hasText: 'Benny Abgabe' })).toBeVisible() // Inserat-Vorschau (listing-preview) wird gerendert await expect(page.locator('.listing-preview').first()).toBeVisible() // Status-Dropdown standard: FREI await expect( - page.locator('label.field').filter({ hasText: ta.listing.status }).locator('select').first() + page.locator('label.field').filter({ has: page.locator(`span:text-is("${ta.listing.status}")`) }).locator('select').first() ).toHaveValue('free') }) test('KI-Inserat: "Text mit KI verbessern" — Mock liefert Inserat-Text', async ({ page }) => { skipUnlessMock() await gotoSection(page, de.nav.forSale) - await expect(page.getByText('Balu Abgabe')).toBeVisible() + await expect(page.locator('.group-composer__animal-head strong').filter({ hasText: 'Balu Abgabe' })).toBeVisible() await page.getByRole('button', { name: ta.ai.improve }).first().click() // Mock antwortet synchron; der generierte Text erscheint in der Vorschau @@ -43,7 +42,7 @@ test.describe('Abgabe', () => { skipUnlessMock() mockDb!.saleAdConfigured = false await gotoSection(page, de.nav.forSale) - await expect(page.getByText('Balu Abgabe')).toBeVisible() + await expect(page.locator('.group-composer__animal-head strong').filter({ hasText: 'Balu Abgabe' })).toBeVisible() await page.getByRole('button', { name: ta.ai.improve }).first().click() await expect(page.getByText(ta.ai.notConfigured)).toBeVisible() @@ -54,14 +53,14 @@ test.describe('Abgabe', () => { }) => { skipUnlessMock() await gotoSection(page, de.nav.forSale) - await expect(page.getByText('Balu Abgabe')).toBeVisible() + await expect(page.locator('.group-composer__animal-head strong').filter({ hasText: 'Balu Abgabe' })).toBeVisible() // Wizard öffnen (navigiert zu /vertraege/neu?tiere=sale-balu,sale-benny) await page.getByRole('button', { name: ta.export.finish }).first().click() await expect(page).toHaveURL(/\/vertraege\/neu\?tiere=/) await expect(page.getByRole('heading', { name: tw.title })).toBeVisible() // Schritt 1: Abnehmer auswählen - await expect(page.getByText(tw.pickContact)).toBeVisible() + await expect(page.getByRole('heading', { name: tw.pickContact })).toBeVisible() }) }) @@ -73,12 +72,12 @@ test.describe('Vertrag-Wizard', () => { await expect(page.getByRole('heading', { name: tw.title })).toBeVisible() // Schritt 1: Abnehmer wählen — Zoohandlung Meier aus dem Seed - await expect(page.getByText(tw.pickContact)).toBeVisible() + await expect(page.getByRole('heading', { name: tw.pickContact })).toBeVisible() await page.locator('.wizard-pick').filter({ hasText: 'Zoohandlung Meier' }).getByRole('radio').check() await page.getByRole('button', { name: tw.next }).click() // Schritt 2: Tiere — Vorauswahl aus ?tiere= ist aktiv - await expect(page.getByText(tw.pickAnimals)).toBeVisible() + await expect(page.getByRole('heading', { name: tw.pickAnimals })).toBeVisible() // Beide ForSale-Tiere sind vorausgewählt (Checkboxen angehakt) await expect( page.locator('.wizard-pick').filter({ hasText: 'Balu Abgabe' }).getByRole('checkbox') @@ -103,13 +102,14 @@ test.describe('Vertrag-Wizard', () => { await expect(page.getByRole('link', { name: tw.downloadDocx })).toBeVisible() }) - test('Schritt 1: fehlender Abnehmer zeigt Validierungsmeldung', async ({ page }) => { + test('Schritt 1: fehlender Abnehmer zeigt Validierungsfehler', async ({ page }) => { skipUnlessMock() await page.goto('/vertraege/neu?tiere=sale-balu') - await expect(page.getByText(tw.pickContact)).toBeVisible() - // Ohne Auswahl direkt auf Weiter klicken + await expect(page.getByRole('heading', { name: tw.pickContact })).toBeVisible() + // Ohne Auswahl direkt auf Weiter klicken → Fehler-Alert erscheint await page.getByRole('button', { name: tw.next }).click() - await expect(page.getByText(tw.pickContact, { exact: true })).toBeVisible() + // Alert enthält den Hinweis (stepError), Schritt bleibt auf 1 + await expect(page.locator('.alert--error').filter({ hasText: tw.pickContact })).toBeVisible() }) test('Schritt 3: ungültiger Preis zeigt Validierungsmeldung', async ({ page }) => { @@ -119,9 +119,11 @@ test.describe('Vertrag-Wizard', () => { await page.locator('.wizard-pick').filter({ hasText: 'Zoohandlung Meier' }).getByRole('radio').check() await page.getByRole('button', { name: tw.next }).click() // Schritt 2: Tiere bestätigen + await expect(page.getByRole('heading', { name: tw.pickAnimals })).toBeVisible() await page.getByRole('button', { name: tw.next }).click() // Schritt 3: leeres Preisfeld -> Fehler + await expect(page.getByLabel(tw.priceLabel)).toBeVisible() await page.getByRole('button', { name: tw.next }).click() - await expect(page.getByText(tw.priceInvalid)).toBeVisible() + await expect(page.locator('.alert--error').filter({ hasText: tw.priceInvalid })).toBeVisible() }) }) diff --git a/gerbil-manager-web/e2e/charakter.spec.ts b/gerbil-manager-web/e2e/charakter.spec.ts index 1cfdc50..65bcfc1 100644 --- a/gerbil-manager-web/e2e/charakter.spec.ts +++ b/gerbil-manager-web/e2e/charakter.spec.ts @@ -17,5 +17,10 @@ test('Charakterbogen: Eigenschaft umschalten, speichern und im Abgabe-Komposer w // Tier zur Abgabe stellen -> erscheint im /abgabe-Komposer mit gesetzter Eigenschaft. await page.getByRole('button', { name: de.pages.abgabe.markAction }).click() await page.goto('/abgabe') - await expect(page.getByRole('checkbox', { name: 'neugierig' })).toBeChecked() + // Auf Krümels Tier-Abschnitt eingrenzen — andere ForSale-Tiere haben ebenfalls + // Charakterbögen, deshalb darf die Assertion nicht seitenbreit nach 'neugierig' suchen. + const kruemelSection = page.locator('.group-composer__animal').filter({ + has: page.locator('strong', { hasText: 'Krümel' }), + }) + await expect(kruemelSection.getByRole('checkbox', { name: 'neugierig' })).toBeChecked() }) diff --git a/gerbil-manager-web/e2e/mock-data.ts b/gerbil-manager-web/e2e/mock-data.ts index a3bd834..efdfec4 100644 --- a/gerbil-manager-web/e2e/mock-data.ts +++ b/gerbil-manager-web/e2e/mock-data.ts @@ -135,17 +135,18 @@ export function seedDb(): MockDb { { ...gerbil('willi', 'Willi', 'male', '2019-09-09', null, 'cv-schwarz'), status: 'Deceased', dateOfDeath: '2022-04-04' }, { ...gerbil('rosa', 'Rosa', 'female', '2020-02-02', null, 'cv-gold'), status: 'Deceased', dateOfDeath: '2023-08-15' }, { ...gerbil('pauli', 'Pauli', 'male', '2023-05-01', null, 'cv-himalaya'), status: 'GivenAway', goHomeDate: '2023-07-15', receiverContactId: 'con-huber' }, - // ABGABE: zwei Tiere zur Abgabe im Großbecken (Gruppe 1 für den Abgabe-Wizard-Test) + // ABGABE: zwei Tiere zur Abgabe im Quarantänebecken (enc-leer ist leer, kein Konflikt + // mit dem Becken-Belegungstest der Großbecken-2-Tiere-Assertion). { ...gerbil('sale-balu', 'Balu Abgabe', 'male', '2024-03-12', null, 'cv-agouti'), status: 'ForSale' as const, - enclosureId: 'enc-gross', + enclosureId: 'enc-leer', notes: 'ruhig, nimmt Leckerlis aus der Hand', }, { ...gerbil('sale-benny', 'Benny Abgabe', 'male', '2024-03-12', null, 'cv-schwarz-schecke'), status: 'ForSale' as const, - enclosureId: 'enc-gross', + enclosureId: 'enc-leer', notes: 'neugieriger Entdecker', }, ]