// @ts-check const { test, expect } = require('@playwright/test') const BENUTZER = process.env.E2E_USER || 'e2e' const PASSWORT = process.env.E2E_PASSWORD || 'e2e-testpasswort' const MARKE = Date.now().toString().slice(-6) const GIRO = `E2E RegelBuchung ${MARKE}` const KATEGORIE = `E2E RegelBuchung Kategorie ${MARKE}` async function anmelden(page) { await page.goto('/login') await page.fill('#benutzername', BENUTZER) await page.fill('#passwort', PASSWORT) await page.click('button[type="submit"]') await expect(page).toHaveURL(/\/$/) } // Fix #94: Aus der Buchungsmaske heraus lässt sich mit dem Toggle // „Regel anlegen“ direkt eine Regel aus der gerade gespeicherten Buchung // erzeugen; ein Dialog zeigt sie danach zum Prüfen. test.describe('Regel aus einer Buchung anlegen', () => { let giroId = null test.beforeAll(async ({ browser }) => { const page = await browser.newPage() await anmelden(page) await page.goto('/konten/neu') await page.fill('#name', GIRO) await page.fill('#anfangssaldo', '1.000,00') await page.click('.formular button[type="submit"]') await expect(page).toHaveURL(/\/konten\/\d+\/bearbeiten/) giroId = page.url().match(/\/konten\/(\d+)\//)[1] await page.goto('/verwaltung/kategorien/neu') await page.fill('#name', KATEGORIE) await page.selectOption('#art', 'ausgabe') await page.click('.formular button[type="submit"]') await page.close() }) test.beforeEach(async ({ page }) => { await anmelden(page) }) test('Toggle ist standardmäßig aus – ohne ihn ändert sich nichts am bisherigen Ablauf', async ({ page }) => { await page.goto(`/konten/${giroId}/buchung`) await expect(page.locator('input[name="regel_anlegen"]')).not.toBeChecked() await page.fill('#datum', '2026-05-01') await page.fill('#betrag', '12,00') await page.fill('#empfaenger', `Ohne Regel ${MARKE}`) await page.click('.buchungsmaske button[type="submit"]') await expect(page.locator('.meldung-erfolg')).toBeVisible() await expect(page.locator('#regeldialog')).toHaveCount(0) }) test('Regel anlegen öffnet den Dialog mit den Buchungsdaten; Abbruch verwirft die Regel wieder', async ({ page }) => { const empfaenger = `Abbruchregel ${MARKE}` await page.goto(`/konten/${giroId}/buchung`) await page.fill('#datum', '2026-05-02') await page.fill('#betrag', '20,00') await page.fill('#empfaenger', empfaenger) await page.selectOption('#zuordnung', { label: KATEGORIE }) await page.check('input[name="regel_anlegen"]') await page.click('.buchungsmaske button[type="submit"]') await expect(page.locator('.meldung-erfolg')).toBeVisible() const dialog = page.locator('#regeldialog') await expect(dialog).toBeVisible() await expect(dialog.locator('input[name="name"]')).toHaveValue(empfaenger) await expect(dialog.locator('input[name="muster"]')).toHaveValue(empfaenger) await expect(dialog.locator('select[name="kategorie_id"]')).toHaveValue(/^\d+$/) await dialog.getByRole('button', { name: 'Abbruch' }).click() await expect(page).toHaveURL(new RegExp(`/konten/${giroId}$`)) await expect(page.locator('#regeldialog')).toHaveCount(0) // Es darf keine neu angelegte Regel zurückbleiben. Der Name steht im // Wert eines Eingabefelds, nicht im Text der Zeile – toContainText // träfe ihn also gar nicht erst. await page.goto('/banking/regeln') await expect(page.locator(`input[name="name"][value="${empfaenger}"]`)).toHaveCount(0) }) test('Speichern im Dialog übernimmt Änderungen und behält die Regel', async ({ page }) => { const empfaenger = `Speicherregel ${MARKE}` const angepasstesMuster = `Speicherregel ${MARKE} angepasst` await page.goto(`/konten/${giroId}/buchung`) await page.fill('#datum', '2026-05-03') await page.fill('#betrag', '30,00') await page.fill('#empfaenger', empfaenger) await page.selectOption('#zuordnung', { label: KATEGORIE }) await page.check('input[name="regel_anlegen"]') await page.click('.buchungsmaske button[type="submit"]') const dialog = page.locator('#regeldialog') await expect(dialog).toBeVisible() await dialog.locator('input[name="muster"]').fill(angepasstesMuster) await dialog.getByRole('button', { name: 'Speichern' }).click() await expect(page).toHaveURL(new RegExp(`/konten/${giroId}$`)) await expect(page.locator('#regeldialog')).toHaveCount(0) // Der Name blieb unverändert; über ihn findet sich die Zeile wieder – // das Muster steckt wie der Name im Wert eines Eingabefelds. await page.goto('/banking/regeln') const zeile = page.locator('tr').filter({ has: page.locator(`input[name="name"][value="${empfaenger}"]`) }) await expect(zeile).toBeVisible() await expect(zeile.locator('input[name="muster"]')).toHaveValue(angepasstesMuster) }) test('Escape im Dialog verwirft die Regel wie ein Klick auf Abbruch', async ({ page }) => { const empfaenger = `Escaperegel ${MARKE}` await page.goto(`/konten/${giroId}/buchung`) await page.fill('#datum', '2026-05-04') await page.fill('#betrag', '40,00') await page.fill('#empfaenger', empfaenger) await page.check('input[name="regel_anlegen"]') await page.click('.buchungsmaske button[type="submit"]') await expect(page.locator('#regeldialog')).toBeVisible() await page.keyboard.press('Escape') await expect(page).toHaveURL(new RegExp(`/konten/${giroId}$`)) await page.goto('/banking/regeln') await expect(page.locator(`input[name="name"][value="${empfaenger}"]`)).toHaveCount(0) }) })