diff --git a/Changes.md b/Changes.md index a00f1e5..88be393 100644 --- a/Changes.md +++ b/Changes.md @@ -1,5 +1,39 @@ # Änderungen +## E2E-Datenbestand wird vor jedem Lauf aufgeräumt (04.09.2026) + +Die Browser-Tests legten ihre Konten, Kategorien und Buchungen bei jedem Lauf neu an, +weggeräumt hat sie niemand: Zuletzt standen über dreitausend Zeilen Testdaten in der +Datenbank – vierzig „E2E Bankprovision …“ hintereinander im Kategoriefilter des +Kontoblatts, und kein Bildschirmfoto eines fehlgeschlagenen Tests war mehr zu gebrauchen. + +`scripts/e2e-aufraeumen.php` räumt den Bestand weg; `tests/e2e/run.sh` ruft es vor jedem +Lauf auf. Vor dem Lauf und nicht danach, weil ein abgebrochener Lauf sonst einen Bestand +hinterlässt, an den niemand mehr denkt – und weil die Daten des letzten Laufs so bis zum +nächsten für die Fehlersuche stehen bleiben. `E2E_KEIN_AUFRAEUMEN=1` lässt sie liegen, +`--probe` zählt nur, was wegfiele. + +Gelöscht wird, was am Testnutzer hängt – nicht, was nach Testdaten aussieht. Ein +Namensmuster übersähe die Buchung „Supermarkt“ und träfe irgendwann etwas Echtes; die +Fremdschlüssel dagegen sagen genau, was zu diesem Nutzer gehört, und nehmen über ihre +Kaskaden auch die Zeilen ohne eigene `benutzer_id` mit (Splitzeilen, Budgetpositionen, +Bankkonten, Kurse). Der Nutzer selbst bleibt stehen, sonst käme der nächste Lauf nicht +durch die Anmeldung. + +Als Schranke gegen den Fehlgriff muss er den Anzeigenamen tragen, den +`scripts/e2e-benutzer.php` setzt: Wer `E2E_USER` versehentlich auf seinen eigenen Zugang +stellt, bekommt einen Abbruch statt eines leeren Datenbestands. + +Das Aufräumen deckte auf, dass sieben Tests auf den Resten früherer Läufe standen: Die +Auswertungen prüfen, dass ein Bericht eine Tabelle statt eines Platzhalters zeigt, das +Cockpit, dass „Übrige Konten“ eine Ebene tiefer führt – Daten dafür legte keiner von ihnen +an. Auf einer frisch aufgeräumten Instanz fielen sie aus; vorher hing ihr Ergebnis davon +ab, wer zuletzt was hatte laufen lassen. `scripts/e2e-grundbestand.php` stellt deshalb nach +dem Aufräumen einen festgelegten Bestand her, dessen Zuschnitte an genau diesen Tests +hängen: mehr Konten als `Vermoegensentwicklung::SERIEN`, Buchungen in jedem Monat des +laufenden Jahres, ein Vorjahr für den Vergleichsbericht, ein Depot mit Wertpapiergeschäft. +Die Suite prüft damit dasselbe wie vorher, aber auf einem Bestand, den sie kennt. + ## E2E-Tests an den Typeahead im Kontoblatt angepasst (04.09.2026) Zwölf E2E-Tests standen seit dem Typeahead-Umbau (Fix #41) auf Rot – nicht, weil die diff --git a/scripts/e2e-aufraeumen.php b/scripts/e2e-aufraeumen.php new file mode 100755 index 0000000..619a558 --- /dev/null +++ b/scripts/e2e-aufraeumen.php @@ -0,0 +1,79 @@ +#!/usr/bin/env php + $anzahl) { + $sage(sprintf(' %-24s %6d', $tabelle, $anzahl)); +} + +exit(0); diff --git a/scripts/e2e-grundbestand.php b/scripts/e2e-grundbestand.php new file mode 100755 index 0000000..bb98e25 --- /dev/null +++ b/scripts/e2e-grundbestand.php @@ -0,0 +1,61 @@ +#!/usr/bin/env php + $anzahl) { + $sage(sprintf(' %-16s %6d', $gattung, $anzahl)); +} + +exit(0); diff --git a/src/Services/E2EAufraeumer.php b/src/Services/E2EAufraeumer.php new file mode 100644 index 0000000..80b3f24 --- /dev/null +++ b/src/Services/E2EAufraeumer.php @@ -0,0 +1,140 @@ +|null + */ + public static function testnutzer(?string $benutzername = null): ?array + { + return Benutzer::findByName($benutzername ?? (getenv('E2E_USER') ?: self::BENUTZERNAME)); + } + + /** + * Ist das wirklich der Testnutzer? Der Anzeigename ist die Schranke: Wer + * `E2E_USER` versehentlich auf seinen eigenen Zugang stellt, verliert sonst + * mit einem Aufruf seinen ganzen Datenbestand. + * + * @param array $nutzer + */ + public static function istTestnutzer(array $nutzer): bool + { + return (string)($nutzer['anzeigename'] ?? '') === self::ANZEIGENAME; + } + + /** + * Räumt den Bestand des Testnutzers weg. + * + * @param bool $probe zählt nur, löscht nichts + * @return array Tabelle → Anzahl der Zeilen; leere bleiben weg + */ + public static function ausfuehren(int $benutzerId, bool $probe = false): array + { + $ergebnis = []; + + foreach (self::TABELLEN as $tabelle) { + $anzahl = $probe + ? (int)Database::fetchValue( + 'SELECT COUNT(*) FROM `' . $tabelle . '` WHERE benutzer_id = ?', + [$benutzerId], + 0 + ) + : Database::execute( + 'DELETE FROM `' . $tabelle . '` WHERE benutzer_id = ?', + [$benutzerId] + ); + + if ($anzahl > 0) { + $ergebnis[$tabelle] = $anzahl; + } + } + + // Bankinstitute sind Stammdaten für alle und hängen an keinem Nutzer. + // Der Import aus bankinstitute.spec.js legt eigene an; sie tragen das + // Präfix, an dem sich die Testdaten erkennen lassen. + $institute = $probe + ? (int)Database::fetchValue( + "SELECT COUNT(*) FROM bankinstitute WHERE institut LIKE 'E2E%'", + [], + 0 + ) + : Database::execute("DELETE FROM bankinstitute WHERE institut LIKE 'E2E%'"); + + if ($institute > 0) { + $ergebnis['bankinstitute'] = $institute; + } + + return $ergebnis; + } +} diff --git a/src/Services/E2EGrundbestand.php b/src/Services/E2EGrundbestand.php new file mode 100644 index 0000000..d0e80b4 --- /dev/null +++ b/src/Services/E2EGrundbestand.php @@ -0,0 +1,147 @@ + Gattung → Anzahl + */ + public static function anlegen(int $benutzerId): array + { + Mandant::setze($benutzerId); + + return (array)Database::transaktion(static function (): array { + $jahr = (int)date('Y'); + $klasse = Klasse::anlegen(self::PRAEFIX . ' Privat'); + + $kategorien = [ + 'ausgabe' => Kategorie::anlegen(['name' => self::PRAEFIX . ' Einkauf', 'art' => 'ausgabe']), + 'wohnen' => Kategorie::anlegen(['name' => self::PRAEFIX . ' Wohnen', 'art' => 'ausgabe']), + 'einnahme' => Kategorie::anlegen(['name' => self::PRAEFIX . ' Gehalt', 'art' => 'einnahme']), + ]; + + // Absteigende Anfangssalden: Das Vermögensdiagramm ordnet nach + // Größe, und nur bei eindeutiger Rangfolge stehen auf Ebene 2 + // verlässlich andere Konten als auf Ebene 1. + $konten = []; + for ($nr = 1; $nr <= self::KONTEN; $nr++) { + $konten[] = Konto::anlegen([ + 'name' => sprintf('%s Konto %02d', self::PRAEFIX, $nr), + 'kontoart' => $nr % 3 === 0 ? 'sparkonto' : 'bank', + 'anfangssaldo' => 10000 - $nr * 250, + 'aktiv' => 1, + ]); + } + + $depot = Konto::anlegen([ + 'name' => self::PRAEFIX . ' Depot', + 'kontoart' => 'depot', + 'anfangssaldo' => 0, + 'aktiv' => 1, + ]); + + $buchungen = 0; + + // Jeden Monat des laufenden Jahres füllen, damit die monatliche + // Aufteilung zwölf Spalten mit Werten zeigt. + for ($monat = 1; $monat <= 12; $monat++) { + $datum = sprintf('%04d-%02d-05', $jahr, $monat); + + Buchung::anlegen([ + 'konto_id' => $konten[0], 'datum' => $datum, 'betrag' => -49.90, + 'empfaenger' => 'Supermarkt', 'kategorie_id' => $kategorien['ausgabe'], + 'klasse_id' => $klasse, + ]); + Buchung::anlegen([ + 'konto_id' => $konten[1], 'datum' => $datum, 'betrag' => -820.00, + 'empfaenger' => 'Miete', 'kategorie_id' => $kategorien['wohnen'], + ]); + Buchung::anlegen([ + 'konto_id' => $konten[0], 'datum' => $datum, 'betrag' => 2400.00, + 'empfaenger' => 'Arbeitgeber', 'kategorie_id' => $kategorien['einnahme'], + ]); + $buchungen += 3; + } + + // Das Vorjahr für den Vergleichsbericht – ein Quartal genügt, er + // stellt Summen gegenüber, keine Monatsverläufe. + for ($monat = 1; $monat <= 3; $monat++) { + Buchung::anlegen([ + 'konto_id' => $konten[0], 'datum' => sprintf('%04d-%02d-12', $jahr - 1, $monat), + 'betrag' => -60.00, 'empfaenger' => 'Supermarkt', + 'kategorie_id' => $kategorien['ausgabe'], + ]); + $buchungen++; + } + + $wertpapier = Wertpapier::anlegen([ + 'name' => self::PRAEFIX . ' Aktie', 'isin' => 'DE0007236101', + 'wkn' => '723610', 'art' => 'aktie', 'waehrung' => 'EUR', 'aktiv' => 1, + ]); + + Depotbuchung::anlegen([ + 'konto_id' => $depot, + 'wertpapier_id' => $wertpapier, + 'wertpapiername' => self::PRAEFIX . ' Aktie', + 'datum' => sprintf('%04d-02-10', $jahr), + 'vorgang' => 'kauf', + 'stueck' => 25, + 'betrag' => 1250.00, + 'gebuehren' => 9.90, + 'verrechnungskonto_id' => $konten[0], + ]); + $buchungen++; + + return [ + 'konten' => count($konten) + 1, + 'kategorien' => count($kategorien), + 'klassen' => 1, + 'wertpapiere' => 1, + 'buchungen' => $buchungen, + ]; + }); + } +} diff --git a/tests/41_E2EAufraeumenTest.php b/tests/41_E2EAufraeumenTest.php new file mode 100644 index 0000000..97b089a --- /dev/null +++ b/tests/41_E2EAufraeumenTest.php @@ -0,0 +1,274 @@ +erkenntDenTestnutzer(); + $this->raeumtDenBestandWeg(); + $this->kaskadeNimmtDieSplitzeilenMit(); + $this->fremderBestandBleibtStehen(); + $this->probelaufLoeschtNichts(); + $this->grundbestandTraegtDieDarstellungstests(); + $this->grundbestandGehtBeimAufraeumenWiederWeg(); + } + + /** Legt einen Nutzer an und macht ihn zum Mandanten. */ + private function nutzerAnlegen(string $anzeigename): int + { + $id = Benutzer::anlegen( + 'aufraeum_' . bin2hex(random_bytes(4)), + 'testpasswort-' . bin2hex(random_bytes(4)), + $anzeigename + ); + Mandant::setze($id); + + return $id; + } + + /** Ein Konto mit einer Buchung darauf; liefert die Kennung der Buchung. */ + private function bestandAnlegen(string $marke): int + { + $konto = Konto::anlegen([ + 'name' => 'E2E Giro ' . $marke, 'kontoart' => 'bank', 'anfangssaldo' => 0, 'aktiv' => 1, + ]); + + return Buchung::anlegen([ + 'konto_id' => $konto, 'datum' => '2026-04-01', 'betrag' => -12.30, + 'empfaenger' => 'Supermarkt', + ]); + } + + private function erkenntDenTestnutzer(): void + { + $this->assert( + E2EAufraeumer::istTestnutzer(['anzeigename' => E2EAufraeumer::ANZEIGENAME]), + 'Der Anzeigename des Testnutzers wird erkannt' + ); + + // Die Schranke gegen den Fehlgriff: Wer E2E_USER auf seinen eigenen + // Zugang stellt, soll nichts verlieren. + $this->assert( + !E2EAufraeumer::istTestnutzer(['anzeigename' => 'Felix']), + 'Ein gewöhnlicher Nutzer gilt nicht als Testnutzer' + ); + $this->assert( + !E2EAufraeumer::istTestnutzer([]), + 'Ohne Anzeigename gilt niemand als Testnutzer' + ); + } + + private function raeumtDenBestandWeg(): void + { + $nutzer = $this->nutzerAnlegen(E2EAufraeumer::ANZEIGENAME); + $this->bestandAnlegen('111111'); + Kategorie::anlegen(['name' => 'E2E Einkauf 111111', 'art' => 'ausgabe']); + Klasse::anlegen('E2E Privat 111111'); + + $ergebnis = E2EAufraeumer::ausfuehren($nutzer); + + $this->assertEquals(1, $ergebnis['konten'] ?? 0, 'Das Konto ist mitgezählt'); + $this->assertEquals(1, $ergebnis['buchungen'] ?? 0, 'Die Buchung ist mitgezählt'); + $this->assertEquals(1, $ergebnis['kategorien'] ?? 0, 'Die Kategorie ist mitgezählt'); + $this->assertEquals(1, $ergebnis['klassen'] ?? 0, 'Die Klasse ist mitgezählt'); + + $this->assertEquals( + 0, + (int)Database::fetchValue('SELECT COUNT(*) FROM konten WHERE benutzer_id = ?', [$nutzer], 0), + 'Nach dem Aufräumen steht kein Konto mehr' + ); + $this->assertEquals( + 0, + (int)Database::fetchValue('SELECT COUNT(*) FROM buchungen WHERE benutzer_id = ?', [$nutzer], 0), + 'Nach dem Aufräumen steht keine Buchung mehr' + ); + + // Der Nutzer selbst bleibt: Ohne ihn käme der nächste Lauf nicht durch + // die Anmeldung. + $this->assertNotEmpty(Benutzer::find($nutzer), 'Der Testnutzer selbst bleibt stehen'); + } + + private function kaskadeNimmtDieSplitzeilenMit(): void + { + $nutzer = $this->nutzerAnlegen(E2EAufraeumer::ANZEIGENAME); + $konto = Konto::anlegen([ + 'name' => 'E2E Giro 222222', 'kontoart' => 'bank', 'anfangssaldo' => 0, 'aktiv' => 1, + ]); + $kategorie = Kategorie::anlegen(['name' => 'E2E Einkauf 222222', 'art' => 'ausgabe']); + + $buchung = Buchung::anlegen( + ['konto_id' => $konto, 'datum' => '2026-04-02', 'betrag' => -90.0, 'empfaenger' => 'Aufzuteilen'], + [ + ['kategorie_id' => $kategorie, 'betrag' => -50.0, 'notiz' => 'Teil eins'], + ['kategorie_id' => $kategorie, 'betrag' => -40.0, 'notiz' => 'Teil zwei'], + ] + ); + + $this->assertEquals(2, count(Buchung::splits($buchung)), 'Die Splitzeilen stehen zunächst'); + + E2EAufraeumer::ausfuehren($nutzer); + + // buchung_splits trägt keine benutzer_id – die Zeilen gehen nur mit, + // weil der Fremdschlüssel kaskadiert. + $this->assertEquals( + 0, + (int)Database::fetchValue( + 'SELECT COUNT(*) FROM buchung_splits WHERE buchung_id = ?', + [$buchung], + 0 + ), + 'Die Splitzeilen gehen über die Kaskade mit' + ); + } + + private function fremderBestandBleibtStehen(): void + { + $fremd = $this->nutzerAnlegen('Felix'); + $this->bestandAnlegen('333333'); + $fremdeKategorie = Kategorie::anlegen(['name' => 'Lebensmittel', 'art' => 'ausgabe']); + + $test = $this->nutzerAnlegen(E2EAufraeumer::ANZEIGENAME); + $this->bestandAnlegen('444444'); + + E2EAufraeumer::ausfuehren($test); + + $this->assertEquals( + 1, + (int)Database::fetchValue('SELECT COUNT(*) FROM konten WHERE benutzer_id = ?', [$fremd], 0), + 'Das Konto des fremden Nutzers steht noch' + ); + $this->assertEquals( + 1, + (int)Database::fetchValue('SELECT COUNT(*) FROM buchungen WHERE benutzer_id = ?', [$fremd], 0), + 'Die Buchung des fremden Nutzers steht noch' + ); + $this->assertNotEmpty( + Database::fetchOne('SELECT * FROM kategorien WHERE id = ?', [$fremdeKategorie]), + 'Die Kategorie des fremden Nutzers steht noch' + ); + } + + /** + * Der Grundbestand ist kein beliebiger Datenhaufen: Jeder Zuschnitt hängt an + * einem Test, der ihn braucht. Bleibt er hinter einer dieser Grenzen zurück, + * fällt der zugehörige Browser-Test aus – und zwar mit einer Meldung über + * eine fehlende Tabellenspalte, die den Grund nicht verrät. + */ + private function grundbestandTraegtDieDarstellungstests(): void + { + $nutzer = $this->nutzerAnlegen(E2EAufraeumer::ANZEIGENAME); + $jahr = (int)date('Y'); + + E2EGrundbestand::anlegen($nutzer); + + $konten = (int)Database::fetchValue( + 'SELECT COUNT(*) FROM konten WHERE benutzer_id = ?', + [$nutzer], + 0 + ); + $this->assertGreaterThan( + Vermoegensentwicklung::SERIEN, + $konten, + 'Mehr Konten als Farbtöne – sonst gibt es kein „Übrige Konten“ zum Aufklappen' + ); + + // Zwölf Monatsspalten füllen sich nur, wenn in jedem Monat etwas steht. + $monate = (int)Database::fetchValue( + 'SELECT COUNT(DISTINCT MONTH(datum)) FROM buchungen + WHERE benutzer_id = ? AND YEAR(datum) = ?', + [$nutzer, $jahr], + 0 + ); + $this->assertEquals(12, $monate, 'Jeder Monat des laufenden Jahres trägt Buchungen'); + + $this->assertGreaterThan( + 0, + (int)Database::fetchValue( + 'SELECT COUNT(*) FROM buchungen WHERE benutzer_id = ? AND YEAR(datum) = ?', + [$nutzer, $jahr - 1], + 0 + ), + 'Das Vorjahr ist besetzt – der Vergleichsbericht stellt zwei Zeiträume nebeneinander' + ); + + $this->assertGreaterThan( + 0, + (int)Database::fetchValue( + 'SELECT COUNT(*) FROM depot_buchungen WHERE benutzer_id = ?', + [$nutzer], + 0 + ), + 'Ein Wertpapiergeschäft steht – sonst sind /wertpapiere/buchungen eine leere Liste' + ); + + // Ohne Kategorie bliebe der Summenbericht ein Platzhalter. + $this->assertGreaterThan( + 0, + (int)Database::fetchValue( + 'SELECT COUNT(*) FROM buchungen WHERE benutzer_id = ? AND kategorie_id IS NOT NULL', + [$nutzer], + 0 + ), + 'Die Buchungen tragen Kategorien' + ); + } + + private function grundbestandGehtBeimAufraeumenWiederWeg(): void + { + $nutzer = $this->nutzerAnlegen(E2EAufraeumer::ANZEIGENAME); + E2EGrundbestand::anlegen($nutzer); + + E2EAufraeumer::ausfuehren($nutzer); + + foreach (['konten', 'buchungen', 'kategorien', 'wertpapiere', 'depot_buchungen'] as $tabelle) { + $this->assertEquals( + 0, + (int)Database::fetchValue( + 'SELECT COUNT(*) FROM `' . $tabelle . '` WHERE benutzer_id = ?', + [$nutzer], + 0 + ), + 'Der Grundbestand ist aus ' . $tabelle . ' wieder verschwunden' + ); + } + } + + private function probelaufLoeschtNichts(): void + { + $nutzer = $this->nutzerAnlegen(E2EAufraeumer::ANZEIGENAME); + $this->bestandAnlegen('555555'); + + $probe = E2EAufraeumer::ausfuehren($nutzer, true); + + $this->assertEquals(1, $probe['konten'] ?? 0, 'Der Probelauf zählt das Konto'); + $this->assertEquals( + 1, + (int)Database::fetchValue('SELECT COUNT(*) FROM konten WHERE benutzer_id = ?', [$nutzer], 0), + 'Der Probelauf lässt das Konto stehen' + ); + } +} diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 17cc2d1..155ca36 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -51,6 +51,57 @@ Hierher gehört nur, was einen Browser braucht: Formularabläufe, Redirects, gerenderte Views, JavaScript. Rechen- und Model-Logik gehört in die PHP-Suite (`tests/NN_*.php`) – schneller und isoliert. +## Aufräumen + +Jeder Lauf legt Konten, Kategorien, Klassen und Buchungen neu an – mit einer +Zeitmarke im Namen, damit zwei Läufe sich nicht ins Gehege kommen. Damit sich +das nicht ansammelt, räumt `run.sh` **vor** jedem Lauf auf: + +```bash +docker compose exec -u www-data php php scripts/e2e-aufraeumen.php +docker compose exec -u www-data php php scripts/e2e-aufraeumen.php --probe # nur zählen +``` + +Vor dem Lauf und nicht danach, weil ein abgebrochener Lauf sonst einen Bestand +hinterlässt, an den niemand mehr denkt – und weil die Daten des letzten Laufs +so bis zum nächsten für die Fehlersuche stehen bleiben. + +Gelöscht wird alles, was am Testnutzer hängt, nicht, was nach Testdaten +aussieht: Ein Namensmuster übersähe die Buchung „Supermarkt“ und träfe +irgendwann etwas Echtes. Der Nutzer selbst bleibt stehen, und er muss den +Anzeigenamen tragen, den `scripts/e2e-benutzer.php` setzt – sonst bricht das +Skript ab, statt einem echten Zugang den Bestand zu leeren. + +`E2E_KEIN_AUFRAEUMEN=1` lässt den Bestand stehen: + +```bash +E2E_KEIN_AUFRAEUMEN=1 tests/e2e/run.sh +``` + +## Grundbestand + +Nach dem Aufräumen legt `run.sh` einen festgelegten Grundbestand an: + +```bash +docker compose exec -u www-data php php scripts/e2e-grundbestand.php +``` + +Ein Teil der Tests prüft die Darstellung, nicht das Rechnen – dass ein Bericht +eine Tabelle statt eines Platzhalters zeigt, dass Zahlenspalten rechtsbündig +stehen, dass „Übrige Konten“ eine Ebene tiefer führt. Solche Tests brauchen +einen Bestand, legen ihn aber nicht selbst an; bis zum Aufräumen lebten sie von +den Resten früherer Läufe und fanden je nach Vorgeschichte etwas anderes vor. + +Die Zuschnitte in `E2EGrundbestand` sind deshalb nicht beliebig: mehr Konten als +`Vermoegensentwicklung::SERIEN` (sonst fehlt „Übrige Konten“), Buchungen in jedem +Monat des laufenden Jahres (sonst bleiben Monatsspalten leer), ein Vorjahr für +den Vergleichsbericht, ein Depot mit Wertpapiergeschäft für die Wertpapierlisten. +Wer daran etwas ändert, sieht in `tests/41_E2EAufraeumenTest.php` nach: Dort steht +zu jeder Grenze, welcher Test daran hängt. + +Wer eine Spec schreibt, die eigene Daten braucht, legt sie weiterhin selbst an – +der Grundbestand trägt nur die Tests, die irgendeinen Bestand voraussetzen. + ## Gemeinsame Helfer `specs/hilfen.js` liegt neben den Specs, endet aber nicht auf `.spec.js` und wird diff --git a/tests/e2e/run.sh b/tests/e2e/run.sh index e411317..784855d 100755 --- a/tests/e2e/run.sh +++ b/tests/e2e/run.sh @@ -24,6 +24,24 @@ IMAGE=$(sed -n 's/^ *image: *//p' "$RUNNER_DIR/docker-compose.yml" | head -n1) docker image inspect "$IMAGE" >/dev/null 2>&1 \ || skip "Playwright-Image $IMAGE nicht vorhanden (docker pull $IMAGE)" +# Vor dem Lauf aufräumen, nicht danach: Ein abgebrochener Lauf hinterlässt sonst +# einen Bestand, an den niemand mehr denkt – und bis hierher bleiben die Daten +# des letzten Laufs für die Fehlersuche stehen. E2E_KEIN_AUFRAEUMEN=1 lässt sie +# stehen, wer sie über den nächsten Lauf hinaus braucht. +if [ "${E2E_KEIN_AUFRAEUMEN:-0}" != "1" ]; then + PROJEKT=$(CDPATH= cd -- "$TEST_DIR/../.." && pwd) + fm() { (cd "$PROJEKT" && docker compose exec -T -u www-data php php "$@"); } + + # Der Grundbestand nur nach erfolgreichem Aufräumen: Sonst stünde er ein + # zweites Mal neben dem alten und verfälschte, was die Tests vorfinden. + if fm scripts/e2e-aufraeumen.php --still; then + fm scripts/e2e-grundbestand.php --still \ + || echo "WARNUNG: Grundbestand fehlgeschlagen — Tests, die einen Bestand erwarten, fallen aus." >&2 + else + echo "WARNUNG: Aufräumen fehlgeschlagen — der Lauf beginnt auf dem alten Bestand." >&2 + fi +fi + # Zugangsdaten des Testnutzers durchreichen; der Runner kennt nur BASE_URL. cd "$RUNNER_DIR" TEST_DIR="$TEST_DIR" BASE_URL="$BASE_URL" exec docker compose run --rm \