// @ts-check const { test, expect } = require('@playwright/test') const { komboboxWaehlen } = require('./hilfen') /* * Der Abgleich mit dem Bargeld-Tool im Browser: die Kachel in der Verwaltung, * das Formular dahinter und die Wirkung im Kontoblatt. * * Als Gegenstelle dient eine Adresse, die es nicht gibt. Das genügt: Der Abruf * selbst steckt in der PHP-Suite, wo ein Testserver antwortet – hier geht es um * den Weg und darum, dass ein gescheiterter Abruf die Zuordnung nicht aufhält. */ 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 Bargeld Giro ${MARKE}` const KATEGORIE = `E2E Bargeld Haushalt ${MARKE}` const ADRESSE = 'https://kasse.beispiel.invalid' 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(/\/$/) } /** Adresse und Kategorienauswahl zurücksetzen – die Instanz gehört nicht dem Test. */ async function zuruecksetzen(page) { await page.goto('/verwaltung/bargeld') await page.fill('#bargeld_url', '') for (const feld of await page.locator('input[name="kategorien[]"]:checked').all()) { await feld.uncheck() } await page.getByRole('button', { name: 'Speichern' }).click() await expect(page.locator('.meldung')).toContainText('gespeichert') } test.describe('Bargeld-Tool', () => { 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.selectOption('#kontoart', 'bank') await page.fill('#anfangssaldo', '1.000,00') await page.click('.formular button[type="submit"]') await expect(page).toHaveURL(/\/konten\/\d+\/bearbeiten/) const treffer = page.url().match(/\/konten\/(\d+)\//) giroId = treffer ? treffer[1] : null 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.afterEach(async ({ page }) => { await zuruecksetzen(page) }) test('Die Verwaltung führt zur Konfiguration', async ({ page }) => { await page.goto('/verwaltung') const kachel = page.locator('.kachel', { hasText: 'Bargeld-Tool' }) await kachel.getByRole('link', { name: /einrichten/ }).click() await expect(page).toHaveURL(/\/verwaltung\/bargeld$/) await expect(page.locator('h1')).toContainText('Bargeld-Tool') await expect(page.locator('#bargeld_url')).toBeVisible() await expect(page.locator('#bargeld_benutzer')).toBeVisible() await expect(page.locator('#bargeld_passwort')).toHaveAttribute('type', 'password') await expect(page.getByRole('checkbox', { name: KATEGORIE })).not.toBeChecked() }) test('Eine Adresse ohne Schema wird abgewiesen', async ({ page }) => { await page.goto('/verwaltung/bargeld') await page.fill('#bargeld_url', 'kasse.beispiel.invalid') await page.getByRole('button', { name: 'Speichern' }).click() await expect(page.locator('.meldung')).toContainText('http://') await expect(page.locator('#bargeld_url')).toHaveValue('') }) test('Der Verbindungstest meldet eine unerreichbare Gegenstelle', async ({ page }) => { await page.goto('/verwaltung/bargeld') await page.fill('#bargeld_url', ADRESSE) await page.getByRole('button', { name: 'Speichern' }).click() await expect(page.locator('.meldung')).toContainText('gespeichert') await page.getByRole('button', { name: 'Verbindung testen' }).click() await expect(page.locator('.meldung-fehler')).toContainText('nicht erreichbar') }) test('Erst mit Adresse zeigt das Kontoblatt die Abgleichspalte', async ({ page }) => { const empfaenger = `Ohne Bargeld ${MARKE}` await page.goto(`/konten/${giroId}/buchung`) await page.selectOption('#art', 'ausgabe') await page.fill('#datum', '2026-04-03') await page.fill('#betrag', '12,30') await page.fill('#empfaenger', empfaenger) await page.click('.buchungsmaske button[type="submit"]') await expect(page.locator('.meldung-erfolg')).toBeVisible() // Ohne Adresse gibt es die Spalte nicht – sie zeigte nur graue Kreise. await expect(page.locator('th.bargeldspalte')).toHaveCount(0) await page.goto('/verwaltung/bargeld') await page.fill('#bargeld_url', ADRESSE) await page.fill('#bargeld_tage', '10') await page.getByRole('button', { name: 'Speichern' }).click() await expect(page.locator('.meldung')).toContainText('gespeichert') await page.goto(`/konten/${giroId}`) await expect(page.locator('th.bargeldspalte')).toHaveCount(1) // Die Spalte steht zwischen Klasse und Betrag. const spalten = await page.locator('table.kontoblatt thead th').allTextContents() expect(spalten.indexOf('Bar')).toBe(spalten.indexOf('Klasse') + 1) expect(spalten.indexOf('Betrag')).toBe(spalten.indexOf('Bar') + 1) // Ohne vorgemerkte Kategorie steht dort der graue Kreis. const zeile = page.locator('tr', { hasText: empfaenger }) await expect(zeile.locator('td.bargeldspalte .bargeld-neutral')).toBeVisible() }) test('Eine vorgemerkte Kategorie wird beim Zuordnen geprüft', async ({ page }) => { // Der Abruf läuft ins Leere; genau das soll das Ausrufezeichen zeigen – // und die Zuordnung muss trotzdem stehen. test.setTimeout(60_000) const empfaenger = `Bargeldabhebung ${MARKE}` await page.goto('/verwaltung/bargeld') await page.fill('#bargeld_url', ADRESSE) await page.getByRole('checkbox', { name: KATEGORIE }).check() await page.getByRole('button', { name: 'Speichern' }).click() await expect(page.locator('.meldung')).toContainText('gespeichert') await page.goto(`/konten/${giroId}/buchung`) await page.selectOption('#art', 'ausgabe') await page.fill('#datum', '2026-04-04') await page.fill('#betrag', '50,00') await page.fill('#empfaenger', empfaenger) await page.click('.buchungsmaske button[type="submit"]') await expect(page.locator('.meldung-erfolg')).toBeVisible() const zeile = page.locator('tr', { hasText: empfaenger }) await zeile.locator('a.zuordnungsfeld').click() await komboboxWaehlen(zeile.locator('#zuordnungsauswahl select'), KATEGORIE) // Die Zuordnung steht, der gescheiterte Abruf hat sie nicht aufgehalten. // Über der Meldung steht noch die des Anlegens – gemeint ist die neue. await expect(page.locator('.meldung-erfolg').last()).toContainText('Zuordnung gespeichert') await expect(page.locator('.meldung-erfolg').last()).toContainText('fehlgeschlagen') const danach = page.locator('tr', { hasText: empfaenger }) await expect(danach).toContainText(KATEGORIE) await expect(danach.locator('td.bargeldspalte .bargeld-fehler')).toBeVisible() }) })