Die offenen Vorgänge „im Bargeld-Tool nicht gefunden“ und „Bargeld-Tool- Prüfung fehlgeschlagen“ führen in den Buchungsbericht mit dem Filter „Bargeld-Tool“ – dort steht die Spalte Kategorie/Gegenkonto mit. Die eigene Liste unter /verwaltung/bargeld/fehler entfällt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
199 lines
8 KiB
JavaScript
199 lines
8 KiB
JavaScript
// @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(90_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.
|
||
// Der Abruf selbst braucht bis zu BargeldTool::ZEITGRENZE (8 s) für die
|
||
// Verbindung – dazu kommt die Namensauflösung der ungültigen Adresse,
|
||
// zusammen bis über 15 s. Der Standard-Timeout von 5 s reicht dafür nicht.
|
||
await expect(page.locator('.meldung-erfolg').last())
|
||
.toContainText('Zuordnung gespeichert', { timeout: 25_000 })
|
||
await expect(page.locator('.meldung-erfolg').last())
|
||
.toContainText('fehlgeschlagen', { timeout: 25_000 })
|
||
|
||
const danach = page.locator('tr', { hasText: empfaenger })
|
||
await expect(danach).toContainText(KATEGORIE)
|
||
await expect(danach.locator('td.bargeldspalte .bargeld-fehler')).toBeVisible()
|
||
|
||
// Der offene Vorgang im Cockpit führt in den Buchungsbericht, gefiltert
|
||
// auf fehlgeschlagene Prüfungen – samt Kategorie (#131).
|
||
await page.goto('/')
|
||
await page.locator('.vorgangsliste a', { hasText: 'Bargeld-Tool-Prüfung fehlgeschlagen' }).click()
|
||
await expect(page).toHaveURL(/\/auswertungen\/bericht\?.*typ=buchungsbericht/)
|
||
await expect(page.locator('select[name="bargeld"]')).toHaveValue('fehler')
|
||
await expect(page.locator('table.buchungsgruppen thead')).toContainText('Kategorie')
|
||
const imBericht = page.locator('table.buchungsgruppen tr', { hasText: empfaenger })
|
||
await expect(imBericht).toContainText(KATEGORIE)
|
||
await expect(imBericht).toContainText(GIRO)
|
||
await expect(imBericht.locator('td.bargeldspalte .bargeld-fehler')).toBeVisible()
|
||
})
|
||
})
|