Elf Listenansichten (Klassen, Buchungsvorlagen, Regelmäßige Buchungen, Erinnerungen, Verträge, Adressen, Sparziele, Kredite, Abgleichregeln, Budgets, Berichtsgruppen) zeigten das Formular unter der Liste. Jetzt öffnet der Knopf „+ Neu“ es als Dialog. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
170 lines
7.2 KiB
JavaScript
170 lines
7.2 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'
|
||
|
||
// 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 gibt es keine Buchungen, die Ist-Werte
|
||
// bleiben leer und die geprüften Summen 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.click('#neu-knopf')
|
||
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}`)
|
||
|
||
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('Die drei Ansichten zeigen Budget, Ist und Saldo je Monat', async ({ page }) => {
|
||
const id = await budgetAnlegen(page, `E2E-Ansichten ${MARKE}`)
|
||
|
||
// Alles: zwölf Monate à drei Wertspalten, dazu die Jahresspalten.
|
||
await page.goto(`/planung/budget?budget=${id}`)
|
||
const zeile = ersteBeplanbareZeile(page)
|
||
await expect(zeile.locator('td')).toHaveCount(1 + 3 + 12 * 3)
|
||
await expect(zeile.locator('input.betragsfeld')).toHaveCount(12)
|
||
// Kein Monat ist zusammengefasst: Januar steht als eigene Spalte da.
|
||
await expect(page.locator('th.gruppenkopf', { hasText: 'Jan' })).toHaveCount(1)
|
||
|
||
await page.click('a:has-text("Nur Budget")')
|
||
await expect(ersteBeplanbareZeile(page).locator('td')).toHaveCount(1 + 1 + 12)
|
||
await expect(ersteBeplanbareZeile(page).locator('input.betragsfeld')).toHaveCount(12)
|
||
|
||
// Nur IST ist eine reine Leseansicht – ohne Eingabefelder und ohne Speichern.
|
||
await page.click('a:has-text("Nur IST")')
|
||
await expect(ersteBeplanbareZeile(page).locator('td')).toHaveCount(1 + 1 + 12)
|
||
await expect(page.locator('input.betragsfeld')).toHaveCount(0)
|
||
await expect(page.locator('button:has-text("Budget speichern")')).toHaveCount(0)
|
||
})
|
||
|
||
test('Zahnrad überträgt den Wert auf das ganze und das restliche Jahr', async ({ page }) => {
|
||
const id = await budgetAnlegen(page, `E2E-Zahnrad ${MARKE}`)
|
||
|
||
await page.goto(`/planung/budget?budget=${id}&ansicht=budget`)
|
||
|
||
const zeile = ersteBeplanbareZeile(page)
|
||
const kategorie = (await zeile.locator('.baumname').innerText()).trim()
|
||
const felder = zeile.locator('input.betragsfeld')
|
||
|
||
// Ganzes Jahr: der Wert aus dem März steht danach auch im Januar.
|
||
await felder.nth(2).fill('100,00')
|
||
await zeile.locator('.zahnrad').nth(2).click()
|
||
await page.click('.zahnradmenue button:has-text("Ganzes Jahr")')
|
||
await expect(felder.nth(0)).toHaveValue('100,00')
|
||
await expect(felder.nth(11)).toHaveValue('100,00')
|
||
|
||
// Restliches Jahr: die Monate davor bleiben stehen.
|
||
await felder.nth(5).fill('40,00')
|
||
await zeile.locator('.zahnrad').nth(5).click()
|
||
await page.click('.zahnradmenue button:has-text("Restliches Jahr")')
|
||
await expect(felder.nth(4)).toHaveValue('100,00')
|
||
await expect(felder.nth(6)).toHaveValue('40,00')
|
||
await expect(felder.nth(11)).toHaveValue('40,00')
|
||
|
||
// Erst das Speichern schreibt die verteilten Werte weg.
|
||
await page.click('button:has-text("Budget speichern")')
|
||
await expect(page.locator('.meldung-erfolg')).toContainText('Budget gespeichert')
|
||
|
||
const wieder = page.locator('tr.kategoriezeile', { hasText: kategorie }).first()
|
||
// Fünf Monate à 100,00 und sieben à 40,00 ergeben 780,00 im Jahr.
|
||
await expect(wieder).toContainText('780,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()
|
||
})
|
||
})
|