Toggle „Regel anlegen“ in der Buchungsmaske (Fix #94); beim Speichern entsteht daraus eine Regel (AbgleichRegel::ausBuchung()), die das Kontoblatt danach in einem modalen Dialog zum Prüfen und Anpassen zeigt. Abbruch (auch per Escape) verwirft die Regel wieder, Speichern übernimmt Änderungen. Die Regelfelder sind aus regeln.php in regelfelder.php ausgelagert, damit beide Formulare dieselbe Bauart teilen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
138 lines
5.4 KiB
JavaScript
138 lines
5.4 KiB
JavaScript
// @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)
|
||
})
|
||
})
|