Wizard-Texte, Admin-Onboarding ueberspringen, kompakte Set-Zeile mobil
Image bauen und in die Registry schieben / build (push) Successful in 6s
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:
1 parent
135425c781
commit
6d57200032
5 files changed
+88
-53
No files matched your search
+27
-21
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user