Initial commit: habit tracker PWA with Google OAuth, push notifications
FastAPI + SQLAlchemy/Alembic + MariaDB backend with Jinja2/htmx/Alpine server-rendered frontend. Multi-user via Google OAuth, daily habit tracking, monthly/weekly history views, Web Push reminders via APScheduler, and PWA support (manifest, service worker, offline caching). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
from app.models.habit import ALL_WEEKDAYS_MASK, HabitType
|
||||
from app.schemas.habit import HabitCreate
|
||||
from app.services import habit_service
|
||||
|
||||
|
||||
def _make_habit(db_session, user_id, name="테스트 습관"):
|
||||
data = HabitCreate(name=name, habit_type=HabitType.BUILD, weekdays_mask=ALL_WEEKDAYS_MASK)
|
||||
return habit_service.create_habit(db_session, user_id, data)
|
||||
|
||||
|
||||
def test_list_habits_requires_login(client):
|
||||
response = client.get("/api/habits")
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_create_and_list_habit(auth_client):
|
||||
response = auth_client.post(
|
||||
"/api/habits", json={"name": "아침 운동", "habit_type": "build", "weekdays_mask": ALL_WEEKDAYS_MASK}
|
||||
)
|
||||
assert response.status_code == 201
|
||||
created = response.json()
|
||||
assert created["name"] == "아침 운동"
|
||||
|
||||
listed = auth_client.get("/api/habits").json()
|
||||
assert [h["name"] for h in listed] == ["아침 운동"]
|
||||
|
||||
|
||||
def test_create_habit_rejects_blank_name(auth_client):
|
||||
response = auth_client.post(
|
||||
"/api/habits", json={"name": " ", "habit_type": "build", "weekdays_mask": ALL_WEEKDAYS_MASK}
|
||||
)
|
||||
assert response.status_code == 422
|
||||
|
||||
|
||||
def test_get_other_users_habit_returns_404(auth_client, db_session, other_user):
|
||||
others_habit = _make_habit(db_session, other_user.id, name="남의 습관")
|
||||
|
||||
response = auth_client.get(f"/api/habits/{others_habit.id}")
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_delete_other_users_habit_returns_404_and_does_not_delete(auth_client, db_session, other_user):
|
||||
others_habit = _make_habit(db_session, other_user.id, name="남의 습관")
|
||||
|
||||
response = auth_client.delete(f"/api/habits/{others_habit.id}")
|
||||
assert response.status_code == 404
|
||||
assert habit_service.get_habit(db_session, others_habit.id, other_user.id) is not None
|
||||
|
||||
|
||||
def test_update_own_habit(auth_client, db_session, test_user):
|
||||
habit = _make_habit(db_session, test_user.id, name="원래 이름")
|
||||
|
||||
response = auth_client.put(
|
||||
f"/api/habits/{habit.id}",
|
||||
json={"name": "새 이름", "habit_type": "build", "weekdays_mask": ALL_WEEKDAYS_MASK},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["name"] == "새 이름"
|
||||
|
||||
|
||||
def test_complete_and_reactivate_habit(auth_client, db_session, test_user):
|
||||
habit = _make_habit(db_session, test_user.id)
|
||||
|
||||
complete_res = auth_client.post(f"/api/habits/{habit.id}/complete")
|
||||
assert complete_res.status_code == 200
|
||||
assert complete_res.json()["status"] == "completed"
|
||||
|
||||
reactivate_res = auth_client.post(f"/api/habits/{habit.id}/reactivate")
|
||||
assert reactivate_res.status_code == 200
|
||||
assert reactivate_res.json()["status"] == "active"
|
||||
|
||||
|
||||
def test_reorder_endpoint(auth_client, db_session, test_user):
|
||||
a = _make_habit(db_session, test_user.id, name="A")
|
||||
b = _make_habit(db_session, test_user.id, name="B")
|
||||
|
||||
response = auth_client.post("/api/habits/reorder", json={"habit_ids": [b.id, a.id]})
|
||||
assert response.status_code == 200
|
||||
|
||||
listed = auth_client.get("/api/habits").json()
|
||||
assert [h["name"] for h in listed] == ["B", "A"]
|
||||
Reference in New Issue
Block a user