Merge pull request 'Fix n.n.: E2E-Läufe sichern Einstellungen, Kippschalter statt Ankreuzfeldern' (#92) from fds2610-bot/Finanzmanager:main into main
Reviewed-on: https://codeberg.org/fds2610/Finanzmanager/pulls/92
This commit is contained in:
commit
c05537d1d0
9 changed files with 351 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -18,3 +18,4 @@ tests/e2e/node_modules/
|
||||||
tests/e2e/playwright-report/
|
tests/e2e/playwright-report/
|
||||||
tests/e2e/test-results/
|
tests/e2e/test-results/
|
||||||
tests/e2e/.auth/
|
tests/e2e/.auth/
|
||||||
|
/data/e2e/
|
||||||
|
|
|
||||||
18
Changes.md
18
Changes.md
|
|
@ -1,5 +1,23 @@
|
||||||
# Änderungen
|
# Änderungen
|
||||||
|
|
||||||
|
## E2E-Läufe lassen die Einstellungen unverändert (29.09.2026)
|
||||||
|
|
||||||
|
- Die Browser-Tests laufen gegen die echte Instanz; der Bargeld-Test hatte dabei die Adresse
|
||||||
|
des Bargeld-Tools geleert. `tests/e2e/run.sh` sichert jetzt die ganze Tabelle
|
||||||
|
`einstellungen` vor dem Lauf und stellt sie danach wieder her (auch bei Abbruch mit
|
||||||
|
Strg+C). Eine nach hartem Abbruch liegengebliebene Sicherung wird vor dem nächsten Lauf
|
||||||
|
eingespielt.
|
||||||
|
- Neu: `Services/E2EEinstellungen`, `scripts/e2e-einstellungen.php sichern|wiederherstellen`,
|
||||||
|
Test 48. Die Sicherung liegt unter `data/e2e/` (nicht im Repository).
|
||||||
|
|
||||||
|
## Kippschalter statt Ankreuzfeldern (29.09.2026)
|
||||||
|
|
||||||
|
- Alle Ankreuzfelder erscheinen als Kippschalter im blauen Design des Projekts: aus =
|
||||||
|
graue Fläche mit ✕, an = Akzentfarbe mit Häkchen (helles und dunkles Thema). Reine CSS-
|
||||||
|
Änderung in `public/static/app.css`; die Elemente bleiben echte Ankreuzfelder.
|
||||||
|
- Ausgenommen ist die Zeilenauswahl in den Listen (Kontoblatt, Depotbuchungen,
|
||||||
|
Umsätze inkl. „alle wählen“).
|
||||||
|
|
||||||
## Regeln: Summe der Anteile in den Splittabellen (29.09.2026)
|
## Regeln: Summe der Anteile in den Splittabellen (29.09.2026)
|
||||||
|
|
||||||
- Die Spalte „Anteil %“ heißt in den Splittabellen der Regeln nur noch „Anteil“, da die
|
- Die Spalte „Anteil %“ heißt in den Splittabellen der Regeln nur noch „Anteil“, da die
|
||||||
|
|
|
||||||
|
|
@ -2314,3 +2314,66 @@ table.liste tr.luecke td {
|
||||||
.protokolleintrag p { margin: .4rem 0; }
|
.protokolleintrag p { margin: .4rem 0; }
|
||||||
.protokolleintrag summary { cursor: pointer; font-size: .88rem; color: var(--text-gedaempft); }
|
.protokolleintrag summary { cursor: pointer; font-size: .88rem; color: var(--text-gedaempft); }
|
||||||
.protokolleintrag .protokolltext { max-height: 22rem; overflow: auto; word-break: break-all; }
|
.protokolleintrag .protokolltext { max-height: 22rem; overflow: auto; word-break: break-all; }
|
||||||
|
|
||||||
|
/* Kippschalter statt Ankreuzfeld. Gilt für jedes Ankreuzfeld; ausgenommen ist nur die
|
||||||
|
Zeilenauswahl in den Listen (Kopf-Ankreuzfeld „alle wählen“ und die Auswahl je Buchung
|
||||||
|
bzw. Umsatz), wo ein Schalter je Zeile die Tabelle aufblähen würde. Das Element bleibt
|
||||||
|
ein echtes Ankreuzfeld: Tastatur, Formularversand und Skripte ändern sich nicht. */
|
||||||
|
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]) {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
position: relative;
|
||||||
|
flex: none;
|
||||||
|
width: 2.6rem;
|
||||||
|
height: 1.4rem;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: var(--rand-kraeftig);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right .5rem center;
|
||||||
|
background-size: .6rem;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.5 1.5l7 7m0-7l-7 7' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
|
||||||
|
box-shadow: inset 0 1px 2px rgba(16, 24, 40, .18);
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: middle;
|
||||||
|
transition: background-color .15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"])::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: .15rem;
|
||||||
|
left: .15rem;
|
||||||
|
width: 1.1rem;
|
||||||
|
height: 1.1rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(#ffffff, #eceff3);
|
||||||
|
box-shadow: 0 1px 3px rgba(16, 24, 40, .35);
|
||||||
|
transition: transform .15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):checked {
|
||||||
|
background-color: var(--akzent);
|
||||||
|
background-position: left .5rem center;
|
||||||
|
background-size: .7rem;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.3 5.4l2.5 2.5 5-5.6' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):checked::before {
|
||||||
|
transform: translateX(1.2rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):focus-visible {
|
||||||
|
outline: 2px solid var(--akzent);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:not(.alle-waehlen):not([name="buchungen[]"]):not([name="umsaetze[]"]):disabled {
|
||||||
|
opacity: .5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="checkbox"]::before { transition: none; }
|
||||||
|
}
|
||||||
|
|
|
||||||
52
scripts/e2e-einstellungen.php
Normal file
52
scripts/e2e-einstellungen.php
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sichert die Programmeinstellungen vor einem E2E-Lauf und stellt sie danach
|
||||||
|
* wieder her.
|
||||||
|
*
|
||||||
|
* docker compose exec -T -u www-data php php scripts/e2e-einstellungen.php sichern
|
||||||
|
* docker compose exec -T -u www-data php php scripts/e2e-einstellungen.php wiederherstellen
|
||||||
|
*
|
||||||
|
* `tests/e2e/run.sh` ruft beides selbst auf. `--still` schweigt, solange
|
||||||
|
* nichts schiefgeht.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Finanzmanager\Config;
|
||||||
|
use Finanzmanager\Services\E2EEinstellungen;
|
||||||
|
|
||||||
|
Config::load();
|
||||||
|
|
||||||
|
$still = in_array('--still', $argv, true);
|
||||||
|
$aktion = $argv[1] ?? '';
|
||||||
|
$pfad = E2EEinstellungen::standardPfad();
|
||||||
|
|
||||||
|
$sage = static function (string $zeile) use ($still): void {
|
||||||
|
if (!$still) {
|
||||||
|
echo $zeile . PHP_EOL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch ($aktion) {
|
||||||
|
case 'sichern':
|
||||||
|
$anzahl = E2EEinstellungen::sichern($pfad);
|
||||||
|
$sage($anzahl === null
|
||||||
|
? 'Sicherung aus einem früheren Lauf vorhanden – bleibt stehen.'
|
||||||
|
: sprintf('%d Einstellungen gesichert.', $anzahl));
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
case 'wiederherstellen':
|
||||||
|
$anzahl = E2EEinstellungen::wiederherstellen($pfad);
|
||||||
|
$sage($anzahl === null
|
||||||
|
? 'Keine Sicherung vorhanden – nichts wiederherzustellen.'
|
||||||
|
: sprintf('%d Einstellungen wiederhergestellt.', $anzahl));
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
fwrite(STDERR, "Aufruf: e2e-einstellungen.php sichern|wiederherstellen [--still]\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
95
src/Services/E2EEinstellungen.php
Normal file
95
src/Services/E2EEinstellungen.php
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Finanzmanager\Services;
|
||||||
|
|
||||||
|
use Finanzmanager\Database;
|
||||||
|
use Finanzmanager\Models\Einstellung;
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sichert die Programmeinstellungen vor einem E2E-Lauf und stellt sie danach
|
||||||
|
* wieder her.
|
||||||
|
*
|
||||||
|
* Die Browser-Tests laufen gegen die echte Instanz und speichern dabei
|
||||||
|
* Formulare des Einstellungsdialogs – der Bargeld-Test leerte so die Adresse
|
||||||
|
* des Bargeld-Tools. Statt jedem Test das Aufräumen einzeln beizubringen,
|
||||||
|
* gilt: Was in `einstellungen` steht, ist nach dem Lauf wieder so wie davor.
|
||||||
|
*
|
||||||
|
* Gesichert wird die ganze Tabelle, nicht eine Liste bekannter Schlüssel –
|
||||||
|
* ein neuer Test mit einer neuen Einstellung braucht so keine Pflege.
|
||||||
|
*/
|
||||||
|
class E2EEinstellungen
|
||||||
|
{
|
||||||
|
/** Wohin die Sicherung geschrieben wird. */
|
||||||
|
public static function standardPfad(): string
|
||||||
|
{
|
||||||
|
return dirname(__DIR__, 2) . '/data/e2e/einstellungen.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Tabelle in eine Datei schreiben.
|
||||||
|
*
|
||||||
|
* Eine vorhandene Sicherung bleibt stehen: Sie stammt aus einem
|
||||||
|
* abgebrochenen Lauf und hält den Stand, der wirklich der echte ist.
|
||||||
|
*
|
||||||
|
* @return int|null Anzahl gesicherter Zeilen, null wenn die Sicherung schon da war
|
||||||
|
*/
|
||||||
|
public static function sichern(string $pfad): ?int
|
||||||
|
{
|
||||||
|
if (is_file($pfad)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$zeilen = Database::fetchAll(
|
||||||
|
'SELECT schluessel, wert, bereich, geaendert_am FROM einstellungen ORDER BY schluessel'
|
||||||
|
);
|
||||||
|
|
||||||
|
$verzeichnis = dirname($pfad);
|
||||||
|
if (!is_dir($verzeichnis) && !mkdir($verzeichnis, 0775, true) && !is_dir($verzeichnis)) {
|
||||||
|
throw new RuntimeException('Verzeichnis nicht anlegbar: ' . $verzeichnis);
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = json_encode($zeilen, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
|
||||||
|
if (file_put_contents($pfad, $json, LOCK_EX) === false) {
|
||||||
|
throw new RuntimeException('Sicherung nicht schreibbar: ' . $pfad);
|
||||||
|
}
|
||||||
|
chmod($pfad, 0600);
|
||||||
|
|
||||||
|
return count($zeilen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Tabelle auf den gesicherten Stand zurücksetzen und die Sicherung
|
||||||
|
* löschen. Zeilen, die der Lauf angelegt hat, verschwinden wieder.
|
||||||
|
*
|
||||||
|
* @return int|null Anzahl wiederhergestellter Zeilen, null wenn es keine Sicherung gibt
|
||||||
|
*/
|
||||||
|
public static function wiederherstellen(string $pfad): ?int
|
||||||
|
{
|
||||||
|
if (!is_file($pfad)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$zeilen = json_decode((string)file_get_contents($pfad), true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
if (!is_array($zeilen)) {
|
||||||
|
throw new RuntimeException('Sicherung unlesbar: ' . $pfad);
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::transaktion(static function () use ($zeilen): void {
|
||||||
|
Database::execute('DELETE FROM einstellungen');
|
||||||
|
foreach ($zeilen as $z) {
|
||||||
|
Database::execute(
|
||||||
|
'INSERT INTO einstellungen (schluessel, wert, bereich, geaendert_am) VALUES (?, ?, ?, ?)',
|
||||||
|
[$z['schluessel'], $z['wert'], $z['bereich'], $z['geaendert_am']]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Einstellung::cacheLeeren();
|
||||||
|
|
||||||
|
unlink($pfad);
|
||||||
|
|
||||||
|
return count($zeilen);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
tests/48_E2EEinstellungenTest.php
Normal file
52
tests/48_E2EEinstellungenTest.php
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Finanzmanager\Database;
|
||||||
|
use Finanzmanager\Models\Einstellung;
|
||||||
|
use Finanzmanager\Services\E2EEinstellungen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Einstellungen überleben einen E2E-Lauf: Was der Lauf ändert, anlegt oder
|
||||||
|
* löscht, ist nach dem Wiederherstellen wieder weg. Anlass: Der Bargeld-Test
|
||||||
|
* leerte die Adresse des Bargeld-Tools in der echten Instanz.
|
||||||
|
*/
|
||||||
|
class E2EEinstellungenTest extends TestCase
|
||||||
|
{
|
||||||
|
protected string $testName = 'Test 48: E2E-Einstellungen sichern und wiederherstellen';
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$pfad = $this->tempPfad('.json');
|
||||||
|
Einstellung::set('e2e_probe_url', 'https://kasse.example.net', 'bargeld');
|
||||||
|
Einstellung::set('e2e_probe_tage', '10', 'bargeld');
|
||||||
|
|
||||||
|
$vorher = Database::fetchAll('SELECT * FROM einstellungen ORDER BY schluessel');
|
||||||
|
|
||||||
|
$anzahl = E2EEinstellungen::sichern($pfad);
|
||||||
|
$this->assertEquals(count($vorher), $anzahl, 'Alle Zeilen werden gesichert');
|
||||||
|
|
||||||
|
// Der Lauf ändert, leert, löscht und legt an.
|
||||||
|
Einstellung::set('e2e_probe_url', '', 'bargeld');
|
||||||
|
Einstellung::set('e2e_probe_tage', '99', 'bargeld');
|
||||||
|
Einstellung::set('e2e_probe_neu', 'x', 'allgemein');
|
||||||
|
Database::execute("DELETE FROM einstellungen WHERE bereich = 'darstellung'");
|
||||||
|
|
||||||
|
$this->assertNull(E2EEinstellungen::sichern($pfad), 'Eine vorhandene Sicherung wird nicht überschrieben');
|
||||||
|
|
||||||
|
$wieder = E2EEinstellungen::wiederherstellen($pfad);
|
||||||
|
$this->assertEquals(count($vorher), $wieder, 'Alle Zeilen kommen zurück');
|
||||||
|
Einstellung::cacheLeeren();
|
||||||
|
|
||||||
|
$this->assertEquals('https://kasse.example.net', Einstellung::get('e2e_probe_url'), 'Die geleerte Adresse ist wieder da');
|
||||||
|
$this->assertEquals('10', Einstellung::get('e2e_probe_tage'), 'Der geänderte Wert ist zurückgesetzt');
|
||||||
|
$this->assertNull(Einstellung::get('e2e_probe_neu'), 'Vom Lauf angelegte Einstellungen verschwinden');
|
||||||
|
$this->assertEquals(
|
||||||
|
$vorher,
|
||||||
|
Database::fetchAll('SELECT * FROM einstellungen ORDER BY schluessel'),
|
||||||
|
'Die Tabelle ist Zeile für Zeile wie vorher, einschließlich Bereich und Änderungszeit'
|
||||||
|
);
|
||||||
|
$this->assert(!is_file($pfad), 'Die Sicherung ist danach gelöscht');
|
||||||
|
$this->assertNull(E2EEinstellungen::wiederherstellen($pfad), 'Ohne Sicherung geschieht nichts');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,12 @@ 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.
|
||||||
|
|
||||||
|
## Einstellungen
|
||||||
|
|
||||||
|
`run.sh` sichert die Tabelle `einstellungen` vor dem Lauf und stellt sie danach wieder
|
||||||
|
her (`scripts/e2e-einstellungen.php`). Specs dürfen Einstellungen also frei ändern, müssen
|
||||||
|
sie aber nicht selbst zurücksetzen.
|
||||||
|
|
||||||
## Aufräumen
|
## Aufräumen
|
||||||
|
|
||||||
Jeder Lauf legt Konten, Kategorien, Klassen und Buchungen neu an – mit einer
|
Jeder Lauf legt Konten, Kategorien, Klassen und Buchungen neu an – mit einer
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,23 @@ if [ "${E2E_KEIN_AUFRAEUMEN:-0}" != "1" ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Die Tests laufen gegen die echte Instanz und speichern dabei Formulare des
|
||||||
|
# Einstellungsdialogs. Deshalb: Einstellungen sichern, nach dem Lauf – auch nach
|
||||||
|
# einem Abbruch – wiederherstellen. Bleibt nach einem harten Abbruch (kill -9) eine
|
||||||
|
# Sicherung liegen, spielt der nächste Lauf sie zuerst ein; sie hält den echten Stand.
|
||||||
|
PROJEKT=$(CDPATH= cd -- "$TEST_DIR/../.." && pwd)
|
||||||
|
einstellungen() { (cd "$PROJEKT" && docker compose exec -T -u www-data php php scripts/e2e-einstellungen.php "$1" --still); }
|
||||||
|
|
||||||
|
einstellungen wiederherstellen \
|
||||||
|
|| echo "WARNUNG: Alte Einstellungssicherung nicht einspielbar." >&2
|
||||||
|
einstellungen sichern \
|
||||||
|
|| echo "WARNUNG: Einstellungen nicht gesichert — der Lauf kann sie verändern." >&2
|
||||||
|
trap 'einstellungen wiederherstellen || echo "WARNUNG: Einstellungen nicht wiederhergestellt (scripts/e2e-einstellungen.php wiederherstellen)." >&2' EXIT
|
||||||
|
trap 'exit 130' INT TERM
|
||||||
|
|
||||||
# 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" docker compose run --rm \
|
||||||
${E2E_USER:+-e E2E_USER="$E2E_USER"} \
|
${E2E_USER:+-e E2E_USER="$E2E_USER"} \
|
||||||
${E2E_PASSWORD:+-e E2E_PASSWORD="$E2E_PASSWORD"} \
|
${E2E_PASSWORD:+-e E2E_PASSWORD="$E2E_PASSWORD"} \
|
||||||
playwright
|
playwright
|
||||||
|
|
|
||||||
49
tests/e2e/specs/kippschalter.spec.js
Normal file
49
tests/e2e/specs/kippschalter.spec.js
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
// @ts-check
|
||||||
|
const { test, expect } = require('@playwright/test')
|
||||||
|
|
||||||
|
const BENUTZER = process.env.E2E_USER || 'e2e'
|
||||||
|
const PASSWORT = process.env.E2E_PASSWORD || 'e2e-testpasswort'
|
||||||
|
|
||||||
|
async function anmelden(page) {
|
||||||
|
await page.goto('/login')
|
||||||
|
await page.fill('#benutzername', BENUTZER)
|
||||||
|
await page.fill('#passwort', PASSWORT)
|
||||||
|
await page.click('button[type="submit"]')
|
||||||
|
await expect(page).toHaveURL(/\/$/)
|
||||||
|
}
|
||||||
|
|
||||||
|
test.describe('Kippschalter', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await anmelden(page)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Ankreuzfelder erscheinen als Schalter und lassen sich umschalten', async ({ page }) => {
|
||||||
|
await page.goto('/konten/neu')
|
||||||
|
const schalter = page.locator('input[name="in_summe"]')
|
||||||
|
|
||||||
|
const aussehen = () => schalter.evaluate((el) => {
|
||||||
|
const stil = getComputedStyle(el)
|
||||||
|
return { breite: parseFloat(stil.width), hintergrund: stil.backgroundColor, appearance: stil.appearance }
|
||||||
|
})
|
||||||
|
|
||||||
|
const vorher = await aussehen()
|
||||||
|
expect(vorher.appearance).toBe('none')
|
||||||
|
expect(vorher.breite).toBeGreaterThan(30)
|
||||||
|
|
||||||
|
const war = await schalter.isChecked()
|
||||||
|
await schalter.click()
|
||||||
|
expect(await schalter.isChecked()).toBe(!war)
|
||||||
|
// Die Farbe läuft über eine kurze Übergangsanimation.
|
||||||
|
await expect.poll(async () => (await aussehen()).hintergrund).not.toBe(vorher.hintergrund)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Zeilenauswahl in den Listen bleibt ein gewöhnliches Ankreuzfeld', async ({ page }) => {
|
||||||
|
await page.goto('/banking/umsaetze')
|
||||||
|
const auswahl = page.locator('input.alle-waehlen').first()
|
||||||
|
if (await auswahl.count() === 0) {
|
||||||
|
test.skip(true, 'keine Umsätze vorhanden')
|
||||||
|
}
|
||||||
|
const appearance = await auswahl.evaluate((el) => getComputedStyle(el).appearance)
|
||||||
|
expect(appearance).not.toBe('none')
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Add table
Reference in a new issue