diff --git a/src/animaltrack/web/routes/actions.py b/src/animaltrack/web/routes/actions.py index c014902..1548d07 100644 --- a/src/animaltrack/web/routes/actions.py +++ b/src/animaltrack/web/routes/actions.py @@ -206,15 +206,11 @@ async def animal_cohort(request: Request, session): ) # Success: re-render fresh form - return HTMLResponse( - content=to_xml( - render_page( - request, - cohort_form(locations, species_list), - title="Create Cohort - AnimalTrack", - active_nav=None, - ) - ), + return render_page( + request, + cohort_form(locations, species_list), + title="Create Cohort - AnimalTrack", + active_nav=None, ) @@ -349,15 +345,11 @@ async def hatch_recorded(request: Request, session): ) # Success: re-render fresh form - return HTMLResponse( - content=to_xml( - render_page( - request, - hatch_form(locations, species_list), - title="Record Hatch - AnimalTrack", - active_nav=None, - ) - ), + return render_page( + request, + hatch_form(locations, species_list), + title="Record Hatch - AnimalTrack", + active_nav=None, ) @@ -694,15 +686,11 @@ async def animal_tag_add(request: Request, session): ) # Success: re-render fresh form - return HTMLResponse( - content=to_xml( - render_page( - request, - tag_add_form(), - title="Add Tag - AnimalTrack", - active_nav=None, - ) - ), + return render_page( + request, + tag_add_form(), + title="Add Tag - AnimalTrack", + active_nav=None, ) @@ -947,15 +935,11 @@ async def animal_tag_end(request: Request, session): ) # Success: re-render fresh form - return HTMLResponse( - content=to_xml( - render_page( - request, - tag_end_form(), - title="End Tag - AnimalTrack", - active_nav=None, - ) - ), + return render_page( + request, + tag_end_form(), + title="End Tag - AnimalTrack", + active_nav=None, ) @@ -1183,15 +1167,11 @@ async def animal_attrs(request: Request, session): ) # Success: re-render fresh form - return HTMLResponse( - content=to_xml( - render_page( - request, - attrs_form(), - title="Update Attributes - AnimalTrack", - active_nav=None, - ) - ), + return render_page( + request, + attrs_form(), + title="Update Attributes - AnimalTrack", + active_nav=None, ) @@ -1468,22 +1448,18 @@ async def animal_outcome(request: Request, session): product_repo = ProductRepository(db) products = [(p.code, p.name) for p in product_repo.list_all() if p.active] - return HTMLResponse( - content=to_xml( - render_page( - request, - outcome_form( - filter_str="", - resolved_ids=[], - roster_hash="", - ts_utc=int(time.time() * 1000), - resolved_count=0, - products=products, - ), - title="Record Outcome - AnimalTrack", - active_nav=None, - ) + return render_page( + request, + outcome_form( + filter_str="", + resolved_ids=[], + roster_hash="", + ts_utc=int(time.time() * 1000), + resolved_count=0, + products=products, ), + title="Record Outcome - AnimalTrack", + active_nav=None, ) @@ -1692,21 +1668,17 @@ async def animal_status_correct(req: Request, session): ) # Success: re-render fresh form - return HTMLResponse( - content=to_xml( - render_page( - req, - status_correct_form( - filter_str="", - resolved_ids=[], - roster_hash="", - ts_utc=int(time.time() * 1000), - resolved_count=0, - ), - title="Correct Status - AnimalTrack", - active_nav=None, - ) + return render_page( + req, + status_correct_form( + filter_str="", + resolved_ids=[], + roster_hash="", + ts_utc=int(time.time() * 1000), + resolved_count=0, ), + title="Correct Status - AnimalTrack", + active_nav=None, ) diff --git a/src/animaltrack/web/routes/eggs.py b/src/animaltrack/web/routes/eggs.py index 255d3a5..5c296fd 100644 --- a/src/animaltrack/web/routes/eggs.py +++ b/src/animaltrack/web/routes/eggs.py @@ -209,22 +209,18 @@ async def product_collected(request: Request, session): ) # Success: re-render form with location sticking, qty cleared - return HTMLResponse( - content=to_xml( - render_page( - request, - eggs_page( - locations, - products, - active_tab="harvest", - selected_location_id=location_id, - harvest_action=product_collected, - sell_action=product_sold, - ), - title="Eggs - AnimalTrack", - active_nav="eggs", - ) + return render_page( + request, + eggs_page( + locations, + products, + active_tab="harvest", + selected_location_id=location_id, + harvest_action=product_collected, + sell_action=product_sold, ), + title="Eggs - AnimalTrack", + active_nav="eggs", ) @@ -320,22 +316,18 @@ async def product_sold(request: Request, session): ) # Success: re-render form with product sticking - return HTMLResponse( - content=to_xml( - render_page( - request, - eggs_page( - locations, - products, - active_tab="sell", - selected_product_code=product_code, - harvest_action=product_collected, - sell_action=product_sold, - ), - title="Eggs - AnimalTrack", - active_nav="eggs", - ) + return render_page( + request, + eggs_page( + locations, + products, + active_tab="sell", + selected_product_code=product_code, + harvest_action=product_collected, + sell_action=product_sold, ), + title="Eggs - AnimalTrack", + active_nav="eggs", ) diff --git a/src/animaltrack/web/routes/feed.py b/src/animaltrack/web/routes/feed.py index d3eb2d0..6fd6495 100644 --- a/src/animaltrack/web/routes/feed.py +++ b/src/animaltrack/web/routes/feed.py @@ -245,25 +245,21 @@ async def feed_given(request: Request, session): ) # Success: re-render form with location/type sticking, amount reset - return HTMLResponse( - content=str( - render_page( - request, - feed_page( - locations, - feed_types, - active_tab="give", - selected_location_id=location_id, - selected_feed_type_code=feed_type_code, - default_amount_kg=default_amount_kg, - balance_warning=balance_warning, - give_action=feed_given, - purchase_action=feed_purchased, - ), - title="Feed - AnimalTrack", - active_nav="feed", - ) + return render_page( + request, + feed_page( + locations, + feed_types, + active_tab="give", + selected_location_id=location_id, + selected_feed_type_code=feed_type_code, + default_amount_kg=default_amount_kg, + balance_warning=balance_warning, + give_action=feed_given, + purchase_action=feed_purchased, ), + title="Feed - AnimalTrack", + active_nav="feed", ) @@ -404,21 +400,17 @@ async def feed_purchased(request: Request, session): ) # Success: re-render form with fields cleared - return HTMLResponse( - content=str( - render_page( - request, - feed_page( - locations, - feed_types, - active_tab="purchase", - give_action=feed_given, - purchase_action=feed_purchased, - ), - title="Feed - AnimalTrack", - active_nav="feed", - ) + return render_page( + request, + feed_page( + locations, + feed_types, + active_tab="purchase", + give_action=feed_given, + purchase_action=feed_purchased, ), + title="Feed - AnimalTrack", + active_nav="feed", ) diff --git a/src/animaltrack/web/routes/move.py b/src/animaltrack/web/routes/move.py index ab2bc1b..d2f23ea 100644 --- a/src/animaltrack/web/routes/move.py +++ b/src/animaltrack/web/routes/move.py @@ -299,18 +299,14 @@ async def animal_move(request: Request, session): ) # Success: re-render fresh form (nothing sticks per spec) - return HTMLResponse( - content=to_xml( - render_page( - request, - move_form( - locations, - action=animal_move, - ), - title="Move - AnimalTrack", - active_nav="move", - ) + return render_page( + request, + move_form( + locations, + action=animal_move, ), + title="Move - AnimalTrack", + active_nav="move", ) diff --git a/tests/test_web_actions.py b/tests/test_web_actions.py index 70f3991..ffc9d84 100644 --- a/tests/test_web_actions.py +++ b/tests/test_web_actions.py @@ -149,7 +149,7 @@ class TestCohortCreationSuccess: assert count_after == count_before + 3 def test_cohort_success_returns_toast(self, client, seeded_db, location_strip1_id): - """Successful cohort creation stores toast in session.""" + """Successful cohort creation renders toast in response body.""" resp = client.post( "/actions/animal-cohort", data={ @@ -164,20 +164,8 @@ class TestCohortCreationSuccess: ) assert resp.status_code == 200 - # Toast is stored in session cookie (FastHTML's add_toast mechanism) - # The session cookie contains base64-encoded toast data with "toasts" key - assert "set-cookie" in resp.headers - session_cookie = resp.headers["set-cookie"] - assert "session_=" in session_cookie - # Base64 decode contains toast message (eyJ0b2FzdHMi... = {"toasts"...) - import base64 - - # Extract base64 portion from cookie value - cookie_value = session_cookie.split("session_=")[1].split(";")[0] - # FastHTML uses itsdangerous, so format is base64.timestamp.signature - base64_data = cookie_value.split(".")[0] - decoded = base64.b64decode(base64_data).decode() - assert "Created 2 duck" in decoded + # Toast is injected into response body by FastHTML's toast middleware + assert "Created 2 duck" in resp.text class TestCohortCreationValidation: @@ -375,7 +363,7 @@ class TestHatchRecordingSuccess: assert count_at_nursery >= 3 def test_hatch_success_returns_toast(self, client, seeded_db, location_strip1_id): - """Successful hatch recording stores toast in session.""" + """Successful hatch recording renders toast in response body.""" resp = client.post( "/actions/hatch-recorded", data={ @@ -387,16 +375,8 @@ class TestHatchRecordingSuccess: ) assert resp.status_code == 200 - # Toast is stored in session cookie (FastHTML's add_toast mechanism) - assert "set-cookie" in resp.headers - session_cookie = resp.headers["set-cookie"] - assert "session_=" in session_cookie - import base64 - - cookie_value = session_cookie.split("session_=")[1].split(";")[0] - base64_data = cookie_value.split(".")[0] - decoded = base64.b64decode(base64_data).decode() - assert "Recorded 2 hatchling" in decoded + # Toast is injected into response body by FastHTML's toast middleware + assert "Recorded 2 hatchling" in resp.text class TestHatchRecordingValidation: @@ -729,8 +709,7 @@ class TestTagAddSuccess: assert tag_count >= len(animals_for_tagging) def test_tag_add_success_returns_toast(self, client, seeded_db, animals_for_tagging): - """Successful tag add stores toast in session.""" - import base64 + """Successful tag add renders toast in response body.""" import time from animaltrack.selection import compute_roster_hash @@ -751,14 +730,8 @@ class TestTagAddSuccess: ) assert resp.status_code == 200 - # Toast is stored in session cookie - assert "set-cookie" in resp.headers - session_cookie = resp.headers["set-cookie"] - assert "session_=" in session_cookie - cookie_value = session_cookie.split("session_=")[1].split(";")[0] - base64_data = cookie_value.split(".")[0] - decoded = base64.b64decode(base64_data).decode() - assert "Tagged" in decoded and "test-tag-toast" in decoded + # Toast is injected into response body by FastHTML's toast middleware + assert "Tagged" in resp.text and "test-tag-toast" in resp.text class TestTagAddValidation: @@ -925,8 +898,7 @@ class TestTagEndSuccess: assert open_after == 0 def test_tag_end_success_returns_toast(self, client, seeded_db, tagged_animals): - """Successful tag end stores toast in session.""" - import base64 + """Successful tag end renders toast in response body.""" import time from animaltrack.selection import compute_roster_hash @@ -947,14 +919,8 @@ class TestTagEndSuccess: ) assert resp.status_code == 200 - # Toast is stored in session cookie - assert "set-cookie" in resp.headers - session_cookie = resp.headers["set-cookie"] - assert "session_=" in session_cookie - cookie_value = session_cookie.split("session_=")[1].split(";")[0] - base64_data = cookie_value.split(".")[0] - decoded = base64.b64decode(base64_data).decode() - assert "Ended tag" in decoded and "test-end-tag" in decoded + # Toast is injected into response body by FastHTML's toast middleware + assert "Ended tag" in resp.text and "test-end-tag" in resp.text class TestTagEndValidation: @@ -1103,8 +1069,7 @@ class TestAttrsSuccess: assert adult_count == len(animals_for_tagging) def test_attrs_success_returns_toast(self, client, seeded_db, animals_for_tagging): - """Successful attrs update stores toast in session.""" - import base64 + """Successful attrs update renders toast in response body.""" import time from animaltrack.selection import compute_roster_hash @@ -1125,14 +1090,8 @@ class TestAttrsSuccess: ) assert resp.status_code == 200 - # Toast is stored in session cookie - assert "set-cookie" in resp.headers - session_cookie = resp.headers["set-cookie"] - assert "session_=" in session_cookie - cookie_value = session_cookie.split("session_=")[1].split(";")[0] - base64_data = cookie_value.split(".")[0] - decoded = base64.b64decode(base64_data).decode() - assert "Updated attributes" in decoded + # Toast is injected into response body by FastHTML's toast middleware + assert "Updated attributes" in resp.text class TestAttrsValidation: @@ -1280,8 +1239,7 @@ class TestOutcomeSuccess: assert harvested_count == len(animals_for_tagging) def test_outcome_success_returns_toast(self, client, seeded_db, animals_for_tagging): - """Successful outcome recording stores toast in session.""" - import base64 + """Successful outcome recording renders toast in response body.""" import time from animaltrack.selection import compute_roster_hash @@ -1302,14 +1260,8 @@ class TestOutcomeSuccess: ) assert resp.status_code == 200 - # Toast is stored in session cookie - assert "set-cookie" in resp.headers - session_cookie = resp.headers["set-cookie"] - assert "session_=" in session_cookie - cookie_value = session_cookie.split("session_=")[1].split(";")[0] - base64_data = cookie_value.split(".")[0] - decoded = base64.b64decode(base64_data).decode() - assert "Recorded sold" in decoded + # Toast is injected into response body by FastHTML's toast middleware + assert "Recorded sold" in resp.text class TestOutcomeValidation: diff --git a/tests/test_web_move.py b/tests/test_web_move.py index 3425e40..d1c0334 100644 --- a/tests/test_web_move.py +++ b/tests/test_web_move.py @@ -198,7 +198,7 @@ class TestMoveAnimalSuccess: location_strip2_id, ducks_at_strip1, ): - """Successful move returns session cookie with toast.""" + """Successful move renders toast in response body.""" ts_utc = int(time.time() * 1000) filter_str = 'location:"Strip 1"' filter_ast = parse_filter(filter_str) @@ -219,16 +219,8 @@ class TestMoveAnimalSuccess: ) assert resp.status_code == 200 - assert "set-cookie" in resp.headers - session_cookie = resp.headers["set-cookie"] - assert "session_=" in session_cookie - # Base64 decode contains toast message - import base64 - - cookie_value = session_cookie.split("session_=")[1].split(";")[0] - base64_data = cookie_value.split(".")[0] - decoded = base64.b64decode(base64_data).decode() - assert "Moved 5 animals to Strip 2" in decoded + # Toast is injected into response body by FastHTML's toast middleware + assert "Moved 5 animals to Strip 2" in resp.text def test_move_success_resets_form( self,