"""Workout rendering and HTMX lifecycle checks, using an isolated database.""" import unittest from datetime import date from types import SimpleNamespace from unittest.mock import MagicMock, patch class WorkoutViewTests(unittest.TestCase): @classmethod def setUpClass(cls): # Import the application without opening a real database connection. with patch('psycopg_pool.ConnectionPool'): import app cls.module = app cls.app = app.app cls.app.config.update(TESTING=True) def setUp(self): import routes.workout as workout self.workout = workout self.db = MagicMock() for module in (self.module, workout): patcher = patch.object(module, 'db', self.db) patcher.start() self.addCleanup(patcher.stop) self.user = SimpleNamespace(id=1, name='Peter', is_authenticated=True, is_active=True, is_anonymous=False, is_admin=False, get_id=lambda: '1') loader = patch.object(self.module.login_manager, '_user_callback', lambda _: self.user) loader.start() self.addCleanup(loader.stop) self.client = self.app.test_client() with self.client.session_transaction() as session: session['_user_id'] = '1' session['_fresh'] = True self.top_sets = [ dict(topset_id=i, exercise_id=i, exercise_name=name, repetitions=reps, weight=weight) for i, (name, reps, weight) in enumerate([ ('30 degrees Smith Press', 7, 93.5), ('Seated Smith machine BTN press', 5, 61.5), ('Smith machine JM press', 12, 62.0), ('DB Lateral Raises', 20, 10.5), ('Smith machine Bulgarian split squat', 12, 96.0), ], 1) ] self.distribution = [ dict(attribute_name=name, percentage=percent, color=color, count=1) for name, percent, color in [('Shoulders', 40, '#477db5'), ('Chest', 20, '#299e9a'), ('Quads', 20, '#8b75bb'), ('Triceps', 20, '#c78565')] ] self.view_model = dict(person_id=1, workout_id=1, person_name='Peter', start_date=date(2026, 9, 5), note='', tags=[], top_sets=self.top_sets, muscle_distribution=self.distribution, equipment_distribution=[], movement_distribution=[]) model = patch.object(workout, '_get_workout_view_model', lambda *args: self.view_model) model.start() self.addCleanup(model.stop) self.db.execute.return_value = self.top_sets self.db.get_topset.return_value = self.top_sets[0] self.db.get_exercise.return_value = {'name': self.top_sets[0]['exercise_name']} self.db.get_all_exercises.return_value = [{'exercise_id': 1, 'name': 'Smith Press'}] self.db.create_topset.return_value = 6 self.db.get_topset_achievements.return_value = dict(is_pr_reps=True, rep_increase=1, weight_increase=0, stalled_sessions=0) self.db.exercises.get_workout_attribute_distribution.return_value = self.distribution self.base = '/person/1/workout/1' def test_full_page_and_fragment_render(self): for headers in ({}, {'HX-Request': 'true'}): response = self.client.get(self.base, headers=headers) self.assertEqual(response.status_code, 200) self.assertIn(b'workout-layout', response.data) self.assertIn(b'Session exercises', response.data) self.assertEqual(response.data.count(b'id=extra-target-1'), 1) def test_summary_counts_unique_exercises_and_refreshes(self): self.db.execute.return_value = self.top_sets + [self.top_sets[0]] response = self.client.get(self.base + '/summary') self.assertEqual(response.status_code, 200) self.assertIn(b'