Merge pull request 'Fix #64: E2E-Datenbestand vor jedem Lauf aufräumen und neu aufbauen' (#65) from fds2610-bot/Finanzmanager:main into main
Reviewed-on: https://codeberg.org/fds2610/Finanzmanager/pulls/65
This commit is contained in:
commit
2abcb852c3
8 changed files with 804 additions and 0 deletions
34
Changes.md
34
Changes.md
|
|
@ -1,5 +1,39 @@
|
||||||
# Änderungen
|
# Ä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)
|
## 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
|
Zwölf E2E-Tests standen seit dem Typeahead-Umbau (Fix #41) auf Rot – nicht, weil die
|
||||||
|
|
|
||||||
79
scripts/e2e-aufraeumen.php
Executable file
79
scripts/e2e-aufraeumen.php
Executable file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Räumt den Datenbestand der E2E-Tests weg.
|
||||||
|
*
|
||||||
|
* docker compose exec -u www-data php php scripts/e2e-aufraeumen.php
|
||||||
|
*
|
||||||
|
* `tests/e2e/run.sh` ruft das vor jedem Lauf selbst auf; von Hand braucht es
|
||||||
|
* den Aufruf nur, wer zwischendurch aufräumen will.
|
||||||
|
*
|
||||||
|
* Gelöscht wird alles, was am Testnutzer hängt – der Nutzer selbst bleibt
|
||||||
|
* stehen. Welcher das ist, sagt `E2E_USER` (sonst `e2e`); er muss den
|
||||||
|
* Anzeigenamen tragen, den `scripts/e2e-benutzer.php` setzt, sonst bricht das
|
||||||
|
* Skript ab.
|
||||||
|
*
|
||||||
|
* Mit `--probe` wird nur gezählt, was wegfiele; `--still` schweigt, solange
|
||||||
|
* nichts schiefgeht.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Finanzmanager\Config;
|
||||||
|
use Finanzmanager\Services\E2EAufraeumer;
|
||||||
|
|
||||||
|
Config::load();
|
||||||
|
|
||||||
|
$probe = in_array('--probe', $argv, true);
|
||||||
|
$still = in_array('--still', $argv, true);
|
||||||
|
|
||||||
|
$sage = static function (string $zeile) use ($still): void {
|
||||||
|
if (!$still) {
|
||||||
|
echo $zeile . PHP_EOL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$nutzer = E2EAufraeumer::testnutzer();
|
||||||
|
|
||||||
|
if ($nutzer === null) {
|
||||||
|
// Kein Testnutzer, kein Testbestand – das ist kein Fehler, sondern der
|
||||||
|
// Zustand vor dem ersten `scripts/e2e-benutzer.php`.
|
||||||
|
$sage('Kein Testnutzer vorhanden – nichts aufzuräumen.');
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!E2EAufraeumer::istTestnutzer($nutzer)) {
|
||||||
|
fwrite(STDERR, sprintf(
|
||||||
|
"Abbruch: '%s' ist nicht als Testnutzer ausgewiesen (Anzeigename '%s' statt '%s').\n"
|
||||||
|
. "Es wurde nichts gelöscht.\n",
|
||||||
|
(string)$nutzer['benutzername'],
|
||||||
|
(string)$nutzer['anzeigename'],
|
||||||
|
E2EAufraeumer::ANZEIGENAME
|
||||||
|
));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ergebnis = E2EAufraeumer::ausfuehren((int)$nutzer['id'], $probe);
|
||||||
|
$gesamt = array_sum($ergebnis);
|
||||||
|
|
||||||
|
if ($gesamt === 0) {
|
||||||
|
$sage('Der Testbestand ist schon leer.');
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sage(sprintf(
|
||||||
|
'%s: %d Zeilen aus %d Tabellen (Testnutzer %s).',
|
||||||
|
$probe ? 'Probelauf' : 'Aufgeräumt',
|
||||||
|
$gesamt,
|
||||||
|
count($ergebnis),
|
||||||
|
(string)$nutzer['benutzername']
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach ($ergebnis as $tabelle => $anzahl) {
|
||||||
|
$sage(sprintf(' %-24s %6d', $tabelle, $anzahl));
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
61
scripts/e2e-grundbestand.php
Executable file
61
scripts/e2e-grundbestand.php
Executable file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legt den Grundbestand an, auf dem die E2E-Tests aufsetzen.
|
||||||
|
*
|
||||||
|
* docker compose exec -u www-data php php scripts/e2e-grundbestand.php
|
||||||
|
*
|
||||||
|
* `tests/e2e/run.sh` ruft das nach dem Aufräumen selbst auf. Gedacht ist es für
|
||||||
|
* einen frisch aufgeräumten Bestand: Ein zweiter Aufruf legt alles noch einmal
|
||||||
|
* an, statt es zu ergänzen.
|
||||||
|
*
|
||||||
|
* Wie beim Aufräumen muss der Nutzer als Testnutzer ausgewiesen sein – sonst
|
||||||
|
* landet der Bestand in einem echten Zugang.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Finanzmanager\Config;
|
||||||
|
use Finanzmanager\Services\E2EAufraeumer;
|
||||||
|
use Finanzmanager\Services\E2EGrundbestand;
|
||||||
|
|
||||||
|
Config::load();
|
||||||
|
|
||||||
|
$still = in_array('--still', $argv, true);
|
||||||
|
|
||||||
|
$sage = static function (string $zeile) use ($still): void {
|
||||||
|
if (!$still) {
|
||||||
|
echo $zeile . PHP_EOL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$nutzer = E2EAufraeumer::testnutzer();
|
||||||
|
|
||||||
|
if ($nutzer === null) {
|
||||||
|
fwrite(STDERR, "Abbruch: Es gibt keinen Testnutzer. Zuerst scripts/e2e-benutzer.php.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!E2EAufraeumer::istTestnutzer($nutzer)) {
|
||||||
|
fwrite(STDERR, sprintf(
|
||||||
|
"Abbruch: '%s' ist nicht als Testnutzer ausgewiesen (Anzeigename '%s' statt '%s').\n"
|
||||||
|
. "Es wurde nichts angelegt.\n",
|
||||||
|
(string)$nutzer['benutzername'],
|
||||||
|
(string)$nutzer['anzeigename'],
|
||||||
|
E2EAufraeumer::ANZEIGENAME
|
||||||
|
));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ergebnis = E2EGrundbestand::anlegen((int)$nutzer['id']);
|
||||||
|
|
||||||
|
$sage(sprintf('Grundbestand angelegt (Testnutzer %s).', (string)$nutzer['benutzername']));
|
||||||
|
|
||||||
|
foreach ($ergebnis as $gattung => $anzahl) {
|
||||||
|
$sage(sprintf(' %-16s %6d', $gattung, $anzahl));
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
140
src/Services/E2EAufraeumer.php
Normal file
140
src/Services/E2EAufraeumer.php
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Finanzmanager\Services;
|
||||||
|
|
||||||
|
use Finanzmanager\Database;
|
||||||
|
use Finanzmanager\Models\Benutzer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Räumt den Datenbestand der E2E-Tests weg.
|
||||||
|
*
|
||||||
|
* Die Browser-Tests legen ihre Konten, Kategorien, Klassen und Buchungen bei
|
||||||
|
* jedem Lauf neu an – mit einer Zeitmarke im Namen, damit zwei Läufe sich nicht
|
||||||
|
* ins Gehege kommen. Weggeräumt hat sie bisher niemand: Nach ein paar Dutzend
|
||||||
|
* Läufen stehen im Kategoriefilter des Kontoblatts vierzig „E2E Bankprovision …“
|
||||||
|
* hintereinander, und kein Bildschirmfoto eines fehlgeschlagenen Tests ist mehr
|
||||||
|
* zu gebrauchen.
|
||||||
|
*
|
||||||
|
* Aufgeräumt wird **vor** dem Lauf, nicht danach: Ein abgebrochener Lauf
|
||||||
|
* hinterlässt sonst einen Bestand, an den niemand mehr denkt, und bis zum
|
||||||
|
* nächsten Lauf bleiben die Daten des letzten für die Fehlersuche stehen.
|
||||||
|
*
|
||||||
|
* 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; die Fremdschlüssel dagegen sagen genau, was zu
|
||||||
|
* diesem Nutzer gehört. Der Nutzer selbst bleibt stehen, sonst wäre der nächste
|
||||||
|
* Lauf ohne `scripts/e2e-benutzer.php` nicht anmeldefähig.
|
||||||
|
*/
|
||||||
|
class E2EAufraeumer
|
||||||
|
{
|
||||||
|
/** Der Anzeigename, den `scripts/e2e-benutzer.php` setzt. */
|
||||||
|
public const ANZEIGENAME = 'E2E-Testnutzer';
|
||||||
|
|
||||||
|
/** Der Benutzername, wenn E2E_USER nichts anderes sagt. */
|
||||||
|
public const BENUTZERNAME = 'e2e';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Tabellen mit `benutzer_id`, Kinder vor Eltern.
|
||||||
|
*
|
||||||
|
* Die Reihenfolge muss stimmen, obwohl die Fremdschlüssel ohnehin
|
||||||
|
* kaskadieren: Nur so meldet jede Tabelle die Zeilen, die sie selbst
|
||||||
|
* verloren hat, statt dass ein späterer Aufruf ins Leere läuft, weil ein
|
||||||
|
* früherer die Zeilen schon mitgenommen hat. Die Tabellen ohne eigene
|
||||||
|
* `benutzer_id` – buchung_splits, buchungsadressen, budget_positionen,
|
||||||
|
* bank_konten, kurse – hängen per CASCADE an einer von diesen.
|
||||||
|
*/
|
||||||
|
private const TABELLEN = [
|
||||||
|
'erinnerungen',
|
||||||
|
'monatsabschluesse',
|
||||||
|
'berichte',
|
||||||
|
'berichtsgruppen',
|
||||||
|
'budgets',
|
||||||
|
'abgleich_regeln',
|
||||||
|
'buchungsvorlagen',
|
||||||
|
'vertraege',
|
||||||
|
'sparziele',
|
||||||
|
'kredite',
|
||||||
|
'zahlungsauftraege',
|
||||||
|
'bank_umsaetze',
|
||||||
|
'bank_abrufe',
|
||||||
|
'bank_zugaenge',
|
||||||
|
'depot_buchungen',
|
||||||
|
'wertpapiere',
|
||||||
|
'regelmaessige_buchungen',
|
||||||
|
'buchungen',
|
||||||
|
'konten',
|
||||||
|
'kontengruppen',
|
||||||
|
'kategorien',
|
||||||
|
'klassen',
|
||||||
|
'adressen',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Der Testnutzer – oder null, wenn es ihn nicht gibt.
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>|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<string,mixed> $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<string,int> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
147
src/Services/E2EGrundbestand.php
Normal file
147
src/Services/E2EGrundbestand.php
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Finanzmanager\Services;
|
||||||
|
|
||||||
|
use Finanzmanager\Database;
|
||||||
|
use Finanzmanager\Mandant;
|
||||||
|
use Finanzmanager\Models\Depotbuchung;
|
||||||
|
use Finanzmanager\Models\Buchung;
|
||||||
|
use Finanzmanager\Models\Kategorie;
|
||||||
|
use Finanzmanager\Models\Klasse;
|
||||||
|
use Finanzmanager\Models\Konto;
|
||||||
|
use Finanzmanager\Models\Wertpapier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legt den Grundbestand an, auf dem die E2E-Tests aufsetzen.
|
||||||
|
*
|
||||||
|
* Ein Teil der Browser-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“ im Vermögensdiagramm eine Ebene
|
||||||
|
* tiefer führt. Solche Tests brauchen einen Bestand, legen ihn aber nicht selbst
|
||||||
|
* an – bis das Aufräumen dazukam, lebten sie von den Resten früherer Läufe.
|
||||||
|
* Genau das machte sie unzuverlässig: Was sie vorfanden, hing davon ab, wer
|
||||||
|
* zuletzt was laufen ließ.
|
||||||
|
*
|
||||||
|
* Der Bestand hier ist stattdessen festgelegt und wird vor jedem Lauf neu
|
||||||
|
* hergestellt. Die Zuschnitte sind nicht beliebig:
|
||||||
|
*
|
||||||
|
* - **Mehr Konten als Farbtöne.** `Vermoegensentwicklung::SERIEN` bestimmt, ab
|
||||||
|
* wann das Diagramm zusammenfasst; erst darüber gibt es „Übrige Konten“ und
|
||||||
|
* eine zweite Ebene zum Aufklappen.
|
||||||
|
* - **Buchungen über das ganze laufende Jahr.** Die Berichte laufen über
|
||||||
|
* „aktuelles Jahr“ und sollen bei monatlicher Aufteilung zwölf Spalten füllen.
|
||||||
|
* - **Ein Vorjahr.** Der Vergleichsbericht stellt zwei Zeiträume nebeneinander.
|
||||||
|
* - **Ein Depot mit Wertpapier und Geschäft.** `/wertpapiere` und
|
||||||
|
* `/wertpapiere/buchungen` sind sonst leere Listen ohne Zahlenspalten.
|
||||||
|
*/
|
||||||
|
class E2EGrundbestand
|
||||||
|
{
|
||||||
|
/** Am Präfix erkennt man die Zeilen wieder; [[E2EAufraeumer]] löscht sie. */
|
||||||
|
public const PRAEFIX = 'E2E Grundbestand';
|
||||||
|
|
||||||
|
/** Mehr als Vermoegensentwicklung::SERIEN, sonst fehlt „Übrige Konten“. */
|
||||||
|
public const KONTEN = Vermoegensentwicklung::SERIEN + 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stellt den Bestand her.
|
||||||
|
*
|
||||||
|
* @return array<string,int> 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,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
274
tests/41_E2EAufraeumenTest.php
Normal file
274
tests/41_E2EAufraeumenTest.php
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Finanzmanager\Database;
|
||||||
|
use Finanzmanager\Mandant;
|
||||||
|
use Finanzmanager\Models\Benutzer;
|
||||||
|
use Finanzmanager\Models\Buchung;
|
||||||
|
use Finanzmanager\Models\Kategorie;
|
||||||
|
use Finanzmanager\Models\Klasse;
|
||||||
|
use Finanzmanager\Models\Konto;
|
||||||
|
use Finanzmanager\Services\E2EAufraeumer;
|
||||||
|
use Finanzmanager\Services\E2EGrundbestand;
|
||||||
|
use Finanzmanager\Services\Vermoegensentwicklung;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix #64: Den E2E-Datenbestand aufräumen und neu aufbauen.
|
||||||
|
*
|
||||||
|
* Geprüft wird beides: dass wirklich alles wegkommt, was am Testnutzer hängt –
|
||||||
|
* einschließlich der Zeilen, die nur über einen Fremdschlüssel daran hängen –
|
||||||
|
* und dass ein zweiter Nutzer daneben unangetastet bleibt. Der zweite Teil ist
|
||||||
|
* der wichtigere: Das Skript läuft künftig automatisch, und wer es auf dem
|
||||||
|
* eigenen Rechner mit echten Daten anstößt, darf davon nichts merken.
|
||||||
|
*/
|
||||||
|
class E2EAufraeumenTest extends TestCase
|
||||||
|
{
|
||||||
|
protected string $testName = 'Test 41: E2E-Datenbestand aufräumen und aufbauen';
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$this->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'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
gerenderte Views, JavaScript. Rechen- und Model-Logik gehört in die PHP-Suite
|
||||||
(`tests/NN_*.php`) – schneller und isoliert.
|
(`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
|
## Gemeinsame Helfer
|
||||||
|
|
||||||
`specs/hilfen.js` liegt neben den Specs, endet aber nicht auf `.spec.js` und wird
|
`specs/hilfen.js` liegt neben den Specs, endet aber nicht auf `.spec.js` und wird
|
||||||
|
|
|
||||||
|
|
@ -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 \
|
docker image inspect "$IMAGE" >/dev/null 2>&1 \
|
||||||
|| skip "Playwright-Image $IMAGE nicht vorhanden (docker pull $IMAGE)"
|
|| 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.
|
# Zugangsdaten des Testnutzers durchreichen; der Runner kennt nur BASE_URL.
|
||||||
cd "$RUNNER_DIR"
|
cd "$RUNNER_DIR"
|
||||||
TEST_DIR="$TEST_DIR" BASE_URL="$BASE_URL" exec docker compose run --rm \
|
TEST_DIR="$TEST_DIR" BASE_URL="$BASE_URL" exec docker compose run --rm \
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue