Wizard-Texte, Admin-Onboarding ueberspringen, kompakte Set-Zeile mobil
Image bauen und in die Registry schieben / build (push) Successful in 6s

- Wizard: Sprach-Hinweis gekuerzt, Repo-Link nur beim Erst-Setup (nicht
  im Onboarding), Hinweis 'erster Benutzer wird Administrator'
- Erster Benutzer (Admin) ist automatisch onboarded und erbt die
  festgelegten Sprache/Design-Einstellungen (kein erneuter Wizard);
  Einstellungen werden nach Admin-Anlage sofort frisch gerendert
- Set-Zeile mobil-tauglich: nowrap, width 100%, kg/reps-Inputs flexibel
  (flex 1, min-width 0), Einheit kompakt im Feld, 'S1' statt 'Set 1',
  Reset als SVG-Icon, kleinere Buttons - kein horizontales Scrollen
- Tests: 169 Checks gruen (39+18+52+32+28)
This commit is contained in:
AI-Agent committed 2026-10-02 20:26:09 +00:00
1 parent 135425c781
commit 6d57200032
5 files changed
+88 -53

No files matched your search

+27 -21
View File
@@ -126,6 +126,8 @@ check("Setup: Sprache kommt zuerst",
const reg = await api("POST", "/api/register", { username: "alex", password: "geheim" });
check("API: Register", reg.status === 200 && !!reg.body.token, reg.body);
// Admin ist automatisch eingestellt (kein Onboarding), Sprache fuer Tests auf Deutsch
await api("PUT", "/api/settings", { language: "de" }, reg.body.token);
// --- Szenario 1: ohne Token -> Auth-Gate, Inline-Fehler, Login in-place ---
const winNoToken = await loadApp(html, appJs, null);
@@ -137,23 +139,23 @@ check("Setup: Sprache kommt zuerst",
!!gate().querySelector('input#auth-user')
&& !!gate().querySelector('input#auth-pass')
&& !!gate().querySelector(".btn-primary"));
check("ohne Token: Login-Screen in Server-Sprache (en)",
check("ohne Token: Login-Screen in Server-Sprache",
Array.from(gate().querySelectorAll(".btn"))
.some(b => b.textContent === "Log in")
&& gate().querySelector(".auth-sub").textContent.includes("Log in to see"));
.some(b => b.textContent === "Anmelden")
&& gate().querySelector(".auth-sub").textContent.includes("Anmelden, um deine Trainingsdaten zu sehen"));
// falsches Kennwort -> Inline-Fehler
gate().querySelector('input#auth-user').value = "alex";
gate().querySelector('input#auth-pass').value = "falsch";
Array.from(gate().querySelectorAll(".btn")).find(b => b.textContent === "Log in").click();
Array.from(gate().querySelectorAll(".btn")).find(b => b.textContent === "Anmelden").click();
await sleep(500);
const authErr = gate().querySelector(".auth-error");
check("ohne Token: Inline-Fehler bei falschem Kennwort",
authErr && !authErr.hidden
&& authErr.textContent.includes("Incorrect username or password"),
&& authErr.textContent.includes("Kennwort inkorrekt"),
authErr && authErr.textContent);
// korrektes Kennwort -> Login wechselt OHNE Reload in-place
gate().querySelector('input#auth-pass').value = "geheim";
Array.from(gate().querySelectorAll(".btn")).find(b => b.textContent === "Log in").click();
Array.from(gate().querySelectorAll(".btn")).find(b => b.textContent === "Anmelden").click();
let loggedIn = false;
for (let i = 0; i < 60; i++) {
const og = winNoToken.document.querySelector("#setup-gate");
@@ -169,21 +171,8 @@ check("Setup: Sprache kommt zuerst",
await sleep(100);
}
check("Login: wechselt ohne Reload in den eingeloggten Zustand", loggedIn);
// Onboarding abschliessen (im selben Fenster)
const ogate = () => winNoToken.document.querySelector("#setup-gate");
if (ogate() && !ogate().hidden) {
Array.from(ogate().querySelectorAll(".day-btn"))
.find(b => b.textContent === "German").click();
await sleep(150);
Array.from(ogate().querySelectorAll(".wizard-nav .btn"))
.find(b => b.textContent === "Weiter").click();
await sleep(200);
Array.from(ogate().querySelectorAll(".wizard-nav .btn"))
.find(b => b.textContent === "Einrichtung abschließen").click();
await sleep(400);
}
check("Login: Onboarding abgeschlossen, Heute-Ansicht sichtbar",
ogate() && ogate().hidden
check("Login: Admin ohne Onboarding direkt in Heute-Ansicht",
winNoToken.document.querySelector("#setup-gate").hidden
&& winNoToken.document.querySelectorAll(".act-card").length === 3);
check("Login: kein Auth-Gate mehr",
winNoToken.document.querySelector("#auth-gate").hidden);
@@ -242,6 +231,23 @@ check("Setup: Sprache kommt zuerst",
Array.from(rows()[0].querySelectorAll(".btn"))
.some(b => b.textContent === "Kennwort ändern"));
// Berta (normaler User) durchlaeuft einmaliges Onboarding (Sprache zuerst)
const loginB = await api("POST", "/api/login",
{ username: "berta", password: "geheim" });
const winB = await loadApp(html, appJs, loginB.body.token);
await sleep(1200);
const bg = () => winB.document.querySelector("#setup-gate");
check("Berta: Onboarding erscheint (einmalig)",
bg() && !bg().hidden);
Array.from(bg().querySelectorAll(".wizard-nav .btn"))
.find(b => b.textContent === "Weiter").click();
await sleep(150);
Array.from(bg().querySelectorAll(".wizard-nav .btn"))
.find(b => b.textContent === "Einrichtung abschließen").click();
await sleep(400);
check("Berta: nach Onboarding Heute-Ansicht",
bg().hidden && winB.document.querySelectorAll(".act-card").length === 3);
// --- Szenario 4: API-Login-Faelle --------------------------------------
check("API: Login mit falschem Passwort -> 401",
(await api("POST", "/api/login", { username: "alex", password: "falsch" })).status === 401);