/** * INBOX-1: Anfragen-Posteingang — Liste/Filter, Triage, KI-Entwurf (inkl. * AiKeyMissing-Hinweis), Senden (inkl. MailNotConfigured-Hinweis). * Mock-gebunden (Seed-Anfragen + Fehlerpfad-Flags) → skipUnlessMock. */ import { acceptNextDialog, de, expect, gotoSection, openFilterPanel, skipUnlessMock, test } from './fixtures' const ta = de.pages.anfragen const td = ta.detail test.describe('Anfragen', () => { test('Liste zeigt Anfragen neueste zuerst + Status-Filter', async ({ page }) => { skipUnlessMock() await gotoSection(page, de.nav.requests) await expect(page.getByRole('heading', { name: ta.title })).toBeVisible() // Neueste zuerst: Anna (05.06.) vor Ben (04.06.) vor Clara (01.06.) const cards = page.locator('.anfrage-card') await expect(cards).toHaveCount(3) await expect(cards.nth(0)).toContainText('Anna Albrecht') await expect(cards.nth(2)).toContainText('clara@example.com') // ohne Anzeigename → Adresse // Status-Badge auf der Karte await expect(cards.nth(0)).toContainText(ta.statusLabels.New) // UX-MOBILE-1: Status-Select liegt im Filter-Drawer — auf Mobil erst öffnen. await openFilterPanel(page) // Filter: nur Beantwortet await page.getByLabel(td.statusLabel).selectOption('Answered') await expect(cards).toHaveCount(1) await expect(cards.first()).toContainText('Danke!') }) test('Sync ohne Gmail-Konfiguration zeigt deutschen Hinweis', async ({ page, mockDb }) => { skipUnlessMock() mockDb!.mailConfigured = false await page.goto('/anfragen') await page.getByRole('button', { name: ta.sync }).click() await expect(page.getByText(ta.mailNotConfigured)).toBeVisible() }) test('Detail: Triage — Abnehmer zuordnen setzt Status auf Zugeordnet', async ({ page, mockDb }) => { skipUnlessMock() await page.goto('/anfragen/req-anna') await expect(page.getByRole('heading', { name: 'Anfrage: Pärchen zur Abgabe?' })).toBeVisible() await expect(page.getByText('anna@example.de', { exact: false })).toBeVisible() await page.getByLabel(td.assignContact).selectOption({ label: 'Zoohandlung Meier' }) await expect(page.locator('.anfrage-badge--assigned')).toBeVisible() expect(mockDb!.requests.find((r) => r.id === 'req-anna')!.assignedContactId).toBe('con-meier') // Verwerfen (mit Bestätigung) → Status Verworfen, Zuordnung bleibt acceptNextDialog(page) await page.getByRole('button', { name: td.abandon }).click() await expect(page.locator('.anfrage-badge--abandoned')).toBeVisible() expect(mockDb!.requests.find((r) => r.id === 'req-anna')!.assignedContactId).toBe('con-meier') }) test('KI-Entwurf füllt das Antwortfeld; Senden markiert als Beantwortet', async ({ page }) => { skipUnlessMock() await page.goto('/anfragen/req-anna') await page.getByRole('button', { name: td.draftButton }).click() const textarea = page.locator('.anfrage-reply__text') await expect(textarea).toHaveValue(/vielen Dank für deine Anfrage/) // Entwurf bearbeiten, dann senden (bestätigt) → Beantwortet + Hinweis await textarea.fill('Hallo Anna, ja — die beiden suchen noch ein Zuhause!') acceptNextDialog(page) await page.getByRole('button', { name: td.send }).click() await expect(page.getByText(td.sent)).toBeVisible() await expect(page.locator('.anfrage-badge--answered')).toBeVisible() }) test('KI ohne Schlüssel: 503 wird zum freundlichen Hinweis', async ({ page, mockDb }) => { skipUnlessMock() mockDb!.aiConfigured = false await page.goto('/anfragen/req-anna') await page.getByRole('button', { name: td.draftButton }).click() await expect(page.getByText(td.aiKeyMissing)).toBeVisible() }) test('Senden ohne Text zeigt Hinweis statt Versand', async ({ page }) => { skipUnlessMock() await page.goto('/anfragen/req-anna') await page.getByRole('button', { name: td.send }).click() await expect(page.getByText(td.sendEmptyBody)).toBeVisible() }) })