feat: v4.0.2 — qualité & robustesse (session expiry UX, validation, mobile, tests)

- 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)
This commit is contained in:
2026-07-20 08:07:22 -04:00
parent a5831456e1
commit ed465333e4
5 changed files with 200 additions and 19 deletions
+89
View File
@@ -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=&section=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": "[email protected]", "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