Build the core user-facing experience with admin login (bcrypt + signed session cookies), profile switcher, workout day viewer with warmups and exercise cards, and HTMX-powered exercise browser with search/filter. - AuthService with bcrypt password verification and itsdangerous session tokens - Auth dependency redirects to /login (303) for unauthenticated requests - NavContextMiddleware injects admin/profiles/active_profile into all templates - Profile management (list, switch, edit) with cookie-based active profile - Workout day viewer shows warmups + exercises + per-user programming targets - Exercise browser with HTMX filter dropdowns (no page reloads) - Flash message partial for success/error feedback - 12 new tests (66 total passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
"""Tests for login/logout routes."""
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
class TestLoginPage:
|
|
"""Tests for GET /login."""
|
|
|
|
def test_login_page_returns_200(self, client: TestClient) -> None:
|
|
"""GET /login should render the login form."""
|
|
response = client.get("/login")
|
|
assert response.status_code == 200
|
|
assert "Login" in response.text
|
|
|
|
def test_login_page_has_form(self, client: TestClient) -> None:
|
|
"""GET /login should contain a login form with username and password."""
|
|
response = client.get("/login")
|
|
assert 'name="username"' in response.text
|
|
assert 'name="password"' in response.text
|
|
|
|
|
|
class TestLoginPost:
|
|
"""Tests for POST /login."""
|
|
|
|
def test_login_invalid_credentials_shows_error(self, client: TestClient) -> None:
|
|
"""POST /login with wrong credentials should show error message."""
|
|
response = client.post(
|
|
"/login",
|
|
data={"username": "wrong", "password": "wrong"},
|
|
follow_redirects=False,
|
|
)
|
|
# Should re-render login page with error or redirect back
|
|
assert response.status_code in (200, 303)
|
|
|
|
|
|
class TestLogout:
|
|
"""Tests for GET /logout."""
|
|
|
|
def test_logout_redirects_to_login(self, client: TestClient) -> None:
|
|
"""GET /logout should clear session and redirect to login."""
|
|
response = client.get("/logout", follow_redirects=False)
|
|
assert response.status_code in (303, 307)
|
|
assert "/login" in response.headers.get("location", "")
|