Add meal tracker app: Flask + SQLite with auth, dashboard, 31 passing tests, Docker Compose

This commit is contained in:
agentbox
2026-07-31 21:25:59 +00:00
parent aabc83281b
commit d58828e0ef
17 changed files with 1214 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
"""Tests for meal periods, responses, and changed-mind logic."""
from datetime import date, datetime
import pytest
from models import (
init_db,
get_db,
ensure_meal_periods,
get_dashboard_data,
upsert_response,
get_user_by_username,
)
class TestMealPeriods:
def test_ensure_creates_periods(self, app):
with app.app_context():
periods = ensure_meal_periods(date(2025, 6, 15))
assert len(periods) == 2
types = {p["meal_type"] for p in periods}
assert types == {"lunch", "dinner"}
for p in periods:
assert p["date"] == "2025-06-15"
def test_ensure_is_idempotent(self, app):
with app.app_context():
p1 = ensure_meal_periods(date(2025, 6, 15))
p2 = ensure_meal_periods(date(2025, 6, 15))
assert p1[0]["id"] == p2[0]["id"]
assert p1[1]["id"] == p2[1]["id"]
class TestResponses:
def test_first_response_no_changed_at(self, app):
with app.app_context():
from models import create_user
user = create_user("test", "hash", is_admin=False)
periods = ensure_meal_periods(date.today())
lunch = periods[0]
resp = upsert_response(user["id"], lunch["id"], "yes")
assert resp["status"] == "yes"
assert resp["changed_at"] is None
def test_flip_yes_to_no_sets_changed_at(self, app):
with app.app_context():
from models import create_user
user = create_user("flipper", "hash", is_admin=False)
periods = ensure_meal_periods(date.today())
lunch = periods[0]
upsert_response(user["id"], lunch["id"], "yes")
resp = upsert_response(user["id"], lunch["id"], "no")
assert resp["status"] == "no"
assert resp["changed_at"] is not None
def test_flip_twice_updates_changed_at(self, app):
with app.app_context():
from models import create_user
user = create_user("flipper2", "hash", is_admin=False)
periods = ensure_meal_periods(date.today())
lunch = periods[0]
upsert_response(user["id"], lunch["id"], "yes")
r1 = upsert_response(user["id"], lunch["id"], "no")
r2 = upsert_response(user["id"], lunch["id"], "yes")
# changed_at should reflect the latest flip
assert r2["changed_at"] is not None
# The second flip should have a different timestamp (or at least not earlier)
assert r2["changed_at"] >= r1["changed_at"]
def test_same_status_no_change(self, app):
with app.app_context():
from models import create_user
user = create_user("same", "hash", is_admin=False)
periods = ensure_meal_periods(date.today())
lunch = periods[0]
r1 = upsert_response(user["id"], lunch["id"], "yes")
r2 = upsert_response(user["id"], lunch["id"], "yes")
assert r1["status"] == r2["status"]
assert r1["changed_at"] == r2["changed_at"]
class TestDashboardData:
def test_dashboard_includes_all_users(self, app):
with app.app_context():
from models import create_user
create_user("u1", "h1", is_admin=True)
create_user("u2", "h2", is_admin=False)
data = get_dashboard_data(date.today())
assert len(data["users"]) == 2
assert data["users"][0]["username"] == "u1"
assert data["users"][1]["username"] == "u2"
def test_dashboard_shows_responses(self, app):
with app.app_context():
from models import create_user
user = create_user("responder", "h", is_admin=True)
periods = ensure_meal_periods(date.today())
lunch = next(p for p in periods if p["meal_type"] == "lunch")
upsert_response(user["id"], lunch["id"], "yes")
data = get_dashboard_data(date.today())
resp = data["users"][0]["responses"]["lunch"]
assert resp["status"] == "yes"
def test_dashboard_defaults_not_answered(self, app):
with app.app_context():
from models import create_user
create_user("silent", "h", is_admin=False)
data = get_dashboard_data(date.today())
resp = data["users"][0]["responses"]["dinner"]
assert resp["status"] == "not_answered"
assert resp["changed_at"] is None