// @ts-check const { test, expect } = require('@playwright/test') const BENUTZER = process.env.E2E_USER || 'e2e' const PASSWORT = process.env.E2E_PASSWORD || 'e2e-testpasswort' /** * Meldet sich an. Die Anwendung leitet nicht angemeldete Aufrufe auf /login um; * bei einer frischen Installation stattdessen auf /einrichtung. */ 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(/\/$/) } test.describe('Grundgerüst', () => { test('Anmeldeseite ist erreichbar', async ({ page }) => { await page.goto('/login') await expect(page.locator('h1, .marke')).toContainText(/Finanzmanager|Anmeldung/) await expect(page.locator('#benutzername')).toBeVisible() }) test('Ohne Anmeldung führt jeder Weg zur Anmeldung', async ({ page }) => { await page.goto('/einstellungen') await expect(page).toHaveURL(/\/(login|einrichtung)/) }) test('Falsches Passwort wird abgewiesen', async ({ page }) => { await page.goto('/login') test.skip(page.url().includes('/einrichtung'), 'Instanz noch nicht eingerichtet') await page.fill('#benutzername', BENUTZER) await page.fill('#passwort', 'ganz sicher falsch') await page.click('button[type="submit"]') await expect(page.locator('.meldung-fehler')).toBeVisible() await expect(page).toHaveURL(/\/login/) }) test('Anmeldung führt ins Cockpit', async ({ page }) => { await anmelden(page) await expect(page.locator('h1')).toContainText('Cockpit') await expect(page.locator('.seitenleiste')).toContainText('Kontenübersicht') }) test('Vermögensentwicklung zeigt zwölf gestapelte Monatsbalken', async ({ page }) => { await anmelden(page) const kachel = page.locator('.kachel', { hasText: 'Vermögensentwicklung' }) await expect(kachel.locator('svg.diagramm')).toBeVisible() // Zwölf Monate, jeder mit eigener Beschriftung unter dem Balken. await expect(kachel.locator('.diagramm-beschriftung:not(.schwach)')).toHaveCount(12) await expect(kachel.locator('.diagramm rect').first()).toBeVisible() // Jedes Balkenstück gehört zu einem Eintrag der Legende, keiner doppelt. const farben = await kachel.locator('.legendenfarbe:not(.leer)').evaluateAll( knoten => knoten.map(k => getComputedStyle(k).backgroundColor) ) expect(farben.length).toBeGreaterThan(0) expect(new Set(farben).size).toBe(farben.length) }) test('Schalter „nur aktive“ behält seinen Zustand', async ({ page }) => { await anmelden(page) const schalter = page.locator('.kachel', { hasText: 'Vermögensentwicklung' }) .locator('.schalter') await expect(schalter).toContainText('nur aktive') // Ein früherer Lauf kann den Schalter umgelegt haben. if (await schalter.getAttribute('aria-checked') === 'false') { await schalter.click() } await expect(schalter).toHaveAttribute('aria-checked', 'true') await schalter.click() await expect(schalter).toHaveAttribute('aria-checked', 'false') // Gespeichert, nicht nur angezeigt: Der Zustand überlebt den Neuaufruf. await page.goto('/') await expect(schalter).toHaveAttribute('aria-checked', 'false') await schalter.click() await expect(schalter).toHaveAttribute('aria-checked', 'true') }) test('Einstellungsdialog zeigt alle Reiter', async ({ page }) => { await anmelden(page) await page.click('a[href="/einstellungen"]') await expect(page.locator('h1')).toContainText('Einstellungen') for (const reiter of ['Allgemein', 'Darstellung', 'Buchhaltung', 'Diagnose']) { await expect(page.locator('.tableiste')).toContainText(reiter) } }) test('Einstellung lässt sich speichern', async ({ page }) => { await anmelden(page) await page.goto('/einstellungen?bereich=darstellung') await page.fill('#zeilen_pro_seite', '250') // Eindeutig das Einstellungsformular treffen – im Kopfbereich steht // ebenfalls ein Submit-Knopf (Abmelden), und der kommt im DOM zuerst. await page.click('.formular.breit button[type="submit"]') await expect(page.locator('.meldung-erfolg')).toBeVisible() await expect(page.locator('#zeilen_pro_seite')).toHaveValue('250') }) test('Abmelden beendet die Sitzung', async ({ page }) => { await anmelden(page) await page.click('form[action="/logout"] button') await expect(page).toHaveURL(/\/login/) await page.goto('/') await expect(page).toHaveURL(/\/login/) }) })