Steuerkram/tests/e2e
fds2610-bot 7cea573ffc Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500
Steuerkram an den e2e-runner angebunden (tests/e2e/, 44 Playwright-Tests).
Der erste Smoke-Lauf fand zwei Seiten mit HTTP 500: AccountController::create
las $_GET['from'] ungeprüft, assets/form.php nutzte $testMode und
$defaultKontoId außerhalb des Bearbeiten-Zweigs. Beides war bis zur
Fehler-Härtung (#142) nur eine stille Warning.

Test 67 räumt sein Belegverzeichnis jetzt mit ab - es blieb als root-eigenes
Verzeichnis liegen und blockierte spätere echte Uploads mit HTTP 500.

Test 77 (neu) sichert die Löschsperre von Beleg::delete() ab.
2026-08-02 11:58:33 +02:00
..
helpers Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
specs Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
.gitignore Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
global-setup.js Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
package-lock.json Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
package.json Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
playwright.config.js Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
README.md Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00
run.sh Fix #e2e: E2E-Tests ergänzt, /accounts/new und /assets/new lieferten HTTP 500 2026-08-02 11:58:33 +02:00

Steuerkram — E2E-Tests (Playwright)

Browser-Tests für die Ebene, die die PHP-Testsuite nicht erreicht: Routing, Controller, Views und das JavaScript in den Formularen.

Sie laufen im Container des generischen e2e-runner-Projekts (~/projects/e2e-runner/) — auf dem Host wird nichts installiert (kein Node, kein Browser, kein npm).

Warum diese Ebene

Die PHP-Suite (tests/NN_*.php) prüft Models und Services und ist dort gründlich. Sie ruft aber nie einen Controller über HTTP auf. Genau dort saßen die zuletzt aufgetretenen Fehler:

  • /accounts/new und /assets/new lieferten HTTP 500 — gefunden vom ersten Smoke-Lauf. Ursache: undefinierte Variablen, die seit der Fehler-Härtung (Fix #142) keine stille Warning mehr sind, sondern eine Exception.
  • Netto/Brutto-Umschalter (Fix #137): Ein submit-Handler rechnet den eingegebenen Bruttowert vor dem Absenden in Netto um. Serverseitig ist nur das Ergebnis sichtbar — eine kaputte Umrechnung fiele nie auf.
  • DOM-XSS in der Bankimport-Vorschau (Fix #133): Die Vorschau wird vollständig im Browser aus einer fetch-Antwort gebaut.

Voraussetzungen

  1. Steuerkram läuft unter http://localhost:8080 (docker compose up -d).

  2. Testnutzer existiert (einmalig, idempotent wiederholbar):

    docker compose exec web php scripts/e2e-user.php
    

    Legt e2e / e2e-test-Pass123! an bzw. setzt Passwort und Sperrstatus zurück. Abweichende Zugangsdaten als Argumente oder per E2E_USER / E2E_PASSWORD (Defaults: helpers/env.js). Entfernen mit --delete.

  3. Testmodus aktiv — sonst lassen sich Testbuchungen und -rechnungen nicht wieder löschen (Einstellungen → Testmodus).

Ausführen

tests/e2e/run.sh

Das Skript prüft vorab, ob Docker, das e2e-runner-Projekt (Pfad überschreibbar via E2E_RUNNER_DIR) und das Playwright-Image vorhanden sind. Fehlt etwas, wird nur gewarnt und übersprungen (Exit 0) — die E2E-Tests sind optional und blockieren keine Umgebung ohne Runner.

Andere Zielinstanz: BASE_URL=http://host.docker.internal:9000 tests/e2e/run.sh

Einzelne Datei oder UI-Modus zum Debuggen:

cd ~/projects/e2e-runner
TEST_DIR=~/projects/Steuerkram/tests/e2e docker compose run --rm playwright \
  sh -c "npm ci && npx playwright test smoke.spec.js"

# UI-Modus, danach http://localhost:8077 öffnen:
TEST_DIR=~/projects/Steuerkram/tests/e2e docker compose run --rm --service-ports playwright-ui

HTML-Report, Screenshots und Traces landen in playwright-report/ und test-results/.

Umgang mit Testdaten

Die Tests laufen gegen eine Instanz mit echten Arbeitsdaten. Deshalb gilt:

  • Sie legen ausschließlich eigene Datensätze an, markiert mit E2E-TEST-<zeit>-<n> (helpers/app.js, uniqueTag), und räumen sie im afterEach wieder ab.
  • Bestehende Belege, Buchungen und Rechnungen werden nie verändert oder gelöscht.
  • Der Bankimport-Test bricht vor dem Bestätigen ab — die Vorschau allein legt keine Transaktionen an.

Reste nach einem abgebrochenen Lauf entfernen:

docker compose exec web php scripts/e2e-cleanup.php          # nur anzeigen
docker compose exec web php scripts/e2e-cleanup.php --force  # löschen

Nicht umkehrbare Nebenwirkung

rechnung-export.spec.js finalisiert eine Rechnung und verbraucht dabei eine Nummer aus dem laufenden Nummernkreis. Die Rechnung selbst wird wieder gelöscht, die Nummer bleibt vergeben (GoBD — eine Rücknahme wäre auch nicht wünschenswert). Wer das vermeiden will, lässt diesen Test weg:

... npx playwright test --grep-invert "Finalisieren"

Aufbau

Datei Inhalt
specs/smoke.spec.js Alle Hauptseiten rendern ohne Serverfehler; 404, Login-Zwang, CSV-Export
specs/beleg-buchung.spec.js Upload → Buchungsmaske → gespeicherte Buchung, inkl. Netto/Brutto-Umschalter
specs/rechnung-export.spec.js Entwurf → Finalisieren → PDF- und XML-Export (XRechnung 3.0)
specs/bank-import.spec.js Bankimport-Vorschau inkl. XSS-Regression
helpers/app.js Upload, Aufräumen, Betragsparsing, gotoOk
helpers/env.js Zugangsdaten und Basis-URL
global-setup.js Einmaliger Login, legt .auth/user.json an

Fallstricke

  • Submit-Buttons immer auf ihr Formular scopen. In der Sidebar steht das Logout-Formular (layout/nav.php); ein ungescopetes button[type="submit"] trifft dessen Button zuerst und beendet die Session — alle folgenden Tests laufen dann gegen die Login-Seite.
  • Reihenfolge in der Buchungsmaske: Die Auswahl des Kategorie-Kontos ruft updateAutoUst() und setzt den USt-Satz passend zum Steuercode. Den Satz deshalb nach dem Konto setzen.
  • Ein Redirect auf /login endet mit Status 200. gotoOk() prüft deshalb zusätzlich den Pfad — sonst schlagen Tests mit irreführenden Meldungen fehl.
  • Belegverzeichnisse aus PHP-Testläufen: docker compose exec web php tests/run.php läuft als root und kann in data/belege/<Jahr>/ ein Verzeichnis anlegen, das root gehört, während die Transaktion die Belegnummer zurückrollt. Trifft später ein echter Upload auf dieselbe Nummer, scheitert move_uploaded_file() mit HTTP 500. Solche Leichen finden: find data/belege -maxdepth 2 -user root