130 lines
6.3 KiB
TypeScript
130 lines
6.3 KiB
TypeScript
/**
|
|
* 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 Quarantänebecken) → skipUnlessMock.
|
|
*/
|
|
import { de, expect, gotoSection, skipUnlessMock, test } from './fixtures'
|
|
|
|
const ta = de.pages.abgabe
|
|
const tw = de.pages.vertraege.wizard
|
|
|
|
test.describe('Abgabe', () => {
|
|
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 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({ 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.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
|
|
await expect(page.locator('.listing-preview').first()).toContainText('Generierter Inserat-Text')
|
|
})
|
|
|
|
test('KI-Inserat: 503 zeigt deutschen Hinweis (saleAdConfigured=false)', async ({ page, mockDb }) => {
|
|
skipUnlessMock()
|
|
mockDb!.saleAdConfigured = false
|
|
await gotoSection(page, de.nav.forSale)
|
|
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()
|
|
})
|
|
|
|
test('Vertrag-Handoff: "Abgabe abschließen" öffnet Wizard mit vorausgewählten Tieren', async ({
|
|
page,
|
|
}) => {
|
|
skipUnlessMock()
|
|
await gotoSection(page, de.nav.forSale)
|
|
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.getByRole('heading', { name: tw.pickContact })).toBeVisible()
|
|
})
|
|
})
|
|
|
|
test.describe('Vertrag-Wizard', () => {
|
|
test('4-Schritte-Wizard: Abnehmer → Tiere → Preis → Vertrag erzeugen', async ({ page }) => {
|
|
skipUnlessMock()
|
|
// Direkt mit vorausgewählten Tieren öffnen (wie über Abgabe-Seite)
|
|
await page.goto('/vertraege/neu?tiere=sale-balu,sale-benny')
|
|
await expect(page.getByRole('heading', { name: tw.title })).toBeVisible()
|
|
|
|
// Schritt 1: Abnehmer wählen — Zoohandlung Meier aus dem Seed
|
|
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.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')
|
|
).toBeChecked()
|
|
await expect(
|
|
page.locator('.wizard-pick').filter({ hasText: 'Benny Abgabe' }).getByRole('checkbox')
|
|
).toBeChecked()
|
|
await page.getByRole('button', { name: tw.next }).click()
|
|
|
|
// Schritt 3: Preis & Datum
|
|
await page.getByLabel(tw.priceLabel).fill('50,00')
|
|
await page.getByRole('button', { name: tw.next }).click()
|
|
|
|
// Schritt 4: Zusammenfassung + Erzeugen
|
|
await expect(page.getByText(tw.summaryTitle)).toBeVisible()
|
|
await expect(page.getByText('Zoohandlung Meier')).toBeVisible()
|
|
await expect(page.getByText('Balu Abgabe')).toBeVisible()
|
|
await page.getByRole('button', { name: tw.generate }).click()
|
|
|
|
// Erfolg: Vertrag erstellt, Download-Link vorhanden
|
|
await expect(page.getByRole('heading', { name: tw.successTitle })).toBeVisible()
|
|
await expect(page.getByRole('link', { name: tw.downloadDocx })).toBeVisible()
|
|
})
|
|
|
|
test('Schritt 1: fehlender Abnehmer zeigt Validierungsfehler', async ({ page }) => {
|
|
skipUnlessMock()
|
|
await page.goto('/vertraege/neu?tiere=sale-balu')
|
|
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()
|
|
// 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 }) => {
|
|
skipUnlessMock()
|
|
await page.goto('/vertraege/neu?tiere=sale-balu')
|
|
// Schritt 1: Abnehmer wählen
|
|
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.locator('.alert--error').filter({ hasText: tw.priceInvalid })).toBeVisible()
|
|
})
|
|
})
|