"""Integration tests for HTTP routes.""" from datetime import date class TestDashboardRoute: def test_dashboard_requires_login(self, client): resp = client.get("/dashboard", follow_redirects=True) assert b"Log In" in resp.data def test_dashboard_shows_today(self, auth_client): resp = auth_client.get("/dashboard") assert resp.status_code == 200 assert b"Today" in resp.data def test_dashboard_renders_users(self, auth_client): resp = auth_client.get("/dashboard") # bob and alice were registered in the same household assert b"alice" in resp.data assert b"bob" in resp.data assert b"Lunch" in resp.data assert b"Dinner" in resp.data def test_dashboard_hides_other_households(self, auth_client): """Bob should NOT see users from other households.""" # Register another user in a different household auth_client.get("/logout") auth_client.post("/register", data={ "username": "stranger", "password": "stranger1", "confirm": "stranger1", "household_action": "create", "new_household_name": "Stranger House", }) # Log back in as bob (Test Household) auth_client.get("/logout") auth_client.post("/login", data={ "username": "bob", "password": "bobpass", }) resp = auth_client.get("/dashboard") assert resp.status_code == 200 assert b"stranger" not in resp.data assert b"Stranger House" not in resp.data class TestRespondRoute: def test_respond_sets_status(self, auth_client): resp = auth_client.post("/respond", data={ "meal_type": "lunch", "status": "yes", }, follow_redirects=True) assert resp.status_code == 200 assert b"Home" in resp.data def test_respond_changes_mind(self, auth_client): auth_client.post("/respond", data={ "meal_type": "dinner", "status": "yes", }) resp = auth_client.post("/respond", data={ "meal_type": "dinner", "status": "no", }, follow_redirects=True) assert resp.status_code == 200 def test_respond_invalid_meal_type(self, auth_client): resp = auth_client.post("/respond", data={ "meal_type": "breakfast", "status": "yes", }, follow_redirects=True) assert b"Invalid meal type" in resp.data def test_respond_invalid_status(self, auth_client): resp = auth_client.post("/respond", data={ "meal_type": "lunch", "status": "maybe", }, follow_redirects=True) assert b"Invalid status" in resp.data class TestHistoryRoute: def test_history_requires_login(self, client): resp = client.get("/history", follow_redirects=True) assert b"Log In" in resp.data def test_history_shows_past_date(self, auth_client): past = date.today().replace(year=date.today().year - 1) resp = auth_client.get(f"/history?date={past.isoformat()}") assert resp.status_code == 200 assert b"History" in resp.data class TestDeleteAccount: def test_delete_own_account(self, auth_client): """Bob deletes his own account.""" resp = auth_client.post("/delete-account", data={ "password": "bobpass", }, follow_redirects=True) assert resp.status_code == 200 assert b"has been deleted" in resp.data # Bob should be logged out resp2 = auth_client.get("/dashboard", follow_redirects=True) assert b"Log In" in resp2.data def test_delete_own_account_wrong_password(self, auth_client): """Delete fails with wrong password.""" resp = auth_client.post("/delete-account", data={ "password": "wrongpass", }, follow_redirects=True) assert b"Incorrect password" in resp.data # Still logged in resp2 = auth_client.get("/dashboard") assert resp2.status_code == 200 class TestAdminRemoveUser: def test_admin_removes_user(self, admin_client): """Admin removes a regular user.""" # admin_client has admin as sole user — need another user to remove admin_client.get("/logout") # Register another user in admin's household from models import get_household_by_name hh = get_household_by_name("Admin Household") admin_client.post("/register", data={ "username": "extra", "password": "extrapass", "confirm": "extrapass", "household_action": "join", "household_id": str(hh["id"]), }) # admin_client logs back in as admin admin_client.get("/logout") admin_client.post("/login", data={ "username": "admin", "password": "adminpass", }) # Remove the extra user from models import get_user_by_username extra = get_user_by_username("extra") resp = admin_client.post(f"/admin/remove-user/{extra['id']}", follow_redirects=True) assert b"has been removed" in resp.data # Extra user should be gone admin_client.get("/dashboard") assert get_user_by_username("extra") is None def test_non_admin_cannot_remove(self, auth_client): """Regular user (bob) cannot remove others.""" resp = auth_client.post("/admin/remove-user/1", follow_redirects=True) assert b"Only admins" in resp.data def test_admin_cannot_remove_admin(self, admin_client): """Admin cannot remove themselves via remove-user.""" resp = admin_client.post("/admin/remove-user/1", follow_redirects=True) assert b"Cannot remove the admin" in resp.data class TestAdminDeleteHousehold: def test_admin_deletes_household(self, admin_client): """Admin deletes entire household.""" resp = admin_client.post("/admin/delete-household", data={ "password": "adminpass", }, follow_redirects=True) assert resp.status_code == 200 assert b"have been deleted" in resp.data def test_admin_delete_household_wrong_password(self, admin_client): resp = admin_client.post("/admin/delete-household", data={ "password": "wrong", }, follow_redirects=True) assert b"Incorrect password" in resp.data def test_non_admin_cannot_delete_household(self, auth_client): resp = auth_client.post("/admin/delete-household", data={ "password": "bobpass", }, follow_redirects=True) assert b"Only admins" in resp.data class TestDashboardOtherUsersGrayedOut: def test_other_users_buttons_are_disabled(self, auth_client): """Bob sees alice's status as badges, not clickable buttons.""" # Bob responds first so we can see his buttons auth_client.post("/respond", data={ "meal_type": "lunch", "status": "yes", }, follow_redirects=True) resp = auth_client.get("/dashboard") # Alice's status should show as a badge (not a form button) assert b"badge-yes" in resp.data or b"badge-not_answered" in resp.data