Add workout logging so users can track sets, reps, weight, and a
"felt easy?" toggle inline from the workout day view via HTMX.
Sessions auto-create on first log. History page shows past sessions
with detailed per-exercise breakdowns.
New services: WorkoutSessionService, LogService
New routes: POST /log, /log/{id}/edit, /log/{id}/delete, GET /history, /history/{id}
New templates: log_form, log_entry, session_card, log_history, session_detail
Modified: exercise_card (inline logging), nav (History link), workouts route (session context)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84 lines
3.2 KiB
Python
84 lines
3.2 KiB
Python
"""Tests for the WorkoutSessionService class."""
|
|
|
|
from datetime import date
|
|
|
|
from sqlmodel import SQLModel, Session, create_engine
|
|
|
|
from app.models.user import User
|
|
from app.models.workout_day import WorkoutDay
|
|
from app.models.workout_session import WorkoutSession
|
|
from app.services.workout_session_service import WorkoutSessionService
|
|
|
|
|
|
class TestWorkoutSessionService:
|
|
"""Tests for workout session CRUD operations."""
|
|
|
|
def _setup(self):
|
|
"""Create an in-memory DB with prerequisite data."""
|
|
engine = create_engine("sqlite:///:memory:")
|
|
SQLModel.metadata.create_all(engine)
|
|
session = Session(engine)
|
|
|
|
user = User(username="phil", password_hash="h", display_name="Phillip")
|
|
day = WorkoutDay(name="Push", day_number=1, description="Push day")
|
|
session.add_all([user, day])
|
|
session.commit()
|
|
session.refresh(user)
|
|
session.refresh(day)
|
|
|
|
service = WorkoutSessionService(session)
|
|
return session, service, user, day
|
|
|
|
def test_get_or_create_session_creates_new(self) -> None:
|
|
"""get_or_create_session should create a new session if none exists."""
|
|
session, service, user, day = self._setup()
|
|
ws = service.get_or_create_session(
|
|
user_id=user.id,
|
|
workout_day_id=day.id,
|
|
session_date=date.today(),
|
|
)
|
|
assert ws.id is not None
|
|
assert ws.user_id == user.id
|
|
assert ws.workout_day_id == day.id
|
|
session.close()
|
|
|
|
def test_get_or_create_session_returns_existing(self) -> None:
|
|
"""get_or_create_session should return existing session for same day."""
|
|
session, service, user, day = self._setup()
|
|
ws1 = service.get_or_create_session(user.id, day.id, date.today())
|
|
ws2 = service.get_or_create_session(user.id, day.id, date.today())
|
|
assert ws1.id == ws2.id
|
|
session.close()
|
|
|
|
def test_list_sessions_for_user(self) -> None:
|
|
"""list_sessions should return all sessions for a user."""
|
|
session, service, user, day = self._setup()
|
|
service.get_or_create_session(user.id, day.id, date.today())
|
|
sessions = service.list_sessions(user_id=user.id)
|
|
assert len(sessions) == 1
|
|
session.close()
|
|
|
|
def test_list_sessions_empty(self) -> None:
|
|
"""list_sessions should return empty list for user with no sessions."""
|
|
session, service, user, day = self._setup()
|
|
sessions = service.list_sessions(user_id=user.id)
|
|
assert len(sessions) == 0
|
|
session.close()
|
|
|
|
def test_get_session_by_id(self) -> None:
|
|
"""get_session_by_id should return the correct session."""
|
|
session, service, user, day = self._setup()
|
|
ws = service.get_or_create_session(user.id, day.id, date.today())
|
|
found = service.get_session_by_id(ws.id)
|
|
assert found is not None
|
|
assert found.id == ws.id
|
|
session.close()
|
|
|
|
def test_update_session_notes(self) -> None:
|
|
"""update_session should allow updating notes."""
|
|
session, service, user, day = self._setup()
|
|
ws = service.get_or_create_session(user.id, day.id, date.today())
|
|
updated = service.update_session(ws.id, notes="Great workout!")
|
|
assert updated.notes == "Great workout!"
|
|
session.close()
|