|
4 | 4 |
|
5 | 5 | import httpx |
6 | 6 | import pytest |
| 7 | +from playwright.sync_api import TimeoutError as PlaywrightTimeoutError |
7 | 8 |
|
8 | 9 | from mavis.test.constants import Programme |
9 | 10 | from mavis.test.data import ClassFileMapping, VaccsFileMapping |
|
34 | 35 | _yg1, _yg2, _yg3 = random.sample(list(range(7, 12)), 3) |
35 | 36 | _year_groups = {p.group: _yg1 for p in Programme} |
36 | 37 |
|
| 38 | +# Separate year groups for consent breakdown test |
| 39 | +# (different teams use different year groups to avoid school conflicts) |
| 40 | +_available_ygs = [y for y in range(7, 12) if y not in [_yg1, _yg2, _yg3]] |
| 41 | +_yg_consent_a, _yg_consent_b = random.sample(_available_ygs, 2) |
| 42 | +_year_groups_consent_a = {p.group: _yg_consent_a for p in Programme} |
| 43 | +_year_groups_consent_b = {p.group: _yg_consent_b for p in Programme} |
| 44 | + |
37 | 45 | _setup_complete = False |
| 46 | +_consent_breakdown_setup_complete = False |
38 | 47 |
|
39 | 48 |
|
40 | | -def _onboard_team(base_url): |
| 49 | +def _onboard_team(base_url, year_groups=None): |
| 50 | + if year_groups is None: |
| 51 | + year_groups = _year_groups |
41 | 52 | onboarding = PointOfCareOnboarding.get_onboarding_data_for_tests( |
42 | 53 | base_url=base_url, |
43 | | - year_groups=_year_groups, |
| 54 | + year_groups=year_groups, |
44 | 55 | ) |
45 | 56 | return _create_onboarding_with_retry(base_url, onboarding) |
46 | 57 |
|
@@ -122,6 +133,43 @@ def school_b(team_b): |
122 | 133 | return team_b.schools[Programme.FLU.group][0] |
123 | 134 |
|
124 | 135 |
|
| 136 | +# Fixtures for consent breakdown test |
| 137 | +@pytest.fixture(scope="module") |
| 138 | +def consent_team_a(base_url): |
| 139 | + onboarding = _onboard_team(base_url, _year_groups_consent_a) |
| 140 | + yield onboarding |
| 141 | + _delete_team(base_url, onboarding.team) |
| 142 | + |
| 143 | + |
| 144 | +@pytest.fixture(scope="module") |
| 145 | +def consent_team_b(base_url): |
| 146 | + onboarding = _onboard_team(base_url, _year_groups_consent_b) |
| 147 | + yield onboarding |
| 148 | + _delete_team(base_url, onboarding.team) |
| 149 | + |
| 150 | + |
| 151 | +@pytest.fixture(scope="module") |
| 152 | +def consent_all_children(): |
| 153 | + return [ |
| 154 | + Child.generate(_yg_consent_a), |
| 155 | + Child.generate(_yg_consent_a), |
| 156 | + Child.generate(_yg_consent_a), |
| 157 | + Child.generate(_yg_consent_a), |
| 158 | + Child.generate(_yg_consent_b), |
| 159 | + Child.generate(_yg_consent_b), |
| 160 | + ] |
| 161 | + |
| 162 | + |
| 163 | +@pytest.fixture(scope="module") |
| 164 | +def consent_school_a(consent_team_a): |
| 165 | + return consent_team_a.schools[Programme.FLU.group][0] |
| 166 | + |
| 167 | + |
| 168 | +@pytest.fixture(scope="module") |
| 169 | +def consent_school_b(consent_team_b): |
| 170 | + return consent_team_b.schools[Programme.FLU.group][0] |
| 171 | + |
| 172 | + |
125 | 173 | def _do_setup(page, base_url, team_a, team_b, all_children, school_a, school_b): |
126 | 174 | global _setup_complete # noqa: PLW0603 |
127 | 175 | if _setup_complete: |
@@ -211,6 +259,97 @@ def _do_setup(page, base_url, team_a, team_b, all_children, school_a, school_b): |
211 | 259 | _setup_complete = True |
212 | 260 |
|
213 | 261 |
|
| 262 | +def _do_consent_breakdown_setup( |
| 263 | + page, base_url, team_a, team_b, all_children, school_a, school_b |
| 264 | +): |
| 265 | + global _consent_breakdown_setup_complete # noqa: PLW0603 |
| 266 | + if _consent_breakdown_setup_complete: |
| 267 | + return |
| 268 | + |
| 269 | + c1, c2, c3, c4, c5, c6 = all_children |
| 270 | + two_mf = ClassFileMapping.REPORTING_REGRESSION_TWO_MF |
| 271 | + one_f = ClassFileMapping.REPORTING_REGRESSION_ONE_F |
| 272 | + |
| 273 | + LogInPage(page).navigate() |
| 274 | + LogInPage(page).log_in_and_choose_team_if_necessary( |
| 275 | + team_a.users["nurse"], team_a.team |
| 276 | + ) |
| 277 | + |
| 278 | + _upload_class_list(page, school_a, team_a, [c1, c2], two_mf, _yg_consent_a) |
| 279 | + _upload_class_list(page, school_a, team_a, [c3, c4], two_mf, _yg_consent_a) |
| 280 | + |
| 281 | + schedule_school_session_if_needed( |
| 282 | + page, |
| 283 | + school_a, |
| 284 | + [Programme.FLU], |
| 285 | + [_yg_consent_a], |
| 286 | + ) |
| 287 | + session_id_a = SessionsOverviewPage(page).get_session_id_from_offline_excel() |
| 288 | + |
| 289 | + team_a_vaccs_fg = _make_file_generator(team_a, [c1, c2, c3, c4]) |
| 290 | + |
| 291 | + SessionsOverviewPage(page).header.click_mavis() |
| 292 | + DashboardPage(page).click_imports() |
| 293 | + ImportsPage(page).click_upload_records() |
| 294 | + ImportRecordsWizardPage( |
| 295 | + page, team_a_vaccs_fg |
| 296 | + ).navigate_to_vaccination_records_import() |
| 297 | + ImportRecordsWizardPage(page, team_a_vaccs_fg).upload_and_verify_output( |
| 298 | + file_mapping=VaccsFileMapping.REPORTING_REGRESSION_TEAM_A, |
| 299 | + session_id=session_id_a, |
| 300 | + programme_group=Programme.FLU.group, |
| 301 | + ) |
| 302 | + |
| 303 | + LogOutPage(page).navigate() |
| 304 | + LogOutPage(page).verify_log_out_page() |
| 305 | + LogInPage(page).navigate() |
| 306 | + LogInPage(page).log_in_and_choose_team_if_necessary( |
| 307 | + team_b.users["nurse"], team_b.team |
| 308 | + ) |
| 309 | + |
| 310 | + _upload_class_list(page, school_b, team_b, [c2], one_f, _yg_consent_a) |
| 311 | + _upload_class_list(page, school_b, team_b, [c4], one_f, _yg_consent_a) |
| 312 | + _upload_class_list(page, school_b, team_b, [c5, c6], two_mf, _yg_consent_b) |
| 313 | + |
| 314 | + schedule_school_session_if_needed( |
| 315 | + page, |
| 316 | + school_b, |
| 317 | + [Programme.FLU], |
| 318 | + [_yg_consent_a, _yg_consent_b], |
| 319 | + ) |
| 320 | + session_id_b = SessionsOverviewPage(page).get_session_id_from_offline_excel() |
| 321 | + |
| 322 | + team_b_vaccs_fg = _make_file_generator(team_b, [c5, c6]) |
| 323 | + |
| 324 | + SessionsOverviewPage(page).header.click_mavis() |
| 325 | + DashboardPage(page).click_imports() |
| 326 | + ImportsPage(page).click_upload_records() |
| 327 | + ImportRecordsWizardPage( |
| 328 | + page, team_b_vaccs_fg |
| 329 | + ).navigate_to_vaccination_records_import() |
| 330 | + ImportRecordsWizardPage(page, team_b_vaccs_fg).upload_and_verify_output( |
| 331 | + file_mapping=VaccsFileMapping.REPORTING_REGRESSION_TEAM_B, |
| 332 | + session_id=session_id_b, |
| 333 | + programme_group=Programme.FLU.group, |
| 334 | + ) |
| 335 | + |
| 336 | + ImportsPage(page).header.click_mavis() |
| 337 | + DashboardPage(page).click_school_moves() |
| 338 | + |
| 339 | + SchoolMovesPage(page).click_child(c2) |
| 340 | + ReviewSchoolMovePage(page).confirm() |
| 341 | + |
| 342 | + SchoolMovesPage(page).click_child(c4) |
| 343 | + ReviewSchoolMovePage(page).confirm() |
| 344 | + |
| 345 | + _refresh_reporting(base_url) |
| 346 | + |
| 347 | + LogOutPage(page).navigate() |
| 348 | + LogOutPage(page).verify_log_out_page() |
| 349 | + |
| 350 | + _consent_breakdown_setup_complete = True |
| 351 | + |
| 352 | + |
214 | 353 | def test_team_a_reporting( |
215 | 354 | page, |
216 | 355 | base_url, |
@@ -478,3 +617,71 @@ def test_team_b_aggregate_csv( |
478 | 617 | assert yg3_f["Cohort"] == 1 |
479 | 618 | assert yg3_f["Vaccinated"] == 0 |
480 | 619 | assert yg3_f["Not Vaccinated"] == 1 |
| 620 | + |
| 621 | + |
| 622 | +def test_consent_breakdown_counts_add_up( |
| 623 | + page, |
| 624 | + base_url, |
| 625 | + consent_team_a, |
| 626 | + consent_team_b, |
| 627 | + consent_all_children, |
| 628 | + consent_school_a, |
| 629 | + consent_school_b, |
| 630 | +): |
| 631 | + """ |
| 632 | + Test: Verify consent report breakdown counts add up to total. |
| 633 | + Steps: |
| 634 | + 1. Setup with single year group for consent breakdown test. |
| 635 | + 2. Log in as Team A nurse. |
| 636 | + 3. Navigate to Reports > Consent tab. |
| 637 | + 4. Get counts from "No consent recorded" box and breakdown boxes. |
| 638 | + 5. Verify breakdown counts add up to total. |
| 639 | + Verification: |
| 640 | + - Sum of breakdown boxes equals "No consent recorded" total. |
| 641 | + - Handles cases where some breakdown boxes may not exist. |
| 642 | + """ |
| 643 | + _do_consent_breakdown_setup( |
| 644 | + page, |
| 645 | + base_url, |
| 646 | + consent_team_a, |
| 647 | + consent_team_b, |
| 648 | + consent_all_children, |
| 649 | + consent_school_a, |
| 650 | + consent_school_b, |
| 651 | + ) |
| 652 | + |
| 653 | + page.context.clear_cookies() |
| 654 | + LogInPage(page).navigate() |
| 655 | + LogInPage(page).log_in_and_choose_team_if_necessary( |
| 656 | + consent_team_a.users["nurse"], consent_team_a.team |
| 657 | + ) |
| 658 | + |
| 659 | + ReportsConsentPage(page).navigate() |
| 660 | + ReportsConsentPage(page).check_filter_for_programme(Programme.FLU) |
| 661 | + |
| 662 | + # Get the total from "No consent recorded" box |
| 663 | + no_consent_total = ReportsConsentPage(page).get_children_count( |
| 664 | + "No consent recorded" |
| 665 | + ) |
| 666 | + |
| 667 | + # Get counts from the three breakdown boxes |
| 668 | + # Note: These box names will need to be verified against actual UI |
| 669 | + breakdown_box_1 = ReportsConsentPage(page).get_children_count( |
| 670 | + "No consent response or not yet invited" |
| 671 | + ) |
| 672 | + breakdown_box_2 = ReportsConsentPage(page).get_children_count("Consent refused") |
| 673 | + |
| 674 | + # Try to get the third breakdown box, but it may not exist |
| 675 | + # if no children have that status |
| 676 | + try: |
| 677 | + breakdown_box_3 = ReportsConsentPage(page).get_children_count( |
| 678 | + "No response - follow-up requested" |
| 679 | + ) |
| 680 | + except PlaywrightTimeoutError: |
| 681 | + breakdown_box_3 = 0 |
| 682 | + |
| 683 | + # Verify the breakdown counts add up to the total |
| 684 | + breakdown_sum = breakdown_box_1 + breakdown_box_2 + breakdown_box_3 |
| 685 | + assert breakdown_sum == no_consent_total, ( |
| 686 | + f"Breakdown sum ({breakdown_sum}) does not match total ({no_consent_total})" |
| 687 | + ) |
0 commit comments