QA-2: Fix Abgabe-e2e Selektoren + ForSale in enc-leer (no Becken-Konflikt) + charakter scoped
This commit is contained in:
@@ -2,37 +2,36 @@
|
|||||||
* QA-2: Abgabe-Wizard (FEAT-12a + FEAT-13) — Abgabetiere gruppieren,
|
* QA-2: Abgabe-Wizard (FEAT-12a + FEAT-13) — Abgabetiere gruppieren,
|
||||||
* KI-Inserat generieren, und Vertrag-Handoff via ?tiere= Query-Parameter.
|
* 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 ta = de.pages.abgabe
|
||||||
const tw = de.pages.vertraege.wizard
|
const tw = de.pages.vertraege.wizard
|
||||||
const tk = de.pages.kontakte
|
|
||||||
|
|
||||||
test.describe('Abgabe', () => {
|
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()
|
skipUnlessMock()
|
||||||
await gotoSection(page, de.nav.forSale)
|
await gotoSection(page, de.nav.forSale)
|
||||||
await expect(page.getByRole('heading', { name: ta.title, exact: true })).toBeVisible()
|
await expect(page.getByRole('heading', { name: ta.title, exact: true })).toBeVisible()
|
||||||
await expect(page.getByText(ta.grouping.title)).toBeVisible()
|
await expect(page.getByText(ta.grouping.title)).toBeVisible()
|
||||||
|
|
||||||
// Die beiden ForSale-Tiere müssen sichtbar sein
|
// Die beiden ForSale-Tiere müssen als Tiername (strong-Element im Komposer) sichtbar sein
|
||||||
await expect(page.getByText('Balu Abgabe')).toBeVisible()
|
await expect(page.locator('.group-composer__animal-head strong').filter({ hasText: 'Balu Abgabe' })).toBeVisible()
|
||||||
await expect(page.getByText('Benny Abgabe')).toBeVisible()
|
await expect(page.locator('.group-composer__animal-head strong').filter({ hasText: 'Benny Abgabe' })).toBeVisible()
|
||||||
|
|
||||||
// Inserat-Vorschau (listing-preview) wird gerendert
|
// Inserat-Vorschau (listing-preview) wird gerendert
|
||||||
await expect(page.locator('.listing-preview').first()).toBeVisible()
|
await expect(page.locator('.listing-preview').first()).toBeVisible()
|
||||||
// Status-Dropdown standard: FREI
|
// Status-Dropdown standard: FREI
|
||||||
await expect(
|
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')
|
).toHaveValue('free')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('KI-Inserat: "Text mit KI verbessern" — Mock liefert Inserat-Text', async ({ page }) => {
|
test('KI-Inserat: "Text mit KI verbessern" — Mock liefert Inserat-Text', async ({ page }) => {
|
||||||
skipUnlessMock()
|
skipUnlessMock()
|
||||||
await gotoSection(page, de.nav.forSale)
|
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 page.getByRole('button', { name: ta.ai.improve }).first().click()
|
||||||
// Mock antwortet synchron; der generierte Text erscheint in der Vorschau
|
// Mock antwortet synchron; der generierte Text erscheint in der Vorschau
|
||||||
@@ -43,7 +42,7 @@ test.describe('Abgabe', () => {
|
|||||||
skipUnlessMock()
|
skipUnlessMock()
|
||||||
mockDb!.saleAdConfigured = false
|
mockDb!.saleAdConfigured = false
|
||||||
await gotoSection(page, de.nav.forSale)
|
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 page.getByRole('button', { name: ta.ai.improve }).first().click()
|
||||||
await expect(page.getByText(ta.ai.notConfigured)).toBeVisible()
|
await expect(page.getByText(ta.ai.notConfigured)).toBeVisible()
|
||||||
@@ -54,14 +53,14 @@ test.describe('Abgabe', () => {
|
|||||||
}) => {
|
}) => {
|
||||||
skipUnlessMock()
|
skipUnlessMock()
|
||||||
await gotoSection(page, de.nav.forSale)
|
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)
|
// Wizard öffnen (navigiert zu /vertraege/neu?tiere=sale-balu,sale-benny)
|
||||||
await page.getByRole('button', { name: ta.export.finish }).first().click()
|
await page.getByRole('button', { name: ta.export.finish }).first().click()
|
||||||
await expect(page).toHaveURL(/\/vertraege\/neu\?tiere=/)
|
await expect(page).toHaveURL(/\/vertraege\/neu\?tiere=/)
|
||||||
await expect(page.getByRole('heading', { name: tw.title })).toBeVisible()
|
await expect(page.getByRole('heading', { name: tw.title })).toBeVisible()
|
||||||
// Schritt 1: Abnehmer auswählen
|
// 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()
|
await expect(page.getByRole('heading', { name: tw.title })).toBeVisible()
|
||||||
|
|
||||||
// Schritt 1: Abnehmer wählen — Zoohandlung Meier aus dem Seed
|
// 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.locator('.wizard-pick').filter({ hasText: 'Zoohandlung Meier' }).getByRole('radio').check()
|
||||||
await page.getByRole('button', { name: tw.next }).click()
|
await page.getByRole('button', { name: tw.next }).click()
|
||||||
|
|
||||||
// Schritt 2: Tiere — Vorauswahl aus ?tiere= ist aktiv
|
// 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)
|
// Beide ForSale-Tiere sind vorausgewählt (Checkboxen angehakt)
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.wizard-pick').filter({ hasText: 'Balu Abgabe' }).getByRole('checkbox')
|
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()
|
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()
|
skipUnlessMock()
|
||||||
await page.goto('/vertraege/neu?tiere=sale-balu')
|
await page.goto('/vertraege/neu?tiere=sale-balu')
|
||||||
await expect(page.getByText(tw.pickContact)).toBeVisible()
|
await expect(page.getByRole('heading', { name: tw.pickContact })).toBeVisible()
|
||||||
// Ohne Auswahl direkt auf Weiter klicken
|
// Ohne Auswahl direkt auf Weiter klicken → Fehler-Alert erscheint
|
||||||
await page.getByRole('button', { name: tw.next }).click()
|
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 }) => {
|
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.locator('.wizard-pick').filter({ hasText: 'Zoohandlung Meier' }).getByRole('radio').check()
|
||||||
await page.getByRole('button', { name: tw.next }).click()
|
await page.getByRole('button', { name: tw.next }).click()
|
||||||
// Schritt 2: Tiere bestätigen
|
// Schritt 2: Tiere bestätigen
|
||||||
|
await expect(page.getByRole('heading', { name: tw.pickAnimals })).toBeVisible()
|
||||||
await page.getByRole('button', { name: tw.next }).click()
|
await page.getByRole('button', { name: tw.next }).click()
|
||||||
// Schritt 3: leeres Preisfeld -> Fehler
|
// Schritt 3: leeres Preisfeld -> Fehler
|
||||||
|
await expect(page.getByLabel(tw.priceLabel)).toBeVisible()
|
||||||
await page.getByRole('button', { name: tw.next }).click()
|
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()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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.
|
// Tier zur Abgabe stellen -> erscheint im /abgabe-Komposer mit gesetzter Eigenschaft.
|
||||||
await page.getByRole('button', { name: de.pages.abgabe.markAction }).click()
|
await page.getByRole('button', { name: de.pages.abgabe.markAction }).click()
|
||||||
await page.goto('/abgabe')
|
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()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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('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('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' },
|
{ ...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'),
|
...gerbil('sale-balu', 'Balu Abgabe', 'male', '2024-03-12', null, 'cv-agouti'),
|
||||||
status: 'ForSale' as const,
|
status: 'ForSale' as const,
|
||||||
enclosureId: 'enc-gross',
|
enclosureId: 'enc-leer',
|
||||||
notes: 'ruhig, nimmt Leckerlis aus der Hand',
|
notes: 'ruhig, nimmt Leckerlis aus der Hand',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...gerbil('sale-benny', 'Benny Abgabe', 'male', '2024-03-12', null, 'cv-schwarz-schecke'),
|
...gerbil('sale-benny', 'Benny Abgabe', 'male', '2024-03-12', null, 'cv-schwarz-schecke'),
|
||||||
status: 'ForSale' as const,
|
status: 'ForSale' as const,
|
||||||
enclosureId: 'enc-gross',
|
enclosureId: 'enc-leer',
|
||||||
notes: 'neugieriger Entdecker',
|
notes: 'neugieriger Entdecker',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user