Finanzmanager/tests/e2e/specs/banking.spec.js
fds2610-bot 0b4a216954 Sammel-Commit: PayPal-Bankverbindung und Bankleitzahlen-Verzeichnis
Zwei Features an derselben Stelle, die im Arbeitsverzeichnis
nebeneinander lagen und sich dieselben Dateien teilen (Routen,
BankingController, Bankzugang, Zugangsformular, Dokumentation) –
getrennte Commits ließen sich daraus nur mit einem kaputten
Zwischenstand schneiden.

PayPal als zweite Art von Bankverbindung
----------------------------------------
„Bankverbindung anlegen“ führt zur Wahl der Art: HBCI/FinTS oder
PayPal (bank_zugaenge.typ, Migration 014). Die Abfrage läuft über die
Classic-NVP-API (Services\PaypalNvp, TransactionSearch und GetBalance).
Kein Dreischritt, da PayPal genau ein Guthabenkonto führt –
Zugangsdaten und Kontenzuordnung stehen in einem Formular. Konten,
Umsätze, Protokoll, Regeln und Abgleich bleiben dieselben.

Bankleitzahlen-Verzeichnis
--------------------------
Verwaltung → Bankleitzahlen (/verwaltung/bankinstitute, Migration 015)
nimmt die CSV-Institutsliste der Deutschen Kreditwirtschaft auf und
beantwortet damit die eine Angabe, die beim Anlegen einer
FinTS-Verbindung regelmäßig fehlt: den PIN/TAN-Zugangspunkt.

Reine Nachschlagedaten ohne benutzer_id; ein Import ersetzt den
gesamten Bestand, statt ihn zu ergänzen. „Nur prüfen“ und „Übernehmen“
sind zwei Knöpfe an derselben Datei – abgelegt wird sie nicht, ihr
Inhalt steht ja in der Tabelle.

Services\FintsInstituteImport nimmt der Datei ihre Eigenheiten ab:
ISO-8859-1 statt UTF-8, ein Institutsname über zwei Zeilen in
Anführungszeichen, dieselbe Bankleitzahl vielfach (eine Zeile je
Filiale), Hunderte leerer Zeilen am Ende, Text statt Adresse, wo es
keinen PIN/TAN-Zugang gibt. Spalten werden über ihre Überschrift
angesprochen; fehlen BLZ und Institut, bricht der Import ab.

Gesucht wird über Bankleitzahl, BIC, Name und Ort in einem Zug: „1822“
steht bei der 1822direkt im Namen und bei der Frankfurter Sparkasse im
BIC, in keiner der beiden Bankleitzahlen.

Aus der Trefferliste führt „Verbindung anlegen“ ins gefüllte
FinTS-Formular. Die FinTS-Adresse ist damit kein Pflichtfeld mehr –
bleibt sie leer, wird sie zur Bankleitzahl nachgeschlagen. Findet auch
das nichts, weist Bankzugang den Zugang ab, statt ihn ohne Gegenstelle
zu speichern.

Tests: 31_PaypalZugangTest, 32_BankinstituteTest,
e2e/specs/banking.spec.js, e2e/specs/bankinstitute.spec.js.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 08:48:14 +02:00

155 lines
6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @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)
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('Bankverbindungen', () => {
test.beforeEach(async ({ page }) => {
await anmelden(page)
})
test('„Bankverbindung anlegen“ führt zur Wahl zwischen HBCI/FinTS und PayPal', async ({ page }) => {
await page.goto('/banking')
await page.click('a[href="/banking/neu"]')
await expect(page.locator('h2')).toContainText('Wie wird abgerufen?')
const karten = page.locator('.formatwahl .formatkarte')
await expect(karten).toHaveCount(2)
await expect(karten.nth(0)).toContainText('HBCI/FinTS')
await expect(karten.nth(1)).toContainText('PayPal')
})
test('Die erste Wahl führt in die bisherige Bankenmaske', async ({ page }) => {
await page.goto('/banking/neu')
await page.click('.formatkarte:has-text("HBCI/FinTS")')
await expect(page).toHaveURL(/\/banking\/neu\/fints$/)
await expect(page.locator('.schrittmarke')).toContainText('Schritt 1 von 3')
await expect(page.locator('#fints_url')).toBeVisible()
await expect(page.locator('#pin')).toBeVisible()
})
test('Die zweite Wahl führt in die PayPal-Maske mit allen Angaben für die Abfrage', async ({ page }) => {
await page.goto('/banking/neu')
await page.click('.formatkarte:has-text("PayPal")')
await expect(page).toHaveURL(/\/banking\/neu\/paypal$/)
// Die drei Angaben der NVP-Schnittstelle und der Endpunkt-Schalter.
await expect(page.locator('#api_benutzer')).toBeVisible()
await expect(page.locator('#api_kennwort')).toBeVisible()
await expect(page.locator('#api_signatur')).toBeVisible()
await expect(page.locator('input[name="sandbox"]')).toBeAttached()
// Die Kontenzuordnung steht hier im Formular, nicht auf einer eigenen Seite.
await expect(page.locator('#konto_id')).toBeVisible()
await expect(page.locator('#konto_id option[value="neu"]')).toHaveCount(1)
})
test('PayPal-Verbindung anlegen, dabei ein neues Konto anlegen und wiederfinden', async ({ page }) => {
const name = `E2E PayPal ${MARKE}`
const konto = `E2E PayPal-Guthaben ${MARKE}`
await page.goto('/banking/neu/paypal')
await page.fill('#name', name)
await page.fill('#api_benutzer', `e2e_api1.example.org`)
await page.fill('#api_kennwort', 'e2e-kennwort')
await page.fill('#api_signatur', 'e2e-signatur')
await page.check('input[name="sandbox"]')
// Die Felder des neuen Kontos sind erst nach dieser Wahl sichtbar.
await expect(page.locator('#neuer_name')).toBeHidden()
await page.selectOption('#konto_id', 'neu')
await expect(page.locator('#neuer_name')).toBeVisible()
await page.fill('#neuer_name', konto)
await page.fill('#anfangssaldo', '25,00')
await page.click('.formular button[type="submit"]')
await expect(page.locator('.meldung-erfolg')).toBeVisible()
await expect(page).toHaveURL(/\/banking$/)
// In der Übersicht steht die Verbindung mit ihrer Art.
const zeile = page.locator('table.liste tr', { hasText: name })
await expect(zeile).toContainText('PayPal')
// Und beim Öffnen steht das eben angelegte Konto zugeordnet da; die
// Geheimnisse werden nicht wieder angezeigt.
await zeile.locator('a').first().click()
await expect(page.locator('#api_benutzer')).toHaveValue('e2e_api1.example.org')
await expect(page.locator('#api_kennwort')).toHaveValue('')
await expect(page.locator('#konto_id option:checked')).toHaveText(konto)
await expect(page.locator('input[name="sandbox"]')).toBeChecked()
})
test('„nicht zugeordnet“ löst eine bestehende Zuordnung wieder', async ({ page }) => {
const name = `E2E PayPal Zuordnung ${MARKE}`
const konto = `E2E PayPal-Konto ${MARKE}`
await page.goto('/banking/neu/paypal')
await page.fill('#name', name)
await page.fill('#api_benutzer', 'e2e_api1.example.org')
await page.fill('#api_kennwort', 'e2e-kennwort')
await page.fill('#api_signatur', 'e2e-signatur')
await page.selectOption('#konto_id', 'neu')
await page.fill('#neuer_name', konto)
await page.click('.formular button[type="submit"]')
await expect(page).toHaveURL(/\/banking$/)
await page.locator('table.liste tr', { hasText: name }).locator('a').first().click()
await expect(page.locator('#konto_id option:checked')).toHaveText(konto)
// Die leere Wahl heißt hier ausdrücklich „Zuordnung lösen“ – sie darf
// nicht als „nichts geändert“ durchrutschen.
await page.selectOption('#konto_id', '')
await page.click('.formular button[type="submit"]')
await expect(page.locator('.meldung-erfolg')).toBeVisible()
await expect(page.locator('#konto_id option:checked')).toHaveText('– nicht zugeordnet –')
})
test('Ein PayPal-Zugang kennt kein TAN-Verfahren', async ({ page }) => {
const name = `E2E PayPal ohne TAN ${MARKE}`
await page.goto('/banking/neu/paypal')
await page.fill('#name', name)
await page.fill('#api_benutzer', 'e2e_api1.example.org')
await page.fill('#api_kennwort', 'e2e-kennwort')
await page.fill('#api_signatur', 'e2e-signatur')
await page.click('.formular button[type="submit"]')
await expect(page).toHaveURL(/\/banking$/)
const ziel = await page
.locator('table.liste tr', { hasText: name })
.locator('a')
.first()
.getAttribute('href')
await page.goto(`${ziel}/verfahren`)
await expect(page.locator('.meldung-warnung')).toContainText('kein TAN-Verfahren')
await expect(page).toHaveURL(new RegExp(`${ziel}$`))
})
})