From ed465333e4c611f3567779a6ad991411c66c8eaa Mon Sep 17 00:00:00 2001 From: bruno Date: Mon, 20 Jul 2026 08:07:22 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20v4.0.2=20=E2=80=94=20qualit=C3=A9=20&?= =?UTF-8?q?=20robustesse=20(session=20expiry=20UX,=20validation,=20mobile,?= =?UTF-8?q?=20tests)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Session expiry: redirects ajoutent ?expired=1 → bannière "Session expired" sur login - Page titles: titre vide → 'Untitled' par défaut (au lieu de chaîne vide) - Error handling: try/catch dans create_page avec message user-friendly (500) - Mobile responsive: sidebar slide-in, modales centrées, landing page adaptative - 10 nouveaux tests de non-régression: landing, register, 404, validation, duplicate - 143 tests passent (133 + 10) --- app/routers/auth.py | 3 ++ app/routers/board.py | 40 ++++++++++-------- app/routers/dashboard.py | 4 +- app/templates/base.html | 83 +++++++++++++++++++++++++++++++++++++ tests/test_app.py | 89 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 200 insertions(+), 19 deletions(-) diff --git a/app/routers/auth.py b/app/routers/auth.py index 3f09d1d..de9ffcd 100644 --- a/app/routers/auth.py +++ b/app/routers/auth.py @@ -55,6 +55,7 @@ body{background:#191919;color:#fff;font-family:-apple-system,BlinkMacSystemFont, +
@@ -76,6 +77,8 @@ body{background:#191919;color:#fff;font-family:-apple-system,BlinkMacSystemFont, diff --git a/tests/test_app.py b/tests/test_app.py index 547596a..0a2e3a1 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1914,3 +1914,92 @@ def test_page_renders_breadcrumb_data(client): assert 'id="fd-breadcrumb-data"' in resp.text assert '"Home"' in resp.text assert "fdBreadcrumb" in resp.text + + +# ═══════════ v4.0.2 — Regression tests (critical paths) ═══════════ + + +def test_landing_page_no_auth(client): + """Visiting / without auth shows the landing page.""" + resp = client.get("/", follow_redirects=False) + assert resp.status_code == 200 + assert "FlowDeck" in resp.text + assert "Get started free" in resp.text or "Get started" in resp.text + + +def test_register_page_get(client): + """GET /auth/register shows the registration form.""" + resp = client.get("/auth/register", follow_redirects=False) + assert resp.status_code == 200 + assert "register" in resp.text.lower() + + +def test_login_page_shows_expired_banner(client): + """Login page with ?expired=1 shows session expired message.""" + resp = client.get("/auth/login?provider=local&expired=1", follow_redirects=False) + assert resp.status_code == 200 + assert "expired" in resp.text.lower() + + +def test_create_page_defaults_to_untitled(client): + """Creating a page with empty title defaults to 'Untitled'.""" + resp = client.post("/board/api/pages?title=§ion=Private", follow_redirects=False) + assert resp.status_code == 200 + data = resp.json() + assert data["title"] == "Untitled" + + +def test_styled_404_page(client): + """Unknown routes return a styled 404 HTML page.""" + resp = client.get("/this-does-not-exist-xyz", follow_redirects=False) + assert resp.status_code == 404 + assert "404" in resp.text + assert "FlowDeck" in resp.text + + +def test_api_404_returns_json(client): + """Unknown API routes return JSON, not HTML.""" + resp = client.get("/api/does-not-exist", follow_redirects=False) + assert resp.status_code == 404 + data = resp.json() + assert "detail" in data + + +def test_login_validation_empty_fields(client): + """Login with empty fields returns 400 error.""" + resp = client.post("/auth/local-login", json={"email": "", "password": ""}) + assert resp.status_code == 400 + data = resp.json() + assert "error" in data + + +def test_register_validation_short_password(client): + """Registration with short password returns 400.""" + resp = client.post("/auth/register", json={ + "email": "test@test.com", "password": "ab", "name": "Test" + }) + assert resp.status_code == 400 + + +def test_register_duplicate_rejected(client): + """Duplicate registration returns 409.""" + # Register first time + r1 = client.post("/auth/register", json={ + "email": "duptest2", "password": "password123", "name": "Dup" + }) + assert r1.status_code == 200 + # Second registration with same email should fail + r2 = client.post("/auth/register", json={ + "email": "duptest2", "password": "password123", "name": "Dup2" + }) + assert r2.status_code == 409 + assert "already exists" in r2.json().get("error", "").lower() + + +def test_session_expired_redirect(client): + """Unauthenticated access to protected page redirects with expired param.""" + resp = client.get("/workspaces", follow_redirects=False) + assert resp.status_code == 302 + location = resp.headers.get("location", "") + assert "login" in location + assert "expired=1" in location