From 8f7ec905a6b2d8f95a221035aa7913450d589c5b Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 6 Jul 2026 10:45:41 +0100 Subject: [PATCH] fix: update exam test logic to handle CSRF token extraction and unanswered question counts --- physics/tests/test_physics_exams.py | 40 +++++++++++++++++++---- rad/tests/test_helpers.py | 50 ++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/physics/tests/test_physics_exams.py b/physics/tests/test_physics_exams.py index c2deb444..efaa4996 100644 --- a/physics/tests/test_physics_exams.py +++ b/physics/tests/test_physics_exams.py @@ -140,10 +140,36 @@ def test_exams(db, client): cid_take_soup = BeautifulSoup(cid_take_res.content, "html.parser") - # Extract csrftoken - csrftoken = cid_take_soup.find( - "input", attrs={"name": "csrfmiddlewaretoken"} - )["value"] + # The question form controls (including CSRF token) are loaded via + # the HTMX fragment. Request that fragment and parse it for the + # form elements instead of relying on the main container page. + if exam_tester.testing_cid_user: + frag_url = reverse( + f"{APP_NAME}:exam_take_fragment", + kwargs={ + "pk": exam.pk, + "sk": n, + "cid": exam_tester.current_user.cid, + "passcode": exam_tester.current_user.passcode, + }, + ) + else: + frag_url = reverse( + f"{APP_NAME}:exam_take_fragment_user", + kwargs={ + "pk": exam.pk, + "sk": n, + }, + ) + + frag_res = client.get(frag_url) + assert frag_res.status_code == HTTPStatus.OK + frag_soup = BeautifulSoup(frag_res.content, "html.parser") + + # Extract csrftoken from the fragment + csrftoken_el = frag_soup.find("input", attrs={"name": "csrfmiddlewaretoken"}) + assert csrftoken_el is not None + csrftoken = csrftoken_el["value"] # Send answers (all TRUE) post_json = { "csrfmiddlewaretoken": csrftoken, @@ -156,7 +182,7 @@ def test_exams(db, client): } res = client.post(question_url, data=post_json) - next_button = cid_take_soup.find("button", attrs={"name": "next"}) + next_button = frag_soup.find("button", attrs={"name": "next"}) # Our final question will trigger a bad request (it shouldn't show a next button) # We currently do still save the form though.... @@ -167,10 +193,10 @@ def test_exams(db, client): assert next_button assert res.status_code == HTTPStatus.FOUND - overview_button = cid_take_soup.find("button", attrs={"name": "finish"}) + overview_button = frag_soup.find("button", attrs={"name": "finish"}) assert overview_button - previous_button = cid_take_soup.find("button", attrs={"name": "previous"}) + previous_button = frag_soup.find("button", attrs={"name": "previous"}) if n > 0: assert previous_button diff --git a/rad/tests/test_helpers.py b/rad/tests/test_helpers.py index cec295d0..c31822a5 100644 --- a/rad/tests/test_helpers.py +++ b/rad/tests/test_helpers.py @@ -327,14 +327,23 @@ class ExamTester: ).text ) - assert ( - len( + # Different apps render unanswered markers differently: + # - `sbas` uses