// @ts-check const { test, expect } = require('@playwright/test') const BENUTZER = process.env.E2E_USER || 'e2e' const PASSWORT = process.env.E2E_PASSWORD || 'e2e-testpasswort' // Eindeutige Namen je Lauf: die Tests arbeiten auf einer bestehenden Instanz // und dürfen sich nicht an Resten eines früheren Laufs stoßen. const MARKE = Date.now().toString().slice(-6) // Ein Jahr weit in der Zukunft: dort sind alle zwölf Monate Folgemonate, die // Spaltenaufteilung des Planers bleibt damit über die Jahre stabil. const JAHR = new Date().getFullYear() + 5 async function anmelden(page) { await page.goto('/login') if (page.url().includes('/einrichtung')) { throw new Error( 'Instanz ist noch nicht eingerichtet. Zuerst einen Benutzer anlegen: ' + 'docker compose exec -u www-data php php scripts/e2e-benutzer.php' ) } await page.fill('#benutzername', BENUTZER) await page.fill('#passwort', PASSWORT) await page.click('button[type="submit"]') await expect(page).toHaveURL(/\/$/) } /** * Legt ein Budget an und liefert dessen Id. Nach dem Anlegen steht sie in der * URL des Planers – die Auswahlliste enthält alle Budgets der Instanz und * taugt deshalb nicht zum Wiederfinden. */ async function budgetAnlegen(page, name) { await page.goto('/planung/budget/verwaltung') await page.fill('#name', name) await page.fill('#jahr', String(JAHR)) await page.click('.formular button:has-text("Budget anlegen")') await expect(page.locator('.meldung-erfolg')).toBeVisible() await expect(page).toHaveURL(/budget=\d+/) return new URL(page.url()).searchParams.get('budget') } /** Die erste Kategoriezeile mit Eingabefeldern – eine Blattkategorie. */ function ersteBeplanbareZeile(page) { return page.locator('tr.kategoriezeile:not(.summenzeile-kategorie)').first() } test.describe('Planung', () => { test.beforeEach(async ({ page }) => { await anmelden(page) }) test('Planungsübersicht führt zu Budget und Monatsabschluss', async ({ page }) => { await page.click('.seitenleiste a[href="/planung"]') await expect(page.locator('h1')).toContainText('Planung') await expect(page.locator('a[href="/planung/budget"]').first()).toBeVisible() await expect(page.locator('a[href="/planung/monatsabschluss"]').first()).toBeVisible() }) test('Budget anlegen, Monatswert eintragen und wiederfinden', async ({ page }) => { const id = await budgetAnlegen(page, `E2E-Budget ${MARKE}`) await page.goto(`/planung/budget?budget=${id}&ansicht=alle`) const zeile = ersteBeplanbareZeile(page) const kategorie = (await zeile.locator('.baumname').innerText()).trim() await zeile.locator('input.betragsfeld').first().fill('250,00') await page.click('button:has-text("Budget speichern")') await expect(page.locator('.meldung-erfolg')).toContainText('Budget gespeichert') // Nach dem Speichern steht der Wert wieder im Feld – und in der Jahressumme. const wieder = page.locator('tr.kategoriezeile', { hasText: kategorie }).first() await expect(wieder.locator('input.betragsfeld').first()).toHaveValue('250,00') await expect(wieder).toContainText('250,00') }) test('Wert auf die Folgemonate übertragen', async ({ page }) => { const id = await budgetAnlegen(page, `E2E-Folgemonate ${MARKE}`) await page.goto(`/planung/budget?budget=${id}&ansicht=alle`) const zeile = ersteBeplanbareZeile(page) const kategorie = (await zeile.locator('.baumname').innerText()).trim() await zeile.locator('input.betragsfeld').first().fill('100,00') await zeile.locator('button[name="uebertragen"]').click() await expect(page.locator('.meldung-erfolg')).toContainText('Folgemonate') const wieder = page.locator('tr.kategoriezeile', { hasText: kategorie }).first() const felder = wieder.locator('input.betragsfeld') await expect(felder.nth(0)).toHaveValue('100,00') await expect(felder.nth(11)).toHaveValue('100,00') // Zwölf Monate à 100,00 stehen als Jahressumme in der Zeile. await expect(wieder).toContainText('1.200,00') }) test('Monat abschließen, Snapshot ansehen und wiedereröffnen', async ({ page }) => { // Ein Monat weit in der Vergangenheit, den kein anderer Test anfasst. const jahr = new Date().getFullYear() - 9 // Rückfragen bejahen: Wiedereröffnen und Abschließen fragen beide nach. page.on('dialog', d => d.accept()) await page.goto(`/planung/monatsabschluss?jahr=${jahr}&monat=6`) await expect(page.locator('h2').first()).toContainText('Prüflauf') // Ein früherer Lauf kann den Monat abgeschlossen zurückgelassen haben. if (await page.locator('button:has-text("Monat wiedereröffnen")').count()) { await page.click('button:has-text("Monat wiedereröffnen")') await expect(page.locator('button:has-text("Monat abschließen")')).toBeVisible() } await page.fill('#notiz', `E2E ${MARKE}`) await page.click('button:has-text("Monat abschließen")') await expect(page.locator('.meldung-erfolg')).toContainText('abgeschlossen') // Der abgeschlossene Monat weist die Sperre aus und bietet den Snapshot an. await expect(page.locator('.phasenmarke')).toContainText('abgeschlossen') await page.click('a:has-text("Snapshot ansehen")') await expect(page.locator('h1')).toContainText('Abschluss') await expect(page.locator('.summenzeile')).toContainText('Summe Kontostände') await page.goto(`/planung/monatsabschluss?jahr=${jahr}&monat=6`) await page.click('button:has-text("Monat wiedereröffnen")') await expect(page.locator('.meldung-erfolg')).toContainText('wieder offen') await expect(page.locator('button:has-text("Monat abschließen")')).toBeVisible() }) })