From c07e4057f06da4eb3b42cf9f30efb11f0268e152 Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Mon, 15 Dec 2025 10:29:35 +0000 Subject: [PATCH 1/9] Refacoring util to work for surveillance regression tests --- pages/datasets/investigation_dataset_page.py | 38 ++++- .../test_surveillance_scenario_10.py | 150 ++++++++++-------- utils/investigation_dataset.py | 50 +++--- 3 files changed, 148 insertions(+), 90 deletions(-) diff --git a/pages/datasets/investigation_dataset_page.py b/pages/datasets/investigation_dataset_page.py index 9ba4ab08..b070e17a 100644 --- a/pages/datasets/investigation_dataset_page.py +++ b/pages/datasets/investigation_dataset_page.py @@ -96,6 +96,7 @@ def __init__(self, page: Page): self.diagnostic_test_result = self.page.locator( "#datasetContent > div:nth-child(1) > div:nth-child(7) > span.userInput" ) + self.show_details_links = self.page.locator('a:has-text("Show details")') # Repeat strings: self.bowel_preparation_administered_string = "Bowel Preparation Administered" @@ -361,10 +362,13 @@ def select_diagnostic_procedure_type(self) -> None: def click_show_completion_proof_information(self) -> None: """ - This method is designed to click on the show completion proof information link. - It clicks on the show completion proof information link. + Clicks on the show completion proof information link if it contains the text "show" (case-insensitive). """ - self.click(self.show_completion_proof_information_details) + if ( + "show" + in self.show_completion_proof_information_details.inner_text().lower() + ): + self.click(self.show_completion_proof_information_details) def click_show_failure_information(self) -> None: """ @@ -416,6 +420,16 @@ def click_save_dataset_button(self) -> None: """ self.safe_accept_dialog(self.save_dataset_button) + def click_save_dataset_button_assert_dialog(self, expected_text: str) -> None: + """ + Clicks on the save dataset button and performs an assertion of the resulting dialog text. + Once done dismissed the dialog. + Args: + expected_text (str): The expected text in the resultant dialog + """ + self.assert_dialog_text("High-risk findings") + self.click(self.save_dataset_button) + def expect_text_to_be_visible(self, text: str) -> None: """ This method is designed to expect a text to be visible on the page. @@ -1193,6 +1207,24 @@ def assert_test_result(self, expected_text: str) -> None: actual_text.lower() == expected_text.lower() ), f"Expected '{expected_text}', but found '{actual_text}'" + def open_all_details_tabs(self) -> None: + """ + Clicks all visible "Show details" links on the page to open all details tabs. + """ + count = self.show_details_links.count() + for i in range(count): + link = self.show_details_links.nth(i) + if link.is_visible(): + self.click(link) + + def open_all_minimized_sections(self) -> None: + """ + Opens all the minimized sections in the investigation dataset form. + """ + self.open_all_details_tabs() + # Then do it again to get the internal sections + self.open_all_details_tabs() + def normalize_label(text: str) -> str: """ diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_10.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_10.py index c21f985f..ef461299 100644 --- a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_10.py +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_10.py @@ -243,6 +243,9 @@ def test_scenario_10(page: Page, general_properties: dict) -> None: "Investigation Datasets" ) + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # Then I confirm the "Investigation Dataset" section of the dataset contains the field "Actual Type of Test" with the value of "Flexible Sigmoidoscopy" DatasetFieldUtil(page).assert_cell_to_right_has_expected_text( "Actual Type of Test", "Flexible Sigmoidoscopy" @@ -256,7 +259,6 @@ def test_scenario_10(page: Page, general_properties: dict) -> None: ) # When I set the following fields and values within the Investigation Dataset for this subject: - InvestigationDatasetsPage(page).click_show_endoscopy_information() DatasetFieldUtil(page).populate_select_locator_for_field( "Endoscopist defined extent", EndoscopyLocationOptions.APPENDIX ) @@ -267,10 +269,12 @@ def test_scenario_10(page: Page, general_properties: dict) -> None: ) # When I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) @@ -288,38 +292,46 @@ def test_scenario_10(page: Page, general_properties: dict) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) - # And I add new polyps 1-2 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.CAECUM, "classification": PolypClassificationOptions.LST_NG, @@ -327,6 +339,23 @@ def test_scenario_10(page: Page, general_properties: dict) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 1, + ) + + # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.ASCENDING_COLON, "classification": PolypClassificationOptions.IIA, @@ -334,46 +363,33 @@ def test_scenario_10(page: Page, general_properties: dict) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, - ] + 2, + ) - # And I add intervention 1 for polyps 1-2 with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO, - "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, - "polyp appears fully resected endoscopically": YesNoUncertainOptions.UNCERTAIN, - } - ], - ] + # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + "polyp appears fully resected endoscopically": YesNoUncertainOptions.UNCERTAIN, + }, + 2, + ) # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "High-risk findings" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog( + "High-risk findings" + ) + # When I press the save Investigation Dataset button - InvestigationDatasetsPage(page).click_show_endoscopy_information() - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - ) - - # Then the Investigation Dataset result message is "High-risk findings" - InvestigationDatasetsPage(page).assert_test_result("High-risk findings") + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 10 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "10") diff --git a/utils/investigation_dataset.py b/utils/investigation_dataset.py index 1f82e9ff..7fd38057 100644 --- a/utils/investigation_dataset.py +++ b/utils/investigation_dataset.py @@ -363,7 +363,6 @@ def complete_dataset_with_args( # Drug Information if drug_information is not None: - InvestigationDatasetsPage(self.page).click_show_drug_information() self.fill_out_drug_information(drug_information) if endoscopy_information: @@ -373,9 +372,6 @@ def complete_dataset_with_args( # Completion Proof Information if completion_information is not None: logging.info("Filling out completion proof information") - InvestigationDatasetsPage( - self.page - ).click_show_completion_proof_information() DatasetFieldUtil(self.page).populate_select_locator_for_field( "Proof Parameters", completion_information["completion proof"] ) @@ -383,7 +379,6 @@ def complete_dataset_with_args( # Failure Information if failure_information is not None: logging.info("Filling out failure information") - self.investigation_datasets_pom.click_show_failure_information() DatasetFieldUtil(self.page).populate_select_locator_for_field_inside_div( self.failure_reasons_string, "divFailureSection", @@ -424,14 +419,6 @@ def fill_out_suspected_findings(self, suspected_findings: dict) -> None: """ Populates the Suspected Findings section of the Investigation Dataset form. """ - logging.info("Starting fill_out_suspected_findings") - try: - logging.info("About to click suspected findings details") - self.investigation_datasets_pom.click_show_suspected_findings_details() - logging.info("Clicked suspected findings details successfully") - except Exception as e: - logging.error(f"Error clicking on Show Suspected Findings Details: {e}") - raise for key, value in suspected_findings.items(): match key: case "extracolonic summary code": @@ -500,12 +487,40 @@ def fill_out_general_information(self, general_information: dict) -> None: self.page ).select_aspirant_endoscopist_option_index(aspirant) + def fill_out_completion_information(self, completion_information: dict) -> None: + """ + This method completes the Completion Proof Information section of the investigation dataset. + Args: + completion_information (dict): A dictionary containing completion proof parameters. + """ + logging.info("Filling out completion proof information") + self.investigation_datasets_pom.click_show_completion_proof_information() + DatasetFieldUtil(self.page).populate_select_locator_for_field( + "Proof Parameters", completion_information["completion proof"] + ) + + def fill_out_failure_information(self, failure_information: dict) -> None: + """ + This method completes the Failure Information section of the investigation dataset. + Args: + failure_information (dict): A dictionary containing failure reasons and related information. + """ + logging.info("Filling out failure information") + DatasetFieldUtil(self.page).populate_select_locator_for_field_inside_div( + self.failure_reasons_string, + "divFailureSection", + failure_information["failure reasons"], + ) + def fill_out_contrast_tagging_and_drug_information( self, contrast_tagging_and_drug: dict ) -> None: + """ + This method completes the Contrast, Tagging & Drug Information section of the investigation dataset. + Args: + contrast_tagging_and_drug (dict): A dictionary containing contrast, tagging agent, and drug information. + """ logging.info("๐Ÿงช Filling out Contrast, Tagging & Drug Information") - self.investigation_datasets_pom.click_show_contrast_tagging_and_drug_information() - # Use for loop and match-case for endoscopy_information fields for key, value in contrast_tagging_and_drug.items(): match key: @@ -635,9 +650,6 @@ def fill_out_radiology_information(self, radiology_data: dict) -> None: """ logging.info("Filling out Radiology Information") - self.investigation_datasets_pom.click_show_radiology_information() - self.investigation_datasets_pom.click_show_radiology_failure_information() - # Use for loop and match-case for radiology data fields for key, value in radiology_data.items(): match key: @@ -722,8 +734,6 @@ def fill_endoscopy_information(self, endoscopy_information: dict) -> None: endoscopy_information (dict): A dictionary containing the endoscopy information to be filled in the form. """ # Endoscopy Information - self.investigation_datasets_pom.click_show_endoscopy_information() - # Use for loop and match-case for endoscopy_information fields for key, value in endoscopy_information.items(): match key: From 652cef326597d57dd35357c9a85f935cdaf6c78a Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Thu, 18 Dec 2025 19:06:28 +0000 Subject: [PATCH 2/9] Refactoring FOBT + Surveillance regression tests Refactoring Investigation dataset ui app to accomodate new changes Refactoring Subject assertion to givebetter error messages Fixing incossistend KIT logging --- .../kit_service_management_repository.py | 20 +- .../InvestigationDatasetBuilderApplication.md | 2 +- investigation_dataset_ui.py | 110 +++- pages/contacts_list/maintain_contacts_page.py | 11 + pages/datasets/investigation_dataset_page.py | 3 +- .../test_fobt_scenario_10.py | 147 ++++-- .../test_fobt_scenario_11.py | 328 +++++++----- .../test_fobt_scenario_12.py | 139 +++-- .../test_fobt_scenario_13.py | 228 +++++---- .../test_fobt_scenario_14.py | 322 +++++++----- .../test_fobt_scenario_15.py | 476 +++++++++++------- .../test_fobt_scenario_16.py | 248 +++++---- .../test_fobt_scenario_17.py | 303 +++++++---- .../test_fobt_scenario_18.py | 234 +++++---- .../test_fobt_scenario_8.py | 244 ++++++--- .../test_surveillance_scenario_4.py | 87 ++-- .../test_surveillance_scenario_5.py | 87 ++-- .../test_surveillance_scenario_8.py | 194 ++++--- .../test_surveillance_scenario_9.py | 89 ++-- .../test_regression_test_setup_steps.py | 54 +- utils/subject_assertion.py | 11 +- 21 files changed, 2114 insertions(+), 1223 deletions(-) diff --git a/classes/repositories/kit_service_management_repository.py b/classes/repositories/kit_service_management_repository.py index 3ad5ab18..78b863ca 100644 --- a/classes/repositories/kit_service_management_repository.py +++ b/classes/repositories/kit_service_management_repository.py @@ -1,8 +1,10 @@ import logging -from typing import Optional +from typing import Optional, Any from utils.oracle.oracle import OracleDB from classes.kits.kit_service_management_record import KitServiceManagementRecord from classes.entities.kit_service_management_entity import KitServiceManagementEntity +import numpy as np +from decimal import Decimal class KitServiceManagementRepository: @@ -284,6 +286,22 @@ def update_kit_service_management_entity( if entity.put_attempts is not None: params["put_attempts"] = entity.put_attempts + params = {k: _sanitize_param(v) for k, v in params.items()} self.oracle_db.update_or_insert_data_to_table(sql_query, params) except Exception as ex: raise RuntimeError(f"Error updating KIT_QUEUE record: {ex}") + + +def _sanitize_param(val: Any) -> Any: + """ + Sanitizes a parameter value for database operations. + Args: + val: The parameter value to sanitize. + Returns: + The sanitized parameter value. + """ + if isinstance(val, np.generic): + return val.item() + if isinstance(val, Decimal): + return float(val) + return val diff --git a/docs/InvestigationDatasetBuilderApplication.md b/docs/InvestigationDatasetBuilderApplication.md index 417567e5..08c55fb8 100644 --- a/docs/InvestigationDatasetBuilderApplication.md +++ b/docs/InvestigationDatasetBuilderApplication.md @@ -329,7 +329,7 @@ Examples include `"yes_no"` and `"therapeutic_diagnostic"`, which are handled as 1. Choose a unique string for `"type"` (e.g., `"yes_no"`, `"therapeutic_diagnostic"`). 2. In your JSON field definition, set `"type"` to this string. -3. Ensure your `render_field` function in `investigation_dataset_ui.py` has a case for your custom type, rendering the appropriate widget (usually a dropdown/selectbox). +3. Ensure your `render_field` function in `investigation_dataset_ui.py` has a case for your custom type, rendering the appropriate widget (dropdown, radio, etc.). - For `"yes_no"`, the UI will show a dropdown with "yes" and "no". - For `"therapeutic_diagnostic"`, the UI will show a dropdown with "therapeutic" and "diagnostic". 4. You can add more custom types by extending the `render_field` function with new cases in the `match-case` or `if` dispatch. diff --git a/investigation_dataset_ui.py b/investigation_dataset_ui.py index 52712a17..fc0fe1a1 100644 --- a/investigation_dataset_ui.py +++ b/investigation_dataset_ui.py @@ -546,7 +546,23 @@ def show_section_with_imports(section_name: str) -> None: ) else: import_block = "" - st.code(f"{import_block}{section_name} = {pretty_dict(result)}", language="python") + # Map section to correct fill method + fill_methods = { + "general_information": "fill_out_general_information", + "drug_information": "fill_out_drug_information", + "endoscopy_information": "fill_endoscopy_information", + "completion_information": "fill_out_completion_information", + "failure_information": "fill_out_failure_information", + "radiology_information": "fill_out_radiology_information", + "suspected_findings": "fill_out_suspected_findings", + } + method = fill_methods.get(section_name, f"fill_{section_name}") + st.code( + f"InvestigationDatasetCompletion(page).{method}({pretty_dict(result)})", + language="python", + ) + if import_block: + st.code(import_block, language="python") def show_drug_group_section_with_imports(section_name: str) -> None: @@ -569,6 +585,8 @@ def show_drug_group_section_with_imports(section_name: str) -> None: all_fields.extend(group["fields"]) _render_drug_group(section_name, group, result) + # No special merging; each section is handled independently + enums = get_enums_used(all_fields) if enums: import_block = ( @@ -576,7 +594,19 @@ def show_drug_group_section_with_imports(section_name: str) -> None: ) else: import_block = "" - st.code(f"{import_block}{section_name} = {pretty_dict(result)}", language="python") + # Map section to correct fill method + fill_methods = { + "drug_information": "fill_out_drug_information", + "contrast_tagging_and_drug": "fill_out_contrast_tagging_and_drug_information", + "tagging_agent_given_drug_information": "fill_out_tagging_agent_given_drug_information", + } + method = fill_methods.get(section_name, f"fill_{section_name}") + st.code( + f"InvestigationDatasetCompletion(page).{method}({pretty_dict(result)})", + language="python", + ) + if import_block: + st.code(import_block, language="python") def _render_single_entry_fields(fields: list, result: dict) -> None: @@ -662,29 +692,63 @@ def show_polyp_information_and_intervention_and_histology() -> None: num_polyps = st.number_input( "Number of polyps", min_value=0, max_value=20, value=1, step=1 ) - polyp_information = [] - polyp_intervention = [] - polyp_histology = [] + polyp_info_dicts = {} + polyp_histology_dicts = {} + polyp_interventions_dicts = {} for pi in range(1, num_polyps + 1): st.markdown(f"### Polyp {pi}") - polyp_information.append(_render_polyp_info(polyp_info_fields, pi)) - polyp_intervention.append(_render_interventions(polyp_intervention_fields, pi)) - polyp_histology.append(_render_histology(polyp_histology_fields, pi)) + polyp_info = _render_polyp_info(polyp_info_fields, pi) + polyp_info_dicts[pi] = polyp_info + interventions = _render_interventions(polyp_intervention_fields, pi) + # If interventions is a list of length 1, store as dict, else as list + if isinstance(interventions, list) and len(interventions) == 1: + polyp_interventions_dicts[pi] = interventions[0] + else: + polyp_interventions_dicts[pi] = interventions + polyp_histology = _render_histology(polyp_histology_fields, pi) + polyp_histology_dicts[pi] = polyp_histology st.markdown("#### Output") - st.code( - f"{import_block}polyp_information = {pretty_list(polyp_information)}", - language="python", - ) - st.code( - f"polyp_intervention = {pretty_list(polyp_intervention)}", - language="python", - ) - st.code( - f"polyp_histology = {pretty_list(polyp_histology)}", - language="python", - ) + output_blocks = [] + for pi in range(1, num_polyps + 1): + info_dict = polyp_info_dicts[pi] + hist_dict = polyp_histology_dicts[pi] + intervention = polyp_interventions_dicts[pi] + code_lines = [] + # Information + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_information({pretty_dict(info_dict)}, {pi})" + ) + # Intervention + if isinstance(intervention, list): + if len(intervention) > 1: + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_multiple_interventions({pretty_list(intervention)}, {pi})" + ) + elif len(intervention) == 1 and isinstance(intervention[0], dict): + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention[0])}, {pi})" + ) + else: + code_lines.append(f"# No intervention for polyp {pi}") + elif isinstance(intervention, dict): + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention)}, {pi})" + ) + else: + code_lines.append(f"# No intervention for polyp {pi}") + # Histology + if not hist_dict: + code_lines.append(f"# No histology for polyp {pi}") + else: + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_histology({pretty_dict(hist_dict)}, {pi})" + ) + output_blocks.append("\n".join(code_lines)) + st.code("\n".join(code_lines), language="python") + if import_block: + st.code(import_block, language="python") def _render_polyp_info(fields: list, pi: int) -> dict: @@ -718,7 +782,7 @@ def _render_interventions(fields: list, pi: int) -> list: f"Add interventions for polyp {pi}?", key=f"add_interventions_{pi}" ) if not add_interventions: - return interventions + return [] num_int = st.number_input( f"Number of interventions for polyp {pi}", min_value=0, @@ -735,6 +799,8 @@ def _render_interventions(fields: list, pi: int) -> list: if val is not None: int_dict[field["key"]] = val interventions.append(int_dict) + if len(interventions) == 1: + return interventions[0] return interventions @@ -799,7 +865,7 @@ def _render_histology(fields: list, pi: int) -> dict: "endoscopy_information": show_section_with_imports, "completion_information": show_section_with_imports, "failure_information": show_section_with_imports, - "polyp_information_and_intervention_and_histology": lambda _: show_polyp_information_and_intervention_and_histology(), # If you want imports here, update similarly + "polyp_information_and_intervention_and_histology": lambda _: show_polyp_information_and_intervention_and_histology(), "contrast_tagging_and_drug": show_drug_group_section_with_imports, "tagging_agent_given_drug_information": show_drug_group_section_with_imports, "radiology_information": show_section_with_imports, diff --git a/pages/contacts_list/maintain_contacts_page.py b/pages/contacts_list/maintain_contacts_page.py index f2346d94..b668b406 100644 --- a/pages/contacts_list/maintain_contacts_page.py +++ b/pages/contacts_list/maintain_contacts_page.py @@ -65,3 +65,14 @@ def click_person_link_from_forename(self, forename: str) -> None: forename (str): The forename of the subject """ self.click(self.page.get_by_role("link", name=forename).last) + + def select_person_by_id(self, person_id: int) -> None: + """ + Selects a person by their unique person ID by clicking the corresponding link. + Requires a search to have been conducted and returned at least one result. + Args: + person_id (int): The unique ID of the person to select + """ + href_selector = f"a[href*='{person_id}']" + person_link = self.page.locator(href_selector).first + self.click(person_link) diff --git a/pages/datasets/investigation_dataset_page.py b/pages/datasets/investigation_dataset_page.py index b070e17a..e82bdad2 100644 --- a/pages/datasets/investigation_dataset_page.py +++ b/pages/datasets/investigation_dataset_page.py @@ -419,6 +419,7 @@ def click_save_dataset_button(self) -> None: It clicks on the save dataset button. """ self.safe_accept_dialog(self.save_dataset_button) + self.page.wait_for_timeout(3000) # 3 second timeout to allow page to update def click_save_dataset_button_assert_dialog(self, expected_text: str) -> None: """ @@ -427,7 +428,7 @@ def click_save_dataset_button_assert_dialog(self, expected_text: str) -> None: Args: expected_text (str): The expected text in the resultant dialog """ - self.assert_dialog_text("High-risk findings") + self.assert_dialog_text(expected_text) self.click(self.save_dataset_button) def expect_text_to_be_visible(self, text: str) -> None: diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_10.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_10.py index d4ca6bf4..ccecbece 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_10.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_10.py @@ -15,9 +15,6 @@ from utils.oracle.oracle import OracleDB from utils.investigation_dataset import InvestigationDatasetCompletion from utils.datasets.investigation_datasets import ( - get_default_general_information, - get_default_drug_information, - get_default_endoscopy_information, get_normal_smokescreen_information, ) from utils.sspi_change_steps import SSPIChangeSteps @@ -57,6 +54,14 @@ from pages.datasets.investigation_dataset_page import ( InvestigationDatasetsPage, FailureReasonsOptions, + BowelPreparationQualityOptions, + ComfortOptions, + EndoscopyLocationOptions, + InsufflationOptions, + OutcomeAtTimeOfProcedureOptions, + DrugTypeOptions, + YesNoOptions, + LateOutcomeOptions, ) from pages.screening_subject_search.reopen_fobt_screening_episode_page import ( ReopenFOBTScreeningEpisodePage, @@ -197,12 +202,18 @@ def test_scenario_10(page: Page) -> None: # And there is a "A183" letter batch for my subject with the exact title "Practitioner Clinic 1st Appointment" # When I process the open "A183 - Practitioner Clinic 1st Appointment" letter batch for my subject - # Then my subject has been updated as follows: batch_processing( page, "A183", "Practitioner Clinic 1st Appointment", - "A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # When I switch users to BCSS "England" as user role "Specialist Screening Practitioner" @@ -274,7 +285,6 @@ def test_scenario_10(page: Page) -> None: page, "A183", "GP Result (Abnormal)", - "A99 - Suitable for Endoscopic Test", ) # Then my subject has been updated as follows: @@ -350,31 +360,66 @@ def test_scenario_10(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = get_default_drug_information() + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = get_default_general_information() - endoscopy_information = get_default_endoscopy_information() - endoscopy_information["procedure type"] = "diagnostic" + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": 1, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = { - "failure reasons": FailureReasonsOptions.PAIN, - } + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} + ) # And I mark the Investigation Dataset as completed - # When I press the save Investigation Dataset button - # And I press OK on my confirmation prompt - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, - ) + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + # When I press the save Investigation Dataset button # Then the Investigation Dataset result message, which I will cancel, is "No Result" - InvestigationDatasetsPage(page).expect_text_to_be_visible("No Result") + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then my subject has been updated as follows: subject_assertion( @@ -482,9 +527,17 @@ def test_scenario_10(page: Page) -> None: page, "A318", "Result Letters - No Post-investigation Appointment", - "A380 - Failed Diagnostic Test - Refer Another", ) + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A380 Failed Diagnostic Test - Refer Another"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # When I select the advance episode option for "Record Contact with Patient" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage(page).click_record_contact_with_patient_button() @@ -540,9 +593,15 @@ def test_scenario_10(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I apply the "Normal_Smokescreen" Investigation Dataset Scenario - # And I mark the Investigation Dataset as completed - # When I press the save Investigation Dataset button ( general_information, drug_information, @@ -550,19 +609,32 @@ def test_scenario_10(page: Page) -> None: failure_information, completion_information, ) = get_normal_smokescreen_information() - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, - completion_information=completion_information, + InvestigationDatasetCompletion(page).fill_out_drug_information(drug_information) + InvestigationDatasetCompletion(page).fill_out_general_information( + general_information + ) + InvestigationDatasetCompletion(page).fill_endoscopy_information( + endoscopy_information + ) + InvestigationDatasetCompletion(page).fill_out_failure_information( + failure_information ) + InvestigationDatasetCompletion(page).fill_out_completion_information( + completion_information + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + # When I press the save Investigation Dataset button # Then the Investigation Dataset result message, which I will cancel, is "Normal (No Abnormalities Found)" - InvestigationDatasetsPage(page).expect_text_to_be_visible( + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog( "Normal (No Abnormalities Found)" ) + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + # Then my subject has been updated as follows: subject_assertion( nhs_no, @@ -631,7 +703,14 @@ def test_scenario_10(page: Page) -> None: page, "A410", "Post-Investigation Appointment Invitation Letter", - "A415 - Post-investigation Appointment Invitation Letter Printed", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, ) # When I view the subject @@ -670,7 +749,6 @@ def test_scenario_10(page: Page) -> None: page, "A430", "Result Letters Following Post-investigation Appointment", - "S61 - Normal (No Abnormalities Found) ", ) # Then my subject has been updated as follows: @@ -785,7 +863,6 @@ def test_scenario_10(page: Page) -> None: page, "A430", "Result Letters Following Post-investigation Appointment", - "S61 - Normal (No Abnormalities Found) ", ) # Then my subject has been updated as follows: diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_11.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_11.py index eb33740e..6d479a4b 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_11.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_11.py @@ -207,12 +207,18 @@ def test_scenario_11(page: Page) -> None: # And there is a "A183" letter batch for my subject with the exact title "Practitioner Clinic 1st Appointment" # When I process the open "A183 - Practitioner Clinic 1st Appointment" letter batch for my subject - # Then my subject has been updated as follows: batch_processing( page=page, batch_type="A183", batch_description="Practitioner Clinic 1st Appointment", - latest_event_status="A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # When I switch users to BCSS "England" as user role "Screening Centre Manager" @@ -342,6 +348,15 @@ def test_scenario_11(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) criteria = { "Person has current role": "Accredited Screening Colonoscopist", @@ -358,49 +373,54 @@ def test_scenario_11(page: Page) -> None: ) # And I set the following fields and values within the "Investigation Dataset" section of the investigation dataset: - general_information = { - "site": 1, - "practitioner": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "site": 1, + "practitioner": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) # When I add the following "bowel preparation administered" drugs and doses within the Investigation Dataset for this subject: - drug_information = {"drug_type1": DrugTypeOptions.MANNITOL, "drug_dose1": "3"} + InvestigationDatasetCompletion(page).fill_out_drug_information( + {"drug_type1": DrugTypeOptions.MANNITOL, "drug_dose1": "3"} + ) # And I set the following fields and values within the "Endoscopy Information" section of the investigation dataset: - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "detection assistant used": YesNoOptions.YES, - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "detection assistant used": YesNoOptions.YES, + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) # When I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: - # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: - # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: - # And I add new polyp 4 with the following fields and values within the Investigation Dataset for this subject: - # And I add new polyp 5 with the following fields and values within the Investigation Dataset for this subject: - # And I add new polyp 6 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.RECTUM, "classification": PolypClassificationOptions.IP, @@ -410,6 +430,37 @@ def test_scenario_11(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 1, + ) + + # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + }, + 1, + ) + + # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( + { + "date of receipt": datetime.today(), + "date of reporting": datetime.today(), + "pathology provider": 1, + "pathologist": 1, + "polyp type": PolypTypeOptions.SERRATED_LESION, + "serrated lesion sub type": SerratedLesionSubTypeOptions.HYPERPLASTIC_POLYP, + "polyp excision complete": PolypExcisionCompleteOptions.R1, + "polyp size": "5", + }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.CAECUM, "classification": PolypClassificationOptions.LST_NG, @@ -419,6 +470,23 @@ def test_scenario_11(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 2, + ) + + # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, + "image id": "AUTO TEST POLYP 2", + }, + 2, + ) + + # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.DESCENDING_COLON, "classification": PolypClassificationOptions.IP, @@ -428,6 +496,23 @@ def test_scenario_11(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 3, + ) + + # And I add intervention 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.COLD_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, + "image id": "AUTO TEST POLYP 3", + }, + 3, + ) + + # And I add new polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.ASCENDING_COLON, "classification": PolypClassificationOptions.ISP, @@ -437,6 +522,23 @@ def test_scenario_11(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 4, + ) + + # And I add intervention 1 for polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.ESD, + "device": PolypInterventionDeviceOptions.ENDOSCOPIC_KNIFE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, + "image id": "AUTO TEST POLYP 4", + }, + 4, + ) + + # And I add new polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.RECTUM, "classification": PolypClassificationOptions.ISP, @@ -446,6 +548,23 @@ def test_scenario_11(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 5, + ) + + # And I add intervention 1 for polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, + "image id": "AUTO TEST POLYP 5", + }, + 5, + ) + + # And I add new polyp 6 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.SIGMOID_COLON, "classification": PolypClassificationOptions.IS, @@ -455,99 +574,30 @@ def test_scenario_11(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, - ] + 6, + ) - # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 4 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 5 with the following fields and values within the Investigation Dataset for this subject: # And I add intervention 1 for polyp 6 with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, - "image id": "AUTO TEST POLYP 2", - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.COLD_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, - "image id": "AUTO TEST POLYP 3", - } - ], - [ - { - "modality": PolypInterventionModalityOptions.ESD, - "device": PolypInterventionDeviceOptions.ENDOSCOPIC_KNIFE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, - "image id": "AUTO TEST POLYP 4", - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, - "image id": "AUTO TEST POLYP 5", - } - ], - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, - "image id": "AUTO TEST POLYP 6", - } - ], - ] - - # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: - polyp_histology = [ + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( { - "date of receipt": datetime.today(), - "date of reporting": datetime.today(), - "pathology provider": 1, - "pathologist": 1, - "polyp type": PolypTypeOptions.SERRATED_LESION, - "serrated lesion sub type": SerratedLesionSubTypeOptions.HYPERPLASTIC_POLYP, - "polyp excision complete": PolypExcisionCompleteOptions.R1, - "polyp size": "5", - } - ] - - # And I mark the Investigation Dataset as complete - # And I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - polyp_histology=polyp_histology, + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, + "image id": "AUTO TEST POLYP 6", + }, + 6, ) + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button # Then the Investigation Dataset result message, which I will cancel, is "Abnormal" - InvestigationDatasetsPage(page).expect_text_to_be_visible("Abnormal") + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("Abnormal") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 5 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "5") @@ -613,9 +663,19 @@ def test_scenario_11(page: Page) -> None: page, "A410", "Post-Investigation Appointment Invitation Letter", - "A415 - Post-investigation Appointment Invitation Letter Printed", ) + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # When I view the event history for the subject's latest episode SubjectScreeningSummaryPage(page).expand_episodes_list() SubjectScreeningSummaryPage(page).click_first_fobt_episode_link() @@ -646,9 +706,19 @@ def test_scenario_11(page: Page) -> None: page, "A417", "Post-Investigation Appointment Cancelled (Screening Centre)", - "A422 - Post-investigation Appointment Cancellation Letter Printed", ) + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A422 Post-investigation Appointment Cancellation Letter Printed" + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # When I advance the subject's episode for "Post-investigation Appointment Required" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage( @@ -689,7 +759,14 @@ def test_scenario_11(page: Page) -> None: page=page, batch_type="A410", batch_description="Post-Investigation Appointment Invitation Letter", - latest_event_status="A415 - Post-investigation Appointment Invitation Letter Printed", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, ) # When I view the subject @@ -794,6 +871,7 @@ def test_scenario_11(page: Page) -> None: "A430", "Result Letters Following Post-investigation Appointment", ) + # Then my subject has been updated as follows: criteria = { "which diagnostic test": "Latest not-void test in latest episode", diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_12.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_12.py index 7346f1f0..b40bf404 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_12.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_12.py @@ -4,6 +4,7 @@ from playwright.sync_api import Page from classes.subject.subject import Subject from classes.user.user import User +from classes.repositories.person_repository import PersonRepository from utils.calendar_picker import CalendarPicker from utils.user_tools import UserTools from utils.subject_assertion import subject_assertion @@ -231,7 +232,14 @@ def test_scenario_12(page: Page) -> None: page, "A183", "Practitioner Clinic 1st Appointment", - "A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # When I switch users to BCSS "England" as user role "Screening Centre Manager" @@ -341,50 +349,82 @@ def test_scenario_12(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() - # And I set the following fields and values within the "Investigation Dataset" section of the investigation dataset: - general_information = { - "site": 1, - "practitioner": 1, - "testing clinician": 1, - "aspirant endoscopist": None, + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # And there is a clinician who meets the following criteria: + user = User.from_user_role_type(user_role) + criteria = { + "Person has current role": "Accredited Screening Colonoscopist", + "Person has current role in organisation": "User's SC", + "Resect & Discard accreditation status": "None", } + query = PersonRepository().build_person_selection_query( + criteria=criteria, person=None, required_person_count=1, user=user, subject=None + ) + df = OracleDB().execute_query(query) + person_name = ( + f"{df["person_family_name"].iloc[0]} {df["person_given_name"].iloc[0]}" + ) + + # And I set the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) # When I add the following "bowel preparation administered" drugs and doses within the Investigation Dataset for this subject: - drug_information = {"drug_type1": DrugTypeOptions.MANNITOL, "drug_dose1": "3"} + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And I set the following fields and values within the "Endoscopy Information" section of the investigation dataset: - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "diagnostic", - "bowel preparation quality": BowelPreparationQualityOptions.FAIR, - "comfort during examination": ComfortOptions.MODERATE_DISCOMFORT, - "comfort during recovery": ComfortOptions.MINIMAL_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.FAIR, + "comfort during examination": ComfortOptions.MODERATE_DISCOMFORT, + "comfort during recovery": ComfortOptions.MINIMAL_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.PAIN} - - # And I mark the Investigation Dataset as complete - # And I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} ) + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button # Then the Investigation Dataset result message, which I will cancel, is "No Result" - InvestigationDatasetsPage(page).expect_text_to_be_visible("No Result") + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # And my subject has been updated as follows: subject_assertion(nhs_no, {"latest episode accumulated result": "No result"}) @@ -450,7 +490,14 @@ def test_scenario_12(page: Page) -> None: page, "A410", "Post-Investigation Appointment Invitation Letter", - "A415 - Post-investigation Appointment Invitation Letter Printed", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, ) # When I view the subject @@ -492,9 +539,17 @@ def test_scenario_12(page: Page) -> None: page, "A353", "GP Letter Indicating Referral to Symptomatic", - "A372 - Refer Symptomatic, GP Letter Printed", ) + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A372 Refer Symptomatic, GP Letter Printed"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # When I view the advance episode options SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() @@ -552,8 +607,7 @@ def test_scenario_12(page: Page) -> None: page, "A358", "Return FOBT Letter after Referral to Symptomatic", - "P202 - Waiting Completion of Outstanding Events", - True, + run_timed_events=True, ) # Then my subject has been updated as follows: @@ -987,7 +1041,12 @@ def test_scenario_12(page: Page) -> None: page=page, batch_type="A319", batch_description="Result Letters - Refer another test after symptomatic referral", - latest_event_status="A395 - Refer Another Diagnostic Test", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A395 Refer Another Diagnostic Test"}, ) LogoutPage(page).log_out() diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_13.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_13.py index 761eaf0c..1944e203 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_13.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_13.py @@ -212,7 +212,14 @@ def test_scenario_13(page: Page) -> None: page, "A183", "Practitioner Clinic 1st Appointment", - "A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # When I switch users to BCSS "England" as user role "Screening Centre Manager" @@ -348,6 +355,14 @@ def test_scenario_13(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) criteria = { @@ -365,43 +380,54 @@ def test_scenario_13(page: Page) -> None: ) # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = {"drug_type1": DrugTypeOptions.MANNITOL, "drug_dose1": "3"} + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "site": 1, - "practitioner": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.ADHESION} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.ADHESION} + ) # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: - # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: - # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.ANASTOMOSIS, "classification": PolypClassificationOptions.IP, @@ -409,59 +435,22 @@ def test_scenario_13(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, - { - "location": EndoscopyLocationOptions.CAECUM, - "classification": PolypClassificationOptions.LST_NG, - "estimate of whole polyp size": "5", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, - "classification": PolypClassificationOptions.LST_NG, - "estimate of whole polyp size": "21", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - ] + 1, + ) # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, - "polyp appears fully resected endoscopically": YesNoOptions.YES, - } - ], - ] + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + }, + 1, + ) # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: - # And I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: - # And I update histology details for polyp 3 with the following fields and values within the Investigation Dataset for this subject: - polyp_histology = [ + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -474,6 +463,35 @@ def test_scenario_13(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.CAECUM, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "5", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 2, + ) + + # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 2, + ) + + # And I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -486,26 +504,52 @@ def test_scenario_13(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 2, + ) + + # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "21", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 3, + ) + + # And I add intervention 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + "polyp appears fully resected endoscopically": YesNoOptions.YES, + }, + 3, + ) + + # And I update histology details for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "pathology lost": YesNoOptions.YES, "reason pathology lost": ReasonPathologyLostOptions.LOST_IN_TRANSIT, }, - ] - - # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - polyp_histology=polyp_histology, + 3, ) + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button # Then the Investigation Dataset result message, which I will cancel, is "LNPCP" - InvestigationDatasetsPage(page).expect_text_to_be_visible("LNPCP") + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("LNPCP") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 13 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "13") diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_14.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_14.py index 629e0e85..defa12ce 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_14.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_14.py @@ -277,7 +277,14 @@ def test_scenario_14(page: Page) -> None: page=page, batch_description="Practitioner Clinic 1st Appointment", batch_type="A183", - latest_event_status="A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # When I switch users to BCSS "England" as user role "Screening Centre Manager" @@ -385,6 +392,14 @@ def test_scenario_14(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) criteria = { @@ -406,44 +421,55 @@ def test_scenario_14(page: Page) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And I set the following endoscopy fields and values within the Investigation Dataset for this subject: - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.ADHESION} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.ADHESION} + ) - # And I add new polyp 1-5 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.CAECUM, "classification": PolypClassificationOptions.LST_NG, @@ -451,95 +477,23 @@ def test_scenario_14(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, - { - "location": EndoscopyLocationOptions.ASCENDING_COLON, - "classification": PolypClassificationOptions.IIA, - "estimate of whole polyp size": "8", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, - "classification": PolypClassificationOptions.IIB, - "estimate of whole polyp size": "9", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.TRANSVERSE_COLON, - "classification": PolypClassificationOptions.IIC, - "estimate of whole polyp size": "7", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.SPLENIC_FLEXURE, - "classification": PolypClassificationOptions.LST_G, - "estimate of whole polyp size": "8", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - ] + 1, + ) # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 4 with the following fields and values within the Investigation Dataset for this subject: - # And I add intervention 1 for polyp 5 with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.ESD, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - ] + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 1, + ) # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: - # And I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: - # And I update histology details for polyp 3 with the following fields and values within the Investigation Dataset for this subject: - # And I update histology details for polyp 4 with the following fields and values within the Investigation Dataset for this subject: - # And I update histology details for polyp 5 with the following fields and values within the Investigation Dataset for this subject: - polyp_histology = [ + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -552,6 +506,35 @@ def test_scenario_14(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NO_DYSPLASIA, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.ASCENDING_COLON, + "classification": PolypClassificationOptions.IIA, + "estimate of whole polyp size": "8", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 2, + ) + + # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + }, + 2, + ) + + # And I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -564,7 +547,59 @@ def test_scenario_14(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, - {}, + 2, + ) + + # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, + "classification": PolypClassificationOptions.IIB, + "estimate of whole polyp size": "9", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 3, + ) + + # And I add intervention 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.ESD, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 3, + ) + + # And I add new polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.TRANSVERSE_COLON, + "classification": PolypClassificationOptions.IIC, + "estimate of whole polyp size": "7", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 4, + ) + + # And I add intervention 1 for polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + }, + 4, + ) + + # And I update histology details for polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -576,6 +611,35 @@ def test_scenario_14(page: Page) -> None: "polyp size": "8", "polyp carcinoma": YesNoUncertainOptions.NO, }, + 4, + ) + + # And I add new polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.SPLENIC_FLEXURE, + "classification": PolypClassificationOptions.LST_G, + "estimate of whole polyp size": "8", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 5, + ) + + # And I add intervention 1 for polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 5, + ) + + # And I update histology details for polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -588,22 +652,20 @@ def test_scenario_14(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.LOW_GRADE_DYSPLASIA, "polyp carcinoma": YesNoUncertainOptions.NO, }, - ] + 5, + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - polyp_histology=polyp_histology, + # Then the Investigation Dataset result message, which I will cancel, is "High-risk findings" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog( + "High-risk findings" ) - # Then the Investigation Dataset result message, which I will cancel, is "High-risk findings" - InvestigationDatasetsPage(page).expect_text_to_be_visible("High-risk findings") + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 9 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "9") diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_15.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_15.py index 12a5a1ed..1d0763f9 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_15.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_15.py @@ -228,7 +228,14 @@ def test_scenario_15(page: Page) -> None: page, "A183", "Practitioner Clinic 1st Appointment", - "A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # When I switch users to BCSS "England" as user role "Screening Centre Manager" @@ -384,6 +391,14 @@ def test_scenario_15(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role_type=user_role) criteria = { @@ -401,41 +416,54 @@ def test_scenario_15(page: Page) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } - general_information = { - "site": 1, - "practitioner": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "site": 1, + "practitioner": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = {"drug_type1": DrugTypeOptions.MANNITOL, "drug_dose1": "3"} + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) - # And I add new polyps 1-5 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.SIGMOID_COLON, "classification": PolypClassificationOptions.IS, @@ -443,87 +471,23 @@ def test_scenario_15(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 1, + ) + + # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( { - "location": EndoscopyLocationOptions.RECTUM, - "classification": PolypClassificationOptions.IS, - "estimate of whole polyp size": "7", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.CAECUM, - "classification": PolypClassificationOptions.IS, - "estimate of whole polyp size": "3", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.YES, - "reason left in situ": PolypReasonLeftInSituOptions.POLYP_TYPE, - "polyp type left in situ": PolypTypeLeftInSituOptions.LYMPHOID_FOLLICLE, - }, - { - "location": EndoscopyLocationOptions.ILEUM, - "classification": PolypClassificationOptions.IS, - "estimate of whole polyp size": "2", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.DESCENDING_COLON, - "classification": PolypClassificationOptions.IS, - "estimate of whole polyp size": "4", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.COLD_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, }, - ] - - # And I add intervention 1 for polyps 1-5 with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.COLD_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.BIOPSY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "intervention success": PolypInterventionSuccessOptions.SUCCESSFUL, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - ] - - # And I update histology details for polyps 1-5 with the following fields and values within the Investigation Dataset for this subject: - polyp_histology = [ + 1, + ) + + # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -536,6 +500,35 @@ def test_scenario_15(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.IS, + "estimate of whole polyp size": "7", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 2, + ) + + # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 2, + ) + + # And I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -546,6 +539,35 @@ def test_scenario_15(page: Page) -> None: "polyp excision complete": PolypExcisionCompleteOptions.R1, "polyp size": "8", }, + 2, + ) + + # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.CAECUM, + "classification": PolypClassificationOptions.IS, + "estimate of whole polyp size": "3", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.YES, + "reason left in situ": PolypReasonLeftInSituOptions.POLYP_TYPE, + "polyp type left in situ": PolypTypeLeftInSituOptions.LYMPHOID_FOLLICLE, + }, + 3, + ) + + # And I add intervention 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.BIOPSY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "intervention success": PolypInterventionSuccessOptions.SUCCESSFUL, + }, + 3, + ) + + # And I update histology details for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -556,6 +578,35 @@ def test_scenario_15(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 3, + ) + + # And I add new polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.ILEUM, + "classification": PolypClassificationOptions.IS, + "estimate of whole polyp size": "2", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 4, + ) + + # And I add intervention 1 for polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 4, + ) + + # And I update histology details for polyp 4 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -568,6 +619,35 @@ def test_scenario_15(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 4, + ) + + # And I add new polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.DESCENDING_COLON, + "classification": PolypClassificationOptions.IS, + "estimate of whole polyp size": "4", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 5, + ) + + # And I add intervention 1 for polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 5, + ) + + # And I update histology details for polyp 5 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -580,22 +660,18 @@ def test_scenario_15(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, - ] + 5, + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - polyp_histology=polyp_histology, - ) + # Then the Investigation Dataset result message, which I will cancel, is "Abnormal" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("Abnormal") - # Then the Investigation Dataset result message is "Abnormal" - InvestigationDatasetsPage(page).expect_text_to_be_visible("Abnormal") + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 4 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "4") @@ -764,7 +840,14 @@ def test_scenario_15(page: Page) -> None: page, "A410", "Post-Investigation Appointment Invitation Letter", - "A415 - Post-investigation Appointment Invitation Letter Printed", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, ) # When I view the subject @@ -796,9 +879,17 @@ def test_scenario_15(page: Page) -> None: page, "A430", "Result Letters Following Post-investigation Appointment", - "A395 - Refer Another Diagnostic Test", ) + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A395 Refer Another Diagnostic Test"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # When I select the advance episode option for "Record Contact with Patient" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage(page).click_record_contact_with_patient_button() @@ -856,15 +947,28 @@ def test_scenario_15(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = {"drug_type1": DrugTypeOptions.MANNITOL, "drug_dose1": "3"} + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) criteria = { "Person has current role": "Accredited Screening Colonoscopist", "Person has current role in organisation": "User's SC", - "Resect & Discard accreditation status": "None", + "Latest resect & discard accreditation start date": "Within the last 2 years", } query = PersonRepository().build_person_selection_query( criteria=criteria, person=None, required_person_count=1, user=user, subject=None @@ -876,57 +980,47 @@ def test_scenario_15(page: Page) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "site": 1, - "practitioner": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} - - # When there is a clinician who meets the following criteria: - criteria = { - "Person has current role": "Accredited Screening Colonoscopist", - "Person has current role in organisation": "User's SC", - "Latest resect & discard accreditation start date": "Within the last 2 years", - } - query = PersonRepository().build_person_selection_query( - criteria=criteria, person=None, required_person_count=1, user=user, subject=None - ) - logging.info(f"Final query: {query}") - df = OracleDB().execute_query(query) - person_name = ( - f"{df["person_family_name"].iloc[0]} {df["person_given_name"].iloc[0]}" + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} ) - # And I set the following fields and values within the Investigation Dataset for this subject: - general_information["testing clinician"] = person_name - # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.SIGMOID_COLON, "classification": PolypClassificationOptions.IS, @@ -935,35 +1029,31 @@ def test_scenario_15(page: Page) -> None: "optical diagnosis confidence": OpticalDiagnosisConfidenceOptions.LOW, "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, - } - ] + }, + 1, + ) # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, - "image id": "AUTO TEST POLYP 6 overall", - } - ] - ] + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.NO_RESECT_AND_DISCARD, + "image id": "AUTO TEST POLYP 6 overall", + }, + 1, + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "Abnormal" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("Abnormal") # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - ) - - # Then the Investigation Dataset result message is "Abnormal" - InvestigationDatasetsPage(page).expect_text_to_be_visible("Abnormal") + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 4 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "4") diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_16.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_16.py index 47ece10c..446b1e31 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_16.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_16.py @@ -219,7 +219,14 @@ def test_scenario_16(page: Page) -> None: page, "A183", "Practitioner Clinic 1st Appointment", - "A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # And there is a "A183" letter batch for my subject with the exact title "GP Result (Abnormal)" @@ -422,6 +429,14 @@ def test_scenario_16(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) query = PersonRepository().build_person_selection_query( @@ -441,41 +456,55 @@ def test_scenario_16(page: Page) -> None: ) # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = {"drug_type1": DrugTypeOptions.MANNITOL, "drug_dose1": "3"} + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "site": 1, - "practitioner": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "retroverted view": YesNoOptions.NO, - "scope imager used": YesNoOptions.YES, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "retroverted view": YesNoOptions.NO, + "scope imager used": YesNoOptions.YES, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) - # I add new polyps 1-3 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + # I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.ANASTOMOSIS, "classification": PolypClassificationOptions.IP, @@ -483,55 +512,22 @@ def test_scenario_16(page: Page) -> None: "estimate of whole polyp size": "11", "left in situ": YesNoOptions.NO, }, + 1, + ) + + # I add interventions 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( { - "location": EndoscopyLocationOptions.CAECUM, - "classification": PolypClassificationOptions.LST_NG, - "polyp access": PolypAccessOptions.EASY, - "estimate of whole polyp size": "5", - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, - "classification": PolypClassificationOptions.LST_NG, - "polyp access": PolypAccessOptions.EASY, - "estimate of whole polyp size": "21", - "left in situ": YesNoOptions.NO, + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "excised": YesNoOptions.YES, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "retrieved": PolypInterventionRetrievedOptions.YES, }, - ] - - # I add interventions 1 for polyps 1-3 with the following fields and values within the Investigation Dataset for this subject: - polyp_interventions = [ - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "excised": YesNoOptions.YES, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "retrieved": PolypInterventionRetrievedOptions.YES, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "excised": YesNoOptions.YES, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "excised": YesNoOptions.YES, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, - "polyp appears fully resected endoscopically": YesNoOptions.YES, - } - ], - ] - - # I update histology details for polyps 1-3 with the following fields and values within the Investigation Dataset for this subject: - polyp_histology = [ + 1, + ) + + # I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of reporting": datetime.today(), "date of receipt": datetime.today(), @@ -544,6 +540,35 @@ def test_scenario_16(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 1, + ) + + # I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.CAECUM, + "classification": PolypClassificationOptions.LST_NG, + "polyp access": PolypAccessOptions.EASY, + "estimate of whole polyp size": "5", + "left in situ": YesNoOptions.NO, + }, + 2, + ) + + # I add interventions 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "excised": YesNoOptions.YES, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 2, + ) + + # I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of reporting": datetime.today(), "date of receipt": datetime.today(), @@ -556,26 +581,52 @@ def test_scenario_16(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 2, + ) + + # I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, + "classification": PolypClassificationOptions.LST_NG, + "polyp access": PolypAccessOptions.EASY, + "estimate of whole polyp size": "21", + "left in situ": YesNoOptions.NO, + }, + 3, + ) + + # I add interventions 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "excised": YesNoOptions.YES, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + "polyp appears fully resected endoscopically": YesNoOptions.YES, + }, + 3, + ) + + # I update histology details for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "pathology lost": YesNoOptions.YES, "reason pathology lost": ReasonPathologyLostOptions.LOST_IN_TRANSIT, }, - ] + 3, + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - endoscopy_information=endoscopy_information, - drug_information=drug_information, - completion_information=completion_information, - failure_information=failure_information, - polyp_information=polyp_information, - polyp_intervention=polyp_interventions, - polyp_histology=polyp_histology, - ) + # Then the Investigation Dataset result message, which I will cancel, is "LNPCP" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("LNPCP") - # Then the Investigation Dataset result message is "LNPCP" - InvestigationDatasetsPage(page).expect_text_to_be_visible(text="LNPCP") + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 13 InvestigationDatasetsPage(page).assert_polyp_algorithm_size( @@ -687,7 +738,14 @@ def test_scenario_16(page: Page) -> None: page, "A410", "Post-Investigation Appointment Invitation Letter", - "A415 - Post-investigation Appointment Invitation Letter Printed", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, ) # When I view the subject @@ -727,9 +785,17 @@ def test_scenario_16(page: Page) -> None: page, "A430", "Result Letters Following Post-investigation Appointment", - "A395 - Refer Another Diagnostic Test", ) + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A395 Refer Another Diagnostic Test"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # When I select the advance episode option for "Record Contact with Patient" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage(page).click_record_contact_with_patient_button() diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_17.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_17.py index 3444ccc9..38759c34 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_17.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_17.py @@ -229,8 +229,16 @@ def test_scenario_17(page: Page) -> None: page=page, batch_description="Practitioner Clinic 1st Appointment", batch_type="A183", - latest_event_status="A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, + ) + # When I switch users to BCSS "England" as user role "Specialist Screening Practitioner" LogoutPage(page).log_out(close_page=False) BasePage(page).go_to_log_in_page() @@ -344,17 +352,27 @@ def test_scenario_17(page: Page) -> None: # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # And I edit the Investigation Dataset for this subject SubjectScreeningSummaryPage(page).click_datasets_link() - # And I open all minimized sections on the dataset SubjectDatasetsPage(page).click_investigation_show_datasets() - # And I mark the Investigation Dataset as completed - # When I press the save Investigation Dataset button + + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) + # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) criteria = { @@ -370,38 +388,49 @@ def test_scenario_17(page: Page) -> None: person_name = ( f"{df["person_family_name"].iloc[0]} {df["person_given_name"].iloc[0]}" ) + # And I set the following fields and values within the Investigation Dataset for this subject: - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} - # And I add new polyp 1-3 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) + + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.ANASTOMOSIS, "classification": PolypClassificationOptions.IP, @@ -409,53 +438,22 @@ def test_scenario_17(page: Page) -> None: "estimate of whole polyp size": "11", "left in situ": YesNoOptions.NO, }, + 1, + ) + + # And I add interventions 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( { - "location": EndoscopyLocationOptions.CAECUM, - "classification": PolypClassificationOptions.LST_NG, - "estimate of whole polyp size": "5", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, - "classification": PolypClassificationOptions.LST_NG, - "polyp access": PolypAccessOptions.EASY, - "estimate of whole polyp size": "21", - "left in situ": YesNoOptions.NO, + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "excised": YesNoOptions.YES, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "retrieved": PolypInterventionRetrievedOptions.YES, }, - ] - # And I add intervention for 3 polyps with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "excised": YesNoOptions.YES, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "retrieved": PolypInterventionRetrievedOptions.YES, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, - "polyp appears fully resected endoscopically": YesNoOptions.YES, - } - ], - ] - # And I add histology for 3 polyps with the following fields and values within the Investigation Dataset for this subject: - polyp_histology = [ + 1, + ) + + # And I add histology 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of reporting": datetime.today(), "date of receipt": datetime.today(), @@ -468,6 +466,35 @@ def test_scenario_17(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.CAECUM, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "5", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 2, + ) + + # And I add interventions 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 2, + ) + + # And I add histology 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of reporting": datetime.today(), "date of receipt": datetime.today(), @@ -480,87 +507,127 @@ def test_scenario_17(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 2, + ) + + # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, + "classification": PolypClassificationOptions.LST_NG, + "polyp access": PolypAccessOptions.EASY, + "estimate of whole polyp size": "21", + "left in situ": YesNoOptions.NO, + }, + 3, + ) + + # And I add interventions 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + "polyp appears fully resected endoscopically": YesNoOptions.YES, + }, + 3, + ) + + # And I add histology 1 for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "pathology lost": YesNoOptions.YES, "reason pathology lost": ReasonPathologyLostOptions.LOST_IN_TRANSIT, }, - ] - # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - polyp_histology=polyp_histology, + 3, ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button # Then the Investigation Dataset result message, which I will cancel, is "LNPCP" - InvestigationDatasetsPage(page).expect_text_to_be_visible("LNPCP") - # Then I confirm the Polyp Algorithm Size for Polyp 1,2 and 3 are 13,4,21 respectively - expected_size = 1 - expected_value = "13" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("LNPCP") - InvestigationDatasetsPage(page).assert_polyp_algorithm_size( - expected_size, expected_value - ) + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + # Then I confirm the Polyp Algorithm Size for Polyp 1 is 13 + InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "13") + + # Then I confirm the Polyp Algorithm Size for Polyp 2 is 4 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(2, "4") + # Then I confirm the Polyp Algorithm Size for Polyp 3 is 21 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(3, "21") - # And I confirm the Polyp Category for Polyp 1,2,3 are "Advanced colorectal polyp", "Premalignant polyp" and "LNPCP" respectively + + # And I confirm the Polyp Category for Polyp 1 is "Advanced colorectal polyp" InvestigationDatasetsPage(page).assert_polyp_category( 1, "Advanced colorectal polyp" ) + # And I confirm the Polyp Category for Polyp 2 is "Premalignant polyp" InvestigationDatasetsPage(page).assert_polyp_category(2, "Premalignant polyp") + # And I confirm the Polyp Category for Polyp 3 is "LNPCP" InvestigationDatasetsPage(page).assert_polyp_category(3, "LNPCP") - # And I confirm the Episode Result is "Abnormal" - episode_result = "LNPCP" - EpisodeRepository().confirm_episode_result(nhs_no, episode_result) + + # And I confirm the Episode Result is "LNPCP" + EpisodeRepository().confirm_episode_result(nhs_no, "LNPCP") # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # And I advance the subject's episode for "Enter Diagnostic Test Outcome" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage(page).click_enter_diagnostic_test_outcome_button() + # And I select Outcome of Diagnostic Test "Refer Symptomatic" DiagnosticTestOutcomePage(page).select_test_outcome_option( OutcomeOfDiagnosticTest.REFER_SYMPTOMATIC ) + # And I select Reason for Symptomatic Referral value "Corrective Surgery" DiagnosticTestOutcomePage(page).select_reason_for_symptomatic_referral_option( ReasonForSymptomaticReferral.CORRECTIVE_SURGERY ) + # And I save the Diagnostic Test Outcome information DiagnosticTestOutcomePage(page).click_save_button() + # Then my subject has been updated as follows: criteria = {"latest event status": "A315 Diagnostic Test Outcome Entered"} subject_assertion( nhs_no, criteria, ) + # When I advance the subject's episode for "Post-investigation Appointment Required" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage( page ).click_post_investigation_appointment_required_button() - # Then my subject has been updated as follows: + + # Then my subject has been updated as follows: subject_assertion( nhs_no, { "latest event status": "A360 Post-investigation Appointment Required", }, ) + # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # And I choose to book a practitioner clinic for my subject SubjectScreeningSummaryPage(page).click_book_practitioner_clinic_button() + # And I set the practitioner appointment date to "today" # And I book the "earliest" available practitioner appointment on this date book_post_investigation_appointment(page, "The Royal Hospital (Wolverhampton)") + # Then my subject has been updated as follows: subject_assertion( nhs_no, @@ -568,16 +635,15 @@ def test_scenario_17(page: Page) -> None: "latest event status": "A410 Post-investigation Appointment Made", }, ) + # And there is a "A410" letter batch for my subject with the exact title "Post-Investigation Appointment Invitation Letter" # When I process the open "A410 - Post-Investigation Appointment Invitation Letter" letter batch for my subject - letter_code = "A410" - letter_type = "Post-Investigation Appointment Invitation Letter" - batch_processing( page, - letter_code, - letter_type, + "A410", + "Post-Investigation Appointment Invitation Letter", ) + # Then my subject has been updated as follows: criteria = { "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" @@ -586,15 +652,20 @@ def test_scenario_17(page: Page) -> None: nhs_no, criteria, ) + # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # And I view the event history for the subject's latest episode SubjectScreeningSummaryPage(page).expand_episodes_list() SubjectScreeningSummaryPage(page).click_first_fobt_episode_link() + # And I view the latest practitioner appointment in the subject's episode EpisodeEventsAndNotesPage(page).click_most_recent_view_appointment_link() + # And I attend the subject's practitioner appointment "today" AppointmentDetailPage(page).mark_appointment_as_attended(datetime.today()) + # Then my subject has been updated as follows: criteria = { "latest episode includes event status": "A416 Post-investigation Appointment Attended ", @@ -607,19 +678,23 @@ def test_scenario_17(page: Page) -> None: # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # When I select the advance episode option for "MDT Referral Required" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage(page).click_mdt_referral_required_button() - # # And I enter simple MDT information + + # And I enter simple MDT information ReferToMDTPage(page).enter_date_in_mdt_discussion_date_field(datetime.today()) ReferToMDTPage(page).select_mdt_location_lookup(1) ReferToMDTPage(page).click_record_mdt_appointment_button() - # Then my subject has been updated as follows: + + # Then my subject has been updated as follows: criteria = {"latest event status": "A348 MDT Referral Required"} subject_assertion( nhs_no, criteria, ) + # And there is a "A348" letter batch for my subject with the exact title "GP Letter Indicating Referral to MDT" # When I process the open "A348" letter batch for my subject batch_processing( @@ -627,6 +702,7 @@ def test_scenario_17(page: Page) -> None: "A348", "GP Letter Indicating Referral to MDT", ) + # Then my subject has been updated as follows: subject_assertion( nhs_no, @@ -637,9 +713,11 @@ def test_scenario_17(page: Page) -> None: # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) - # # And I select the advance episode option for "Patient Unfit, Handover into Symptomatic Care" + + # And I select the advance episode option for "Patient Unfit, Handover into Symptomatic Care" SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() AdvanceFOBTScreeningEpisodePage(page).click_handover_into_symptomatic_care_button() + # And I fill in Handover into Symptomatic Care form for Patient Unfit for Treatment and Cease from programme HandoverIntoSymptomaticCarePage(page).select_referral_dropdown_option( "Referral to Patient's GP Practice" @@ -656,10 +734,12 @@ def test_scenario_17(page: Page) -> None: "latest event status": "A357 Patient Unfit, Handover into Symptomatic Care", }, ) + # And there is a "A357" letter batch for my subject with the exact title "Handover into Symptomatic Care, Patient Unfit" SubjectRepository().there_is_letter_batch_for_subject( nhs_no, "A357", "Handover into Symptomatic Care, Patient Unfit", True ) + # When I switch users to BCSS "England" as user role "Hub Manager" LogoutPage(page).log_out(close_page=False) BasePage(page).go_to_log_in_page() @@ -693,6 +773,7 @@ def test_scenario_17(page: Page) -> None: OrganisationSwitchPage(page).click_continue() if user_role is None: raise ValueError("User role is none") + # And I process the open "A357 - Handover into Symptomatic Care, Patient Unfit" letter batch for my subject batch_processing( page, diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_18.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_18.py index 9460ccdb..9023bd88 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_18.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_18.py @@ -247,7 +247,14 @@ def test_scenario_18(page: Page) -> None: page=page, batch_description="Practitioner Clinic 1st Appointment", batch_type="A183", - latest_event_status="A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # And there is a "A183" letter batch for my subject with the exact title "GP Result (Abnormal)" @@ -533,11 +540,21 @@ def test_scenario_18(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) @@ -556,38 +573,47 @@ def test_scenario_18(page: Page) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "therapeutic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following completion proof values within the Investigation Dataset for this subject: - completion_information = {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) - # And I add new polyps 1-3 with the following fields and values within the Investigation Dataset for this subject: - polyp_information = [ + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( { "location": EndoscopyLocationOptions.ANASTOMOSIS, "classification": PolypClassificationOptions.IP, @@ -595,55 +621,22 @@ def test_scenario_18(page: Page) -> None: "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, + 1, + ) + + # And I add 1 intervention for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( { - "location": EndoscopyLocationOptions.CAECUM, - "classification": PolypClassificationOptions.LST_NG, - "estimate of whole polyp size": "5", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, - }, - { - "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, - "classification": PolypClassificationOptions.LST_NG, - "estimate of whole polyp size": "21", - "polyp access": PolypAccessOptions.EASY, - "left in situ": YesNoOptions.NO, + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, }, - ] - - # And I add 1 intervention for polyps 1-3 with the following fields and values within the Investigation Dataset for this subject: - polyp_intervention = [ - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.EMR, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, - } - ], - [ - { - "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.HOT_SNARE, - "excised": YesNoOptions.YES, - "retrieved": PolypInterventionRetrievedOptions.YES, - "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, - "polyp appears fully resected endoscopically": YesNoOptions.YES, - } - ], - ] - - # And I add histology for polyps 1-3 with the following fields and values within the Investigation Dataset for this subject: - polyp_histology = [ + 1, + ) + + # And I add histology for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -656,6 +649,35 @@ def test_scenario_18(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.CAECUM, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "5", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 2, + ) + + # And I add 1 intervention for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 2, + ) + + # And I add histology for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "date of receipt": datetime.today(), "date of reporting": datetime.today(), @@ -668,28 +690,52 @@ def test_scenario_18(page: Page) -> None: "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, "polyp carcinoma": YesNoUncertainOptions.NO, }, + 2, + ) + + # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "21", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 3, + ) + + # And I add 1 intervention for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + "polyp appears fully resected endoscopically": YesNoOptions.YES, + }, + 3, + ) + + # And I add histology for polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( { "pathology lost": YesNoOptions.YES, "reason pathology lost": ReasonPathologyLostOptions.LOST_IN_TRANSIT, }, - ] + 3, + ) - # And I open all minimized sections on the dataset # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "LNPCP" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("LNPCP") + # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - completion_information=completion_information, - polyp_information=polyp_information, - polyp_intervention=polyp_intervention, - polyp_histology=polyp_histology, - ) - - # Then the Investigation Dataset result message is "LNPCP" - InvestigationDatasetsPage(page).expect_text_to_be_visible("LNPCP") + InvestigationDatasetsPage(page).click_save_dataset_button() # Then I confirm the Polyp Algorithm Size for Polyp 1 is 13 InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "13") diff --git a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_8.py b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_8.py index c152f4ca..7a839db5 100644 --- a/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_8.py +++ b/tests/regression/regression_tests/fobt_regression_tests/test_fobt_scenario_8.py @@ -19,6 +19,11 @@ IVContrastAdministeredOptions, FailureReasonsOptions, InvestigationDatasetsPage, + BowelPreparationQualityOptions, + ComfortOptions, + EndoscopyLocationOptions, + InsufflationOptions, + OutcomeAtTimeOfProcedureOptions, ) from pages.datasets.subject_datasets_page import SubjectDatasetsPage from utils.user_tools import UserTools @@ -35,11 +40,6 @@ from pages.screening_subject_search.attend_diagnostic_test_page import ( AttendDiagnosticTestPage, ) -from utils.datasets.investigation_datasets import ( - get_default_general_information, - get_default_drug_information, - get_default_endoscopy_information, -) from utils.oracle.oracle import OracleDB from utils.oracle.subject_selector import SubjectSelector from utils.fit_kit import FitKitLogged, FitKitGeneration @@ -227,7 +227,14 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A183", batch_description="Practitioner Clinic 1st Appointment", - latest_event_status="A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # And there is a "A183" letter batch for my subject with the exact title "GP Result (Abnormal)" @@ -235,7 +242,14 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A183", batch_description="GP Result (Abnormal)", - latest_event_status="A25 - 1st Colonoscopy Assessment Appointment Booked, letter sent", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A25 1st Colonoscopy Assessment Appointment Booked, letter sent" + }, ) # When I switch users to BCSS "England" as user role "Screening Centre Manager" @@ -336,6 +350,8 @@ def test_scenario_8(page: Page) -> None: user_role = UserTools.switch_user( page, "Screening Centre Manager", remember_user=True ) + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") # And I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) @@ -383,7 +399,14 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A397", batch_description="Discharge from screening round - no contact (letter to patient)", - latest_event_status="A391 - Patient Discharge Letter Printed - No Patient Contact", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A391 Patient Discharge Letter Printed - No Patient Contact" + }, ) # And there is a "A391" letter batch for my subject with the exact title "Discharge from screening round - no contact (letter to GP)" @@ -392,7 +415,6 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A391", batch_description="Discharge from screening round - no contact (letter to GP)", - latest_event_status="A351 - GP Discharge Letter Printed - No Patient Contact", ) # Then my subject has been updated as follows: @@ -527,63 +549,73 @@ def test_scenario_8(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "site": 1, - "practitioner": 1, - "testing clinician": 1, - "reporting radiologist": 2, - "fit for subsequent endoscopic referral": YesNoOptions.YES, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "site": 1, + "practitioner": 1, + "testing clinician": 1, + "reporting radiologist": 2, + "fit for subsequent endoscopic referral": YesNoOptions.YES, + } + ) # And I set the following fields and values within the Contrast, Tagging & Drug Information: # And I add the following Additional Bowel Preparation drugs and values within the Investigation Dataset for this subject: - contrast_tagging_and_drug = { - "iv buscopan administered": IVBuscopanAdministeredOptions.NO, - "contraindicated": YesNoOptions.NO, - "iv contrast administered": IVContrastAdministeredOptions.NO, - "tagging agent given": TaggingAgentDrugAdministeredOptions.YES, - "additional bowel preparation administered": AdditionalBowelPrepAdministeredOptions.YES, - "drug_type1": DrugTypeOptions.PICOLAX, - "drug_dose1": "1", - } + InvestigationDatasetCompletion(page).fill_out_contrast_tagging_and_drug_information( + { + "iv buscopan administered": IVBuscopanAdministeredOptions.NO, + "contraindicated": YesNoOptions.NO, + "iv contrast administered": IVContrastAdministeredOptions.NO, + "tagging agent given": TaggingAgentDrugAdministeredOptions.YES, + "additional bowel preparation administered": AdditionalBowelPrepAdministeredOptions.YES, + "drug_type1": DrugTypeOptions.PICOLAX, + "drug_dose1": "1", + } + ) # And I add the following "Tagging Agent Given" drugs and doses within the Investigation Dataset for this subject: - # | Gastrografin | 1 | - tagging_agent_given_drug_information = { - "drug_type1": DrugTypeOptions.GASTROGRAFIN, - "drug_dose1": "1", - } + InvestigationDatasetCompletion(page).fill_out_tagging_agent_given_drug_information( + {"drug_type1": DrugTypeOptions.GASTROGRAFIN, "drug_dose1": "1"} + ) # And I set the following fields and values within the Radiology Information: - # And I set the following fields and values within the Radiology Information: - radiology_information = { - "examination quality": ExaminationQualityOptions.GOOD, - "scan position": ScanPositionOptions.DUAL, - "procedure outcome": ProcedureOutcomeOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - "segmental inadequacy": SegmentalInadequacyOptions.NO, - "intracolonic summary code": IntracolonicSummaryCodeOptions.CX_INADEQUATE_STUDY, - } - - suspected_findings = { - "extracolonic summary code": ExtracolonicSummaryCodeOptions.E4_IMPORTANT_REQUIRES_ACTION, - } + InvestigationDatasetCompletion(page).fill_out_radiology_information( + { + "examination quality": ExaminationQualityOptions.GOOD, + "scan position": ScanPositionOptions.DUAL, + "procedure outcome": ProcedureOutcomeOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + "segmental inadequacy": SegmentalInadequacyOptions.NO, + "intracolonic summary code": IntracolonicSummaryCodeOptions.CX_INADEQUATE_STUDY, + } + ) + InvestigationDatasetCompletion(page).fill_out_suspected_findings( + { + "extracolonic summary code": ExtracolonicSummaryCodeOptions.E4_IMPORTANT_REQUIRES_ACTION, + } + ) # And I set the following radiology failure reasons within the Investigation Dataset for this subject: # | No failure reasons | NOTE - this can be left as default - there is only one option - # And I open all minimized sections on the dataset # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + # When I press the save Investigation Dataset button - # And I press OK on my confirmation prompt - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - contrast_tagging_and_drug=contrast_tagging_and_drug, - tagging_agent_given_drug_information=tagging_agent_given_drug_information, - radiology_information=radiology_information, - suspected_findings=suspected_findings, - ) + # Then the Investigation Dataset result message, which I will cancel, is "Abnormal" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("Abnormal") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then my subject has been updated as follows: criteria = { @@ -662,7 +694,14 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A410", batch_description="Post-Investigation Appointment Invitation Letter", - latest_event_status="A415 - Post-investigation Appointment Invitation Letter Printed", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, ) # When I view the subject @@ -698,7 +737,11 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A430", batch_description="Result Letters Following Post-investigation Appointment", - latest_event_status="A395 - Refer Another Diagnostic Test", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, {"latest event status": "A395 Refer Another Diagnostic Test"} ) # When I view the subject @@ -818,10 +861,23 @@ def test_scenario_8(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I open all minimized sections on the dataset # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: # | Mannitol | 3 | - drug_information = get_default_drug_information() + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And I set the following fields and values within the Investigation Dataset for this subject: # | Screening Site | (Pick first option) | @@ -843,29 +899,50 @@ def test_scenario_8(page: Page) -> None: # | Insufflation | Air | # | Outcome at time of procedure | Leave department | # | Late outcome | No complications | - general_information = get_default_general_information() - endoscopy_information = get_default_endoscopy_information() - endoscopy_information["procedure type"] = "diagnostic" + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": 1, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: # | Pain | - failure_information = { - "failure reasons": FailureReasonsOptions.PAIN, - } - - # And I mark the Investigation Dataset as completed - # And I press the save Investigation Dataset button - # When I press the save Investigation Dataset button - # And I press OK on my confirmation prompt - InvestigationDatasetCompletion(page).complete_dataset_with_args( - general_information=general_information, - drug_information=drug_information, - endoscopy_information=endoscopy_information, - failure_information=failure_information, + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} ) + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button # Then the Investigation Dataset result message, which I will cancel, is "No Result" - InvestigationDatasetsPage(page).expect_text_to_be_visible("No Result") + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then my subject has been updated as follows: criteria = { @@ -940,7 +1017,11 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A318", batch_description="Result Letters - No Post-investigation Appointment", - latest_event_status="A380 - Failed Diagnostic Test - Refer Another", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, {"latest event status": "A380 Failed Diagnostic Test - Refer Another"} ) # When I view the subject @@ -959,17 +1040,23 @@ def test_scenario_8(page: Page) -> None: } subject_assertion(nhs_no, criteria) - # # And there is a "A397" letter batch for my subject with the exact title "Discharge from screening round - no contact (letter to patient)" - # # When I process the open "A397" letter batch for my subject - # # Then my subject has been updated as follows: + # And there is a "A397" letter batch for my subject with the exact title "Discharge from screening round - no contact (letter to patient)" + # When I process the open "A397" letter batch for my subject batch_processing( page=page, batch_type="A397", batch_description="Discharge from screening round - no contact (letter to patient)", - latest_event_status="A391 - Patient Discharge Letter Printed - No Patient Contact", ) - # # When I receive an SSPI update to change their date of birth to "73" years old + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A391 Patient Discharge Letter Printed - No Patient Contact" + }, + ) + + # When I receive an SSPI update to change their date of birth to "73" years old SSPIChangeSteps().sspi_update_to_change_dob_received(nhs_no, 73) # Then my subject has been updated as follows: @@ -984,7 +1071,6 @@ def test_scenario_8(page: Page) -> None: page=page, batch_type="A391", batch_description="Discharge from screening round - no contact (letter to GP)", - latest_event_status="A351 - GP Discharge Letter Printed - No Patient Contact", ) # Then my subject has been updated as follows: diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_4.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_4.py index 47fa3986..1833ec42 100644 --- a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_4.py +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_4.py @@ -215,11 +215,21 @@ def test_scenario_4(page: Page) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) @@ -238,46 +248,49 @@ def test_scenario_4(page: Page) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "diagnostic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.PAIN} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} + ) - # And I open all minimized sections on the dataset # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - ) + # Then the Investigation Dataset result message, which I will cancel, is "No Result" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") - # Then the Investigation Dataset result message is "No Result" - InvestigationDatasetsPage(page).expect_text_to_be_visible("No Result") + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_5.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_5.py index c3e2329b..c03dfebf 100644 --- a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_5.py +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_5.py @@ -235,11 +235,21 @@ def test_scenario_5(page: Page, general_properties: dict) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) @@ -258,46 +268,49 @@ def test_scenario_5(page: Page, general_properties: dict) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "diagnostic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.PAIN} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} + ) - # And I open all minimized sections on the dataset # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - ) + # Then the Investigation Dataset result message, which I will cancel, is "No Result" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") - # Then the Investigation Dataset result message is "No Result" - InvestigationDatasetsPage(page).expect_text_to_be_visible("No Result") + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_8.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_8.py index e510f314..de7bc46e 100644 --- a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_8.py +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_8.py @@ -2,7 +2,9 @@ from playwright.sync_api import Page from classes.repositories.subject_repository import SubjectRepository from pages.organisations.organisations_page import OrganisationSwitchPage -from pages.screening_subject_search.high_risk_findings_result_from_symptomatic_procedure_page import HighRiskFindingsResultFromSymptomaticProcedure +from pages.screening_subject_search.high_risk_findings_result_from_symptomatic_procedure_page import ( + HighRiskFindingsResultFromSymptomaticProcedure, +) from pages.screening_subject_search.refer_to_mdt_page import ReferToMDTPage from pages.screening_subject_search.reopen_episode_page import ReopenEpisodePage from pages.screening_subject_search.reopen_surveillance_episode_page import ( @@ -60,6 +62,7 @@ ReasonForSymptomaticReferral, ) + @pytest.mark.vpn_required @pytest.mark.regression @pytest.mark.surveillance_regression_tests @@ -349,11 +352,21 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) @@ -372,46 +385,49 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "diagnostic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.PAIN} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} + ) - # And I open all minimized sections on the dataset # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - ) + # Then the Investigation Dataset result message, which I will cancel, is "No Result" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") - # Then the Investigation Dataset result message is "No Result" - InvestigationDatasetsPage(page).expect_text_to_be_visible("No Result") + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() # Then my subject has been updated as follows: subject_assertion( @@ -527,6 +543,7 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: "surveillance due date reason": "# Not checking - probably hasn't changed", } subject_assertion(nhs_no, criteria) + # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) @@ -542,9 +559,11 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: # And I select Diagnostic Test Type "Colonoscopy" AdvanceSurveillanceEpisodePage(page).select_test_type_dropdown_option("Colonoscopy") + # And I enter a Diagnostic Test First Offered Appointment Date of "today" AdvanceSurveillanceEpisodePage(page).click_calendar_button() CalendarPicker(page).v1_calender_picker(datetime.today()) + # And I advance the subject's episode for "Invite for Diagnostic Test >>" AdvanceSurveillanceEpisodePage(page).click_invite_for_diagnostic_test_button() @@ -556,10 +575,12 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: # When I select the advance episode option for "Attend Diagnostic Test" AdvanceSurveillanceEpisodePage(page).click_attend_diagnostic_test_button() + # And I attend the subject's diagnostic test today AttendDiagnosticTestPage(page).click_calendar_button() CalendarPicker(page).v1_calender_picker(datetime.today()) AttendDiagnosticTestPage(page).click_save_button() + # Then my subject has been updated as follows: subject_assertion( nhs_no, @@ -568,14 +589,22 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: # When I view the subject screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + # And I edit the Investigation Dataset for this subject SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) + # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) criteria = { @@ -591,44 +620,51 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: person_name = ( f"{df['person_family_name'].iloc[0]} {df['person_given_name'].iloc[0]}" ) + # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "diagnostic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) + # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.PAIN} - # And I open all minimized sections on the dataset + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} + ) + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - ) - # Then the Investigation Dataset result message is "No Result" - InvestigationDatasetsPage(page).expect_text_to_be_visible("No Result") - # Then my subject has been updated as follows: + # Then the Investigation Dataset result message, which I will cancel, is "No Result" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() subject_assertion( nhs_no, @@ -732,9 +768,9 @@ def test_scenario_8(page: Page, general_properties: dict) -> None: ).click_high_risk_findings_result_from_symptomatic_procedure_button() # And I set the Date of Symptomatic Procedure to "yesterday" - HighRiskFindingsResultFromSymptomaticProcedure(page).enter_date_of_symptomatic_procedure( - datetime.today() - timedelta(days=1) - ) + HighRiskFindingsResultFromSymptomaticProcedure( + page + ).enter_date_of_symptomatic_procedure(datetime.today() - timedelta(days=1)) # And the Screening Interval is 36 months HighRiskFindingsResultFromSymptomaticProcedure(page).assert_text_in_alert_textbox( "recall interval of 36 months" diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_9.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_9.py index 04095eb2..8921db28 100644 --- a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_9.py +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_9.py @@ -233,11 +233,21 @@ def test_scenario_9(page: Page, general_properties: dict) -> None: SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + # And I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: - drug_information = { - "drug_dose1": "3", - "drug_type1": DrugTypeOptions.MANNITOL, - } + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) # And there is a clinician who meets the following criteria: user = User.from_user_role_type(user_role) @@ -256,49 +266,52 @@ def test_scenario_9(page: Page, general_properties: dict) -> None: ) # And I set the following fields and values within the Investigation Dataset for this subject: - general_information = { - "practitioner": 1, - "site": 1, - "testing clinician": person_name, - "aspirant endoscopist": None, - } + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) - endoscopy_information = { - "endoscope inserted": "yes", - "procedure type": "diagnostic", - "bowel preparation quality": BowelPreparationQualityOptions.GOOD, - "comfort during recovery": ComfortOptions.NO_DISCOMFORT, - "comfort during examination": ComfortOptions.NO_DISCOMFORT, - "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, - "scope imager used": YesNoOptions.YES, - "retroverted view": YesNoOptions.NO, - "start of intubation time": "09:00", - "start of extubation time": "09:30", - "end time of procedure": "10:00", - "scope id": "Autotest", - "insufflation": InsufflationOptions.AIR, - "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, - "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, - } + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) # And I set the following failure reasons within the Investigation Dataset for this subject: - failure_information = {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) - # And I open all minimized sections on the dataset # And I mark the Investigation Dataset as completed - # When I press the save Investigation Dataset button - InvestigationDatasetCompletion(page).complete_dataset_with_args( - endoscopy_information=endoscopy_information, - drug_information=drug_information, - general_information=general_information, - failure_information=failure_information, - ) + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() - # Then the Investigation Dataset result message is "Normal (No Abnormalities Found)" - InvestigationDatasetsPage(page).expect_text_to_be_visible( + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "Normal (No Abnormalities Found)" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog( "Normal (No Abnormalities Found)" ) + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + # And I confirm the Episode Result is "Normal (No Abnormalities Found)" EpisodeRepository().confirm_episode_result( nhs_no, "Normal (No Abnormalities Found)" diff --git a/tests/regression/regression_tests/test_regression_test_setup_steps.py b/tests/regression/regression_tests/test_regression_test_setup_steps.py index 6156a4ee..c847ede1 100644 --- a/tests/regression/regression_tests/test_regression_test_setup_steps.py +++ b/tests/regression/regression_tests/test_regression_test_setup_steps.py @@ -16,10 +16,8 @@ set_org_parameter_value, check_parameter, ) -from utils.oracle.oracle_specific_functions.screening_colonoscopist import ( - build_accredited_screening_colonoscopist_query, - get_accredited_screening_colonoscopist_in_bcs001, -) +from classes.repositories.person_repository import PersonRepository +from utils.oracle.oracle import OracleDB def test_allow_10_minute_colonsocopy_assessment_appointments( @@ -56,17 +54,48 @@ def test_asc_with_current_resect_and_discard_accreditation( """ UserTools.user_login(page, "BCSS Bureau Staff at X26") - current_df = build_accredited_screening_colonoscopist_query("Current") - if current_df.empty: + criteria = { + "Person has current role": "Accredited Screening Colonoscopist", + "Person has current role in organisation": "BCS001", + "Resect & Discard Accreditation Status": "Current", + } + query = PersonRepository().build_person_selection_query( + criteria=criteria, person=None, required_person_count=1, user=None, subject=None + ) + logging.info(f"Final query: {query}") + current_df = OracleDB().execute_query(query) + + if not current_df.empty: pytest.skip( - "No Accredited Screening Colonoscopist with current Resect & Discard accreditation found." + "Accredited Screening Colonoscopist with current Resect & Discard accreditation found." ) - expired_df = build_accredited_screening_colonoscopist_query("Expiring soon") - if expired_df.empty: + + criteria = { + "Person has current role": "Accredited Screening Colonoscopist", + "Person has current role in organisation": "BCS001", + "Resect & Discard Accreditation Status": "Expiring soon", + } + query = PersonRepository().build_person_selection_query( + criteria=criteria, person=None, required_person_count=1, user=None, subject=None + ) + logging.info(f"Final query: {query}") + expired_df = OracleDB().execute_query(query) + + if not expired_df.empty: pytest.skip( - "No Accredited Screening Colonoscopist with expiring Resect & Discard accreditation found." + "Accredited Screening Colonoscopist with expiring Resect & Discard accreditation found." ) - person_df = get_accredited_screening_colonoscopist_in_bcs001() + + criteria = { + "Person has current role": "Accredited Screening Colonoscopist", + "Person has current role in organisation": "BCS001", + } + query = PersonRepository().build_person_selection_query( + criteria=criteria, person=None, required_person_count=1, user=None, subject=None + ) + logging.info(f"Final query: {query}") + person_df = OracleDB().execute_query(query) + if person_df.empty: pytest.fail("No Accredited Screening Colonoscopist found in the database.") @@ -75,10 +104,11 @@ def test_asc_with_current_resect_and_discard_accreditation( surname = person_df.iloc[0]["person_family_name"] forename = person_df.iloc[0]["person_given_name"] + person_id = person_df.iloc[0]["prs_id"] MaintainContactsPage(page).fill_surname_input_field(surname) MaintainContactsPage(page).fill_forenames_input_field(forename) MaintainContactsPage(page).click_search_button() - MaintainContactsPage(page).click_person_link_from_surname(surname) + MaintainContactsPage(page).select_person_by_id(person_id) EditContactPage(page).click_view_resect_and_discard_link() ResectAndDiscardAccreditationHistoryPage(page).verify_heading_is_correct() diff --git a/utils/subject_assertion.py b/utils/subject_assertion.py index d2ec850a..4630adbe 100644 --- a/utils/subject_assertion.py +++ b/utils/subject_assertion.py @@ -51,7 +51,11 @@ def subject_assertion( failed_criteria = [] criteria_keys = [key for key in criteria if key != nhs_number_string] for key in criteria_keys: + # Always include keys that start with 'which' (case-insensitive) in the query single_criteria = {nhs_number_string: nhs_number, key: criteria[key]} + for k in criteria_keys: + if k.lower().startswith("which") and k != key: + single_criteria[k] = criteria[k] query, bind_vars = builder.build_subject_selection_query( criteria=single_criteria, user=user, @@ -64,13 +68,10 @@ def subject_assertion( subject_nhs_number_string not in df.columns or nhs_number not in df[subject_nhs_number_string].values ): - actual_value = ( - df[key].iloc[0] if key in df.columns and not df.empty else "" - ) logging.warning( - f"[ASSERTION MISMATCH] Key: '{key}' | Expected: '{criteria[key]}' | Actual: '{actual_value}'" + f"[ASSERTION MISMATCH] Key: '{key}' | Expected: '{criteria[key]}'" ) - failed_criteria.append((key, criteria[key], actual_value)) + failed_criteria.append((key, criteria[key])) if failed_criteria: log_message = ( From 358f6760f4dbbdb8541fe7ca0794d056b30a745a Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Thu, 18 Dec 2025 19:12:58 +0000 Subject: [PATCH 3/9] Fixing spelling mistake --- pages/datasets/investigation_dataset_page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/datasets/investigation_dataset_page.py b/pages/datasets/investigation_dataset_page.py index e82bdad2..82078482 100644 --- a/pages/datasets/investigation_dataset_page.py +++ b/pages/datasets/investigation_dataset_page.py @@ -424,7 +424,7 @@ def click_save_dataset_button(self) -> None: def click_save_dataset_button_assert_dialog(self, expected_text: str) -> None: """ Clicks on the save dataset button and performs an assertion of the resulting dialog text. - Once done dismissed the dialog. + Once done it dismisses the dialog. Args: expected_text (str): The expected text in the resultant dialog """ From a7a1b95b083c9f0d980311ae4266d7e125036890 Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Fri, 19 Dec 2025 11:36:43 +0000 Subject: [PATCH 4/9] Completing scenario 11 of surveillance regression tests --- .../contact_with_patient_page.py | 16 + .../diagnostic_test_outcome_page.py | 18 + .../test_surveillance_scenario_11.py | 693 ++++++++++++++++++ 3 files changed, 727 insertions(+) create mode 100644 tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_11.py diff --git a/pages/screening_subject_search/contact_with_patient_page.py b/pages/screening_subject_search/contact_with_patient_page.py index 8487928c..00f5954c 100644 --- a/pages/screening_subject_search/contact_with_patient_page.py +++ b/pages/screening_subject_search/contact_with_patient_page.py @@ -2,6 +2,7 @@ from pages.base_page import BasePage from utils.calendar_picker import CalendarPicker from datetime import datetime +from typing import List class ContactWithPatientPage(BasePage): @@ -149,6 +150,21 @@ def record_contact(self, outcome: str, patient_contacted: str = "Yes") -> None: self.select_outcome_dropdown_option(outcome) self.click_save_button() + def outcome_dropdown_contains_options(self, options: List[str]) -> None: + """ + Asserts that all provided options are present in the Outcome of Diagnostic Test dropdown. + + Args: + options (List[str]): List of option strings to check. + """ + dropdown_options = [ + opt.inner_text() for opt in self.outcome_dropdown.locator("option").all() + ] + for item in options: + assert ( + item in dropdown_options + ), f"Dropdown is missing expected option: '{item}'" + def verify_contact_with_patient_page_is_displayed(self) -> None: """Verify that the 'Contact With Patient' page is displayed.""" expect(self.bowel_cancer_screening_ntsh_page_title).to_have_text( diff --git a/pages/screening_subject_search/diagnostic_test_outcome_page.py b/pages/screening_subject_search/diagnostic_test_outcome_page.py index c29a02b1..90ab9715 100644 --- a/pages/screening_subject_search/diagnostic_test_outcome_page.py +++ b/pages/screening_subject_search/diagnostic_test_outcome_page.py @@ -84,6 +84,24 @@ def test_outcome_dropdown_contains_options(self, options: List[str]) -> None: item in dropdown_options ), f"Dropdown is missing expected option: '{item}'" + def reason_for_onward_referral_dropdown_contains_options( + self, options: List[str] + ) -> None: + """ + Asserts that all provided options are present in the Outcome of Diagnostic Test dropdown. + + Args: + options (List[str]): List of option strings to check. + """ + dropdown_options = [ + opt.inner_text() + for opt in self.reason_for_onward_referral_dropdown.locator("option").all() + ] + for item in options: + assert ( + item in dropdown_options + ), f"Dropdown is missing expected option: '{item}'" + def verify_reason_for_symptomatic_referral(self, symptomatic_reason: str) -> None: """ Verify reason for symptomatic referral is visible. diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_11.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_11.py new file mode 100644 index 00000000..419c1faf --- /dev/null +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_11.py @@ -0,0 +1,693 @@ +import logging +from datetime import datetime +import pytest +from playwright.sync_api import Page + +from classes.repositories.person_repository import PersonRepository +from classes.user.user import User +from pages.datasets.colonoscopy_dataset_page import ( + ColonoscopyDatasetsPage, + FitForColonoscopySspOptions, +) +from pages.datasets.investigation_dataset_page import ( + AdenomaSubTypeOptions, + BowelPreparationQualityOptions, + ComfortOptions, + CompletionProofOptions, + DrugTypeOptions, + EndoscopyLocationOptions, + FailureReasonsOptions, + InsufflationOptions, + InvestigationDatasetsPage, + LateOutcomeOptions, + OutcomeAtTimeOfProcedureOptions, + PolypAccessOptions, + PolypClassificationOptions, + PolypDysplasiaOptions, + PolypExcisionCompleteOptions, + PolypInterventionDeviceOptions, + PolypInterventionExcisionTechniqueOptions, + PolypInterventionModalityOptions, + PolypInterventionRetrievedOptions, + PolypTypeOptions, + ReasonPathologyLostOptions, + YesNoOptions, + YesNoUncertainOptions, +) +from pages.datasets.subject_datasets_page import SubjectDatasetsPage +from pages.logout.log_out_page import LogoutPage +from pages.screening_subject_search.advance_surveillance_episode_page import ( + AdvanceSurveillanceEpisodePage, +) +from pages.screening_subject_search.attend_diagnostic_test_page import ( + AttendDiagnosticTestPage, +) +from pages.screening_subject_search.contact_with_patient_page import ( + ContactWithPatientPage, +) +from pages.screening_subject_search.diagnostic_test_outcome_page import ( + DiagnosticTestOutcomePage, + OutcomeOfDiagnosticTest, + ReasonForOnwardReferral, + ReferralProcedureType, +) +from pages.screening_subject_search.subject_screening_summary_page import ( + SubjectScreeningSummaryPage, +) +from utils import screening_subject_page_searcher +from utils.batch_processing import batch_processing +from utils.calendar_picker import CalendarPicker +from utils.dataset_field_util import DatasetFieldUtil +from utils.generate_health_check_forms_util import GenerateHealthCheckFormsUtil +from utils.investigation_dataset import InvestigationDatasetCompletion +from utils.oracle.oracle import OracleDB +from utils.sspi_change_steps import SSPIChangeSteps +from utils.subject_assertion import subject_assertion +from utils.user_tools import UserTools + + +@pytest.mark.vpn_required +@pytest.mark.regression +@pytest.mark.surveillance_regression_tests +def test_scenario_11(page: Page, general_properties: dict) -> None: + """ + Scenario: 11: Close on existing LNPCP result + + X500-X505-A99-A59-A259-A315-A361-A323-A317-A318-A395-A99-A59-A306-A400-A157-C203 [SSCL52b] + + This scenario tests where a subject has had one diagnostic test and been referred for a second, which is cancelled. Then contact with the subject is lost and the episode is closed on the existing result of LNPCP. Below age at recall, the subject remains in Surveillance. + + Scenario summary: + + > Run surveillance invitations for 1 subject > X500 (3.1) + > SSPI update changes subject to below-age at recall + > Process X500 letter batch > X505 (3.1) + > Complete the colonoscopy assessment dataset - fit for colonoscopy + > Record patient contact โ€“ contacted, suitable for colonoscopy > A99 (3.1) + > Invite for diagnostic test > A59 (2.1) + > Attend diagnostic test > A259 (2.1) + > Complete investigation dataset โ€“ LNPCP (2.1) + > Enter diagnostic test outcome โ€“ refer another test > A315 (2.1) + > Post-investigation appointment not required > A361 (2.1) + > Record patient contact โ€“ post-investigation appointment not required > A323 (2.1) > A317 > A318 (2.5) + > Process A318 letter batch > A395 (2.5) + > Record patient contact โ€“ suitable for colonoscopy > A99 (2.3) + > Invite for diagnostic test > A59 (2.1) + > Cancel diagnostic test > A306 (2.1) + > Record patient contact โ€“ not contacted, close on existing result > A400 (2.2) + > Process A400 letter batch > A157 (2.2) > C203 (3.6) + > Check recall [SSCL52b] + """ + # Given I log in to BCSS "England" as user role "Screening Centre Manager" + user_role = UserTools.user_login( + page, "Screening Centre Manager at BCS001", return_role_type=True + ) + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") + + # When I run surveillance invitations for 1 subject + org_id = general_properties["eng_screening_centre_id"] + nhs_no = GenerateHealthCheckFormsUtil(page).invite_surveillance_subjects_early( + org_id + ) + logging.info(f"[SUBJECT RETRIEVAL] Subject's NHS Number: {nhs_no}") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode status": "Open", + "latest episode type": "Surveillance", + "latest event status": "X500 Selected For Surveillance", + "responsible screening centre code": "User's screening centre", + "subject has unprocessed SSPI updates": "No", + "subject has user DOB updates": "No", + }, + user_role, + ) + + # And I receive an SSPI update to change their date of birth to "44" years old + SSPIChangeSteps().sspi_update_to_change_dob_received(nhs_no, 44) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"subject age": "44"}) + + # And there is a "X500" letter batch for my subject with the exact title "Surveillance Selection" + # When I process the open "X500" letter batch for my subject + batch_processing( + page, + "X500", + "Surveillance Selection", + ) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"latest event status": "X505 HealthCheck Form Printed"}) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Colonoscopy Assessment Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_colonoscopy_show_datasets() + + # And I update the Colonoscopy Assessment Dataset with the following values: + ColonoscopyDatasetsPage(page).select_fit_for_colonoscopy_option( + FitForColonoscopySspOptions.YES + ) + ColonoscopyDatasetsPage(page).click_dataset_complete_radio_button_yes() + + # And I save the Colonoscopy Assessment Dataset + ColonoscopyDatasetsPage(page).save_dataset() + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Record Contact with Patient" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_record_contact_with_patient_button() + + # And I record contact with the subject with outcome "Suitable for Endoscopic Test" + ContactWithPatientPage(page).record_contact("Suitable for Endoscopic Test") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A99 Suitable for Endoscopic Test", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the advance episode options + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select Diagnostic Test Type "Limited Colonoscopy" + AdvanceSurveillanceEpisodePage(page).select_test_type_dropdown_option( + "Limited Colonoscopy" + ) + + # And I select Intended Extent "Ascending Colon" + AdvanceSurveillanceEpisodePage(page).select_intended_extent_dropdown_option( + "Ascending Colon" + ) + + # And I enter a Diagnostic Test First Offered Appointment Date of "today" + AdvanceSurveillanceEpisodePage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + + # And I advance the subject's episode for "Invite for Diagnostic Test >>" + AdvanceSurveillanceEpisodePage(page).click_invite_for_diagnostic_test_button() + + page.wait_for_timeout(500) # Timeout to allow subject to update on the DB + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A59 Invited for Diagnostic Test", + }, + ) + + # When I select the advance episode option for "Attend Diagnostic Test" + AdvanceSurveillanceEpisodePage(page).click_attend_diagnostic_test_button() + + # And I attend the subject's diagnostic test today + AttendDiagnosticTestPage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + AttendDiagnosticTestPage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A259 Attended Diagnostic Test"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Investigation Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # Then I get a confirmation prompt that "contains" "The Endoscopist Defined Extent selected indicates that the diagnostic test type is Colonoscopy." + # When I press OK on my confirmation prompt + InvestigationDatasetsPage(page).assert_dialog_text( + "The Endoscopist Defined Extent selected indicates that the diagnostic test type is Colonoscopy.", + True, + ) + + # When I set the following fields and values within the Investigation Dataset for this subject: + DatasetFieldUtil(page).populate_select_locator_for_field( + "Endoscopist defined extent", EndoscopyLocationOptions.CAECUM + ) + + # Then I confirm the "Investigation Dataset" section of the dataset contains the field "Actual Type of Test" with the value of "Colonoscopy" + DatasetFieldUtil(page).assert_cell_to_right_has_expected_text( + "Actual Type of Test", "Colonoscopy" + ) + + # When I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) + + # And there is a clinician who meets the following criteria: + user = User.from_user_role_type(user_role) + criteria = { + "Person has current role": "Accredited Screening Colonoscopist", + "Person has current role in organisation": "User's SC", + "Resect & Discard accreditation status": "None", + } + query = PersonRepository().build_person_selection_query( + criteria=criteria, person=None, required_person_count=1, user=user, subject=None + ) + df = OracleDB().execute_query(query) + person_name = ( + f"{df["person_family_name"].iloc[0]} {df["person_given_name"].iloc[0]}" + ) + + # And I set the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) + + # And I set the following completion proof values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) + + # And I set the following failure reasons within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) + + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.SPLENIC_FLEXURE, + "classification": PolypClassificationOptions.IP, + "estimate of whole polyp size": "11", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 1, + ) + + # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + }, + 1, + ) + + # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( + { + "date of receipt": datetime.today(), + "date of reporting": datetime.today(), + "pathology provider": 1, + "pathologist": 1, + "polyp type": PolypTypeOptions.ADENOMA, + "adenoma sub type": AdenomaSubTypeOptions.NOT_REPORTED, + "polyp excision complete": PolypExcisionCompleteOptions.R1, + "polyp size": "13", + "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, + "polyp carcinoma": YesNoUncertainOptions.NO, + }, + 1, + ) + + # And I add new polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.CAECUM, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "5", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 2, + ) + + # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 2, + ) + + # And I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( + { + "date of receipt": datetime.today(), + "date of reporting": datetime.today(), + "pathology provider": 1, + "pathologist": 1, + "polyp type": PolypTypeOptions.ADENOMA, + "adenoma sub type": AdenomaSubTypeOptions.TUBULAR_ADENOMA, + "polyp excision complete": PolypExcisionCompleteOptions.R1, + "polyp size": "4", + "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, + "polyp carcinoma": YesNoUncertainOptions.NO, + }, + 2, + ) + + # And I add new polyp 3 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.HEPATIC_FLEXURE, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "21", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 3, + ) + + # And I add intervention 1 for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + "polyp appears fully resected endoscopically": YesNoOptions.YES, + }, + 3, + ) + + # And I update histology details for polyp 2 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( + { + "pathology lost": YesNoOptions.YES, + "reason pathology lost": ReasonPathologyLostOptions.LOST_IN_TRANSIT, + }, + 3, + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "LNPCP" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("LNPCP") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + + # Then I confirm the Polyp Algorithm Size for Polyp 1 is 13 + InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "13") + + # And I confirm the Polyp Algorithm Size for Polyp 2 is 4 + InvestigationDatasetsPage(page).assert_polyp_algorithm_size(2, "4") + + # And I confirm the Polyp Algorithm Size for Polyp 3 is 21 + InvestigationDatasetsPage(page).assert_polyp_algorithm_size(3, "21") + + # And I confirm the Polyp Category for Polyp 1 is "Advanced colorectal polyp" + InvestigationDatasetsPage(page).assert_polyp_category( + 1, "Advanced colorectal polyp" + ) + + # And I confirm the Polyp Category for Polyp 2 is "Premalignant polyp" + InvestigationDatasetsPage(page).assert_polyp_category(2, "Premalignant polyp") + + # And I confirm the Polyp Category for Polyp 3 is "LNPCP" + InvestigationDatasetsPage(page).assert_polyp_category(3, "LNPCP") + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Enter Diagnostic Test Outcome" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_enter_diagnostic_test_outcome_button() + + # Then I confirm the Outcome Of Diagnostic Test dropdown has the following options: + DiagnosticTestOutcomePage(page).test_outcome_dropdown_contains_options( + [ + "Refer Another Diagnostic Test", + "Refer Symptomatic", + "Refer Surveillance (BCSP)", + ], + ) + + # When I select Outcome of Diagnostic Test "Refer Surveillance (BCSP)" + DiagnosticTestOutcomePage(page).select_test_outcome_option( + OutcomeOfDiagnosticTest.REFER_ANOTHER_DIAGNOSTIC_TEST + ) + + # And I select Radiological or Endoscopic Referral value "Endoscopic" + DiagnosticTestOutcomePage(page).select_referral_procedure_type( + ReferralProcedureType.ENDOSCOPIC + ) + + # Then I confirm the Reason for Onward Referral dropdown has the following options: + DiagnosticTestOutcomePage( + page + ).reason_for_onward_referral_dropdown_contains_options( + [ + "Polyp not Fully Excised", + "Check Polyp Site", + "Multiple Polyps, not all Removed", + "Histology Required", + "Unexplained Symptoms", + "Interventions Required", + "Incomplete Colonic Visualisation", + ] + ) + + # And I select Reason for Onward Referral value "Check Polyp Site" + DiagnosticTestOutcomePage(page).select_reason_for_onward_referral( + ReasonForOnwardReferral.CHECK_POLYP_SITE + ) + + # And I set any onward referring clinician + DiagnosticTestOutcomePage(page).select_valid_onward_referral_consultant_index(1) + + # And I save the Diagnostic Test Outcome + DiagnosticTestOutcomePage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A315 Diagnostic Test Outcome Entered"}, + ) + + # When I advance the subject's episode for "Other Post-investigation Contact Required" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_other_post_investigation_contact_required_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A361 Other Post-investigation Contact Required"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Record other post-investigation contact" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_record_other_post_investigation_contact_button() + + # And I confirm the patient outcome dropdown has the following options: + ContactWithPatientPage(page).outcome_dropdown_contains_options( + [ + "Post-investigation Appointment Not Required", + "Post-investigation Appointment Required", + "No outcome", + ] + ) + + # And I record contact with the subject with outcome "Post-investigation Appointment Not Required" + ContactWithPatientPage(page).record_post_investigation_appointment_not_required() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A318 Post-investigation Appointment NOT Required - Result Letter Created" + }, + ) + + # And there is a "A318" letter batch for my subject with the exact title "Result Letters - No Post-investigation Appointment" + # When I process the open "A318" letter batch for my subject + batch_processing( + page, + "A318", + "Result Letters - No Post-investigation Appointment", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, {"latest event status": "A395 Refer Another Diagnostic Test"} + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # When I select the advance episode option for "Record Contact with Patient" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_record_contact_with_patient_button() + + # And I record contact with the subject with outcome "Suitable for Endoscopic Test" + ContactWithPatientPage(page).record_contact("Suitable for Endoscopic Test") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A99 Suitable for Endoscopic Test", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the advance episode options + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select Diagnostic Test Type "Colonoscopy" + AdvanceSurveillanceEpisodePage(page).select_test_type_dropdown_option("Colonoscopy") + + # And I enter a Diagnostic Test First Offered Appointment Date of "today" + AdvanceSurveillanceEpisodePage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + + # And I advance the subject's episode for "Invite for Diagnostic Test >>" + AdvanceSurveillanceEpisodePage(page).click_invite_for_diagnostic_test_button() + + page.wait_for_timeout(500) # Timeout to allow subject to update on the DB + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A59 Invited for Diagnostic Test", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I advance the subject's episode for "Cancel Diagnostic Test" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_cancel_diagnostic_test_button() + + # Then my subject has been updated as follows: + AdvanceSurveillanceEpisodePage(page).verify_latest_event_status_value( + "A306 - Cancel Diagnostic Test" + ) + + # And I select the advance episode option for "Record Contact with Patient" + AdvanceSurveillanceEpisodePage(page).click_record_contact_with_patient_button() + + # And I record contact with the subject with values: + ContactWithPatientPage(page).record_contact( + "Close Episode with Existing result", "No" + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A400 Follow-up Test Cancelled by Screening Centre"}, + ) + + # And there is a "A400" letter batch for my subject with the exact title "Follow-up Test Cancelled by Screening Centre" + # When I process the open "A400" letter batch for my subject + batch_processing( + page, + "A400", + "Follow-up Test Cancelled by Screening Centre", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Latest not-void test in latest episode", + "calculated fobt due date": "Unchanged", + "calculated lynch due date": "Null", + "calculated surveillance due date": "3 years from diagnostic test", + "ceased confirmation date": "Null", + "ceased confirmation details": "Null", + "ceased confirmation user id": "Null", + "clinical reason for cease": "Null", + "latest episode accumulated result": "LNPCP", + "latest episode recall calculation method": "Diagnostic test date", + "latest episode recall episode type": "Surveillance - LNPCP", + "latest episode recall surveillance type": "LNPCP", + "latest episode status": "Closed", + "latest episode status reason": "Episode Complete", + "latest event status": "A157 LNPCP", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Null", + "screening due date date of change": "Unchanged", + "screening due date reason": "Unchanged", + "screening status": "Surveillance", + "screening status date of change": "Unchanged", + "screening status reason": "Unchanged", + "surveillance due date": "Calculated Surveillance due date", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Result - LNPCP", + "symptomatic procedure date": "Null", + "symptomatic procedure result": "Null", + "screening referral type": "Null", + }, + ) + + LogoutPage(page).log_out() From a1ecb4f19257063d89c867fcf1718b46bcba98e7 Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Mon, 22 Dec 2025 10:19:01 +0000 Subject: [PATCH 5/9] Initial commit --- .../test_surveillance_scenario_12.py | 560 ++++++++++++++++++ 1 file changed, 560 insertions(+) create mode 100644 tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_12.py diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_12.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_12.py new file mode 100644 index 00000000..ea6cdda0 --- /dev/null +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_12.py @@ -0,0 +1,560 @@ +import logging +from datetime import datetime +import pytest +from playwright.sync_api import Page + +from classes.repositories.person_repository import PersonRepository +from classes.user.user import User +from pages.datasets.colonoscopy_dataset_page import ( + ColonoscopyDatasetsPage, + FitForColonoscopySspOptions, +) +from pages.datasets.investigation_dataset_page import ( + AdenomaSubTypeOptions, + BowelPreparationQualityOptions, + ComfortOptions, + CompletionProofOptions, + DrugTypeOptions, + EndoscopyLocationOptions, + FailureReasonsOptions, + InsufflationOptions, + InvestigationDatasetsPage, + LateOutcomeOptions, + OutcomeAtTimeOfProcedureOptions, + PolypAccessOptions, + PolypClassificationOptions, + PolypDysplasiaOptions, + PolypExcisionCompleteOptions, + PolypInterventionDeviceOptions, + PolypInterventionExcisionTechniqueOptions, + PolypInterventionModalityOptions, + PolypInterventionRetrievedOptions, + PolypTypeOptions, + ReasonPathologyLostOptions, + YesNoOptions, + YesNoUncertainOptions, +) +from pages.datasets.subject_datasets_page import SubjectDatasetsPage +from pages.logout.log_out_page import LogoutPage +from pages.screening_practitioner_appointments.appointment_detail_page import ( + AppointmentDetailPage, +) +from pages.screening_subject_search.advance_surveillance_episode_page import ( + AdvanceSurveillanceEpisodePage, +) +from pages.screening_subject_search.attend_diagnostic_test_page import ( + AttendDiagnosticTestPage, +) +from pages.screening_subject_search.contact_with_patient_page import ( + ContactWithPatientPage, +) +from pages.screening_subject_search.diagnostic_test_outcome_page import ( + DiagnosticTestOutcomePage, + OutcomeOfDiagnosticTest, + ReasonForSymptomaticReferral, +) +from pages.screening_subject_search.episode_events_and_notes_page import ( + EpisodeEventsAndNotesPage, +) +from pages.screening_subject_search.handover_into_symptomatic_care_page import ( + HandoverIntoSymptomaticCarePage, +) +from pages.screening_subject_search.subject_screening_summary_page import ( + SubjectScreeningSummaryPage, +) +from utils import screening_subject_page_searcher +from utils.appointments import book_post_investigation_appointment +from utils.batch_processing import batch_processing +from utils.calendar_picker import CalendarPicker +from utils.generate_health_check_forms_util import GenerateHealthCheckFormsUtil +from utils.investigation_dataset import InvestigationDatasetCompletion +from utils.oracle.oracle import OracleDB +from utils.sspi_change_steps import SSPIChangeSteps +from utils.subject_assertion import subject_assertion +from utils.user_tools import UserTools + + +@pytest.mark.wip +@pytest.mark.vpn_required +@pytest.mark.regression +@pytest.mark.surveillance_regression_tests +def test_scenario_12(page: Page, general_properties: dict) -> None: + """ + Scenario: 12: Unsuitable for symptomatic (do not cease) + + X500-X505-A99-A259-A315-A360-A410-A415-A416-A316-A353-A372-A357-A356-C203 [SSCL21b] + + This scenario tests the episode pathway in which the subject is referred for a symptomatic procedure, but they are discharged as being unsuitable, with no MDT referral. The subject is not ceased from the programme as part of the handover. Being still in the age range, the subject is returned to FOBT screening. + + Because we cannot know if we will be inviting a subject who has had previous FOBT episodes, or only a bowel scope episode, it is impossible to check if they will be set to Call or Recall; we can only check that they are not longer in Surveillance status. + + Scenario summary: + + > Run surveillance invitations for 1 subject > X500 (3.1) + > SSPI update changes subject to in-age at recall + > Process X500 letter batch > X505 (3.1) + > Complete the colonoscopy assessment dataset - fit for colonoscopy + > Record patient contact โ€“ contacted, suitable for colonoscopy > A99 (3.1) + > Invite for diagnostic test > A59 (2.1) + > Attend diagnostic test > A259 (2.1) + > Complete investigation dataset โ€“ LNPCP (2.1) + > Enter diagnostic test outcome โ€“ refer symptomatic > A315 (2.1) + > Post-investigation appointment required > A360 (2.1) + > Book post-investigation appointment > A410 (2.4) + > Process A410 letter batch > A415 (2.4) + > Attend post-investigation appointment > A416 > A316 (2.4) + > MDT not required > A353 (2.6) + > Process A353 letter batch > A372 (2.6) + > Unsuitable for symptomatic procedure โ€“ handover to GP, no cease > A357 (2.6) + > Process A357 letter batch > A356 > (2.6) > C203 (1.13) + > Check recall [SSCL21b] + """ + # Given I log in to BCSS "England" as user role "Screening Centre Manager" + user_role = UserTools.user_login( + page, "Screening Centre Manager at BCS001", return_role_type=True + ) + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") + + # When I run surveillance invitations for 1 subject + org_id = general_properties["eng_screening_centre_id"] + nhs_no = GenerateHealthCheckFormsUtil(page).invite_surveillance_subjects_early( + org_id + ) + logging.info(f"[SUBJECT RETRIEVAL] Subject's NHS Number: {nhs_no}") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode status": "Open", + "latest episode type": "Surveillance", + "latest event status": "X500 Selected For Surveillance", + "responsible screening centre code": "User's screening centre", + "subject has unprocessed SSPI updates": "No", + "subject has user DOB updates": "No", + }, + user_role, + ) + + # And I receive an SSPI update to change their date of birth to "70" years old + SSPIChangeSteps().sspi_update_to_change_dob_received(nhs_no, 70) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"subject age": "70"}) + + # And there is a "X500" letter batch for my subject with the exact title "Surveillance Selection" + # When I process the open "X500" letter batch for my subject + batch_processing( + page, + "X500", + "Surveillance Selection", + ) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"latest event status": "X505 HealthCheck Form Printed"}) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Colonoscopy Assessment Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_colonoscopy_show_datasets() + + # And I update the Colonoscopy Assessment Dataset with the following values: + ColonoscopyDatasetsPage(page).select_fit_for_colonoscopy_option( + FitForColonoscopySspOptions.YES + ) + ColonoscopyDatasetsPage(page).click_dataset_complete_radio_button_yes() + + # And I save the Colonoscopy Assessment Dataset + ColonoscopyDatasetsPage(page).save_dataset() + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Record Contact with Patient" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_record_contact_with_patient_button() + + # And I record contact with the subject with outcome "Suitable for Endoscopic Test" + ContactWithPatientPage(page).record_contact("Suitable for Endoscopic Test") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A99 Suitable for Endoscopic Test", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the advance episode options + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select Diagnostic Test Type "Colonoscopy" + AdvanceSurveillanceEpisodePage(page).select_test_type_dropdown_option("Colonoscopy") + + # And I enter a Diagnostic Test First Offered Appointment Date of "today" + AdvanceSurveillanceEpisodePage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + + # And I advance the subject's episode for "Invite for Diagnostic Test >>" + AdvanceSurveillanceEpisodePage(page).click_invite_for_diagnostic_test_button() + + page.wait_for_timeout(500) # Timeout to allow subject to update on the DB + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A59 Invited for Diagnostic Test", + }, + ) + + # When I select the advance episode option for "Attend Diagnostic Test" + AdvanceSurveillanceEpisodePage(page).click_attend_diagnostic_test_button() + + # And I attend the subject's diagnostic test today + AttendDiagnosticTestPage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + AttendDiagnosticTestPage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A259 Attended Diagnostic Test"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Investigation Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # When I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) + + # And there is a clinician who meets the following criteria: + user = User.from_user_role_type(user_role) + criteria = { + "Person has current role": "Accredited Screening Colonoscopist", + "Person has current role in organisation": "User's SC", + "Resect & Discard accreditation status": "None", + } + query = PersonRepository().build_person_selection_query( + criteria=criteria, person=None, required_person_count=1, user=user, subject=None + ) + df = OracleDB().execute_query(query) + person_name = ( + f"{df["person_family_name"].iloc[0]} {df["person_given_name"].iloc[0]}" + ) + + # And I set the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.APPENDIX, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.NO, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) + + # And I set the following completion proof values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_APPENDIX} + ) + + # And I set the following failure reasons within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) + + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.APPENDIX, + "classification": PolypClassificationOptions.ISP, + "estimate of whole polyp size": "19", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 1, + ) + + # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.ESD, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + "polyp appears fully resected endoscopically": YesNoOptions.YES, + }, + 1, + ) + + # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( + { + "date of receipt": datetime.today(), + "date of reporting": datetime.today(), + "pathology provider": 1, + "pathologist": 1, + "polyp type": PolypTypeOptions.ADENOMA, + "adenoma sub type": AdenomaSubTypeOptions.VILLOUS_ADENOMA, + "polyp excision complete": PolypExcisionCompleteOptions.R1, + "polyp size": "20", + "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, + "polyp carcinoma": YesNoUncertainOptions.NO, + }, + 1, + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "LNPCP" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("LNPCP") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + + # Then I confirm the Polyp Algorithm Size for Polyp 1 is 20 + InvestigationDatasetsPage(page).assert_polyp_algorithm_size(1, "20") + + # And I confirm the Polyp Category for Polyp 1 is "LNPCP" + InvestigationDatasetsPage(page).assert_polyp_category(1, "LNPCP") + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Enter Diagnostic Test Outcome" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_enter_diagnostic_test_outcome_button() + + # Then I confirm the Outcome Of Diagnostic Test dropdown has the following options: + DiagnosticTestOutcomePage(page).test_outcome_dropdown_contains_options( + [ + "Refer Another Diagnostic Test", + "Refer Symptomatic", + "Refer Surveillance (BCSP)", + ], + ) + + # When I select Outcome of Diagnostic Test "Refer Symptomatic" + DiagnosticTestOutcomePage(page).select_test_outcome_option( + OutcomeOfDiagnosticTest.REFER_SYMPTOMATIC + ) + + # And I select Reason for Symptomatic Referral value "Suspected Cancer Surgery" + DiagnosticTestOutcomePage(page).select_reason_for_symptomatic_referral_option( + ReasonForSymptomaticReferral.SUSPECTED_CANCER_SURGERY + ) + + # And I save the Diagnostic Test Outcome + DiagnosticTestOutcomePage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A315 Diagnostic Test Outcome Entered"}, + ) + + # When I advance the subject's episode for "Post-investigation Appointment Required" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_post_investigation_appointment_required_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A360 Post-investigation Appointment Required"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I choose to book a practitioner clinic for my subject + SubjectScreeningSummaryPage(page).click_book_practitioner_clinic_button() + + # And I set the practitioner appointment date to "today" + # And I book the earliest available post investigation appointment on this date + book_post_investigation_appointment(page, "The Royal Hospital (Wolverhampton)") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A410 Post-investigation Appointment Made"}, + ) + + # And there is a "A410" letter batch for my subject with the exact title "Post-Investigation Appointment Invitation Letter" + # When I process the open "A410" letter batch for my subject + batch_processing( + page, + "A410", + "Post-Investigation Appointment Invitation Letter", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the event history for the subject's latest episode + SubjectScreeningSummaryPage(page).expand_episodes_list() + SubjectScreeningSummaryPage(page).click_first_surveillance_episode_link() + + # And I view the latest practitioner appointment in the subject's episode + EpisodeEventsAndNotesPage(page).click_most_recent_view_appointment_link() + + # And I attend the subject's practitioner appointment "today" + AppointmentDetailPage(page).mark_appointment_as_attended(datetime.today()) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode includes event status": "A416 Post-investigation Appointment Attended", + "latest event status": "A316 Post-investigation Appointment Attended", + }, + ) + + # When I view the advance episode options + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I advance the subject's episode for "MDT Referral Not Required" + AdvanceSurveillanceEpisodePage(page).click_mdt_referral_not_required_button() + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"latest event status": "A353 MDT Referral Not Required"}) + + # And there is a "A353" letter batch for my subject with the exact title "GP Letter Indicating Referral to Symptomatic" + # When I process the open "A353" letter batch for my subject + batch_processing( + page, + "A353", + "GP Letter Indicating Referral to Symptomatic", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, {"latest event status": "A372 Refer Symptomatic, GP Letter Printed"} + ) + + # When I view the advance episode options + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select the advance episode option for "Patient Unfit, Handover into Symptomatic Care" + AdvanceSurveillanceEpisodePage(page).click_handover_into_symptomatic_care_button() + + # I fill in Handover into Symptomatic Care form for Patient Unfit for Treatment and do not Cease + HandoverIntoSymptomaticCarePage(page).select_referral_dropdown_option( + "Referral to Patient's GP Practice" + ) + HandoverIntoSymptomaticCarePage(page).select_practitioner_from_index(1) + HandoverIntoSymptomaticCarePage(page).fill_notes("Handover notes - unfit") + HandoverIntoSymptomaticCarePage(page).select_cease_from_program(False) + HandoverIntoSymptomaticCarePage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A357 Patient Unfit, Handover into Symptomatic Care", + }, + ) + + # And there is a "A357" letter batch for my subject with the exact title "Handover into Symptomatic Care, Patient Unfit" + # When I process the open "A357" letter batch for my subject + batch_processing( + page, + "A357", + "Handover into Symptomatic Care, Patient Unfit", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Only not-void test in latest episode", + "calculated fobt due date": "2 years from diagnostic test", + "calculated lynch due date": "Null", + "calculated surveillance due date": "Null", + "ceased confirmation date": "Null", + "ceased confirmation details": "Null", + "ceased confirmation user id": "Null", + "clinical reason for cease": "Null", + "latest episode accumulated result": "LNPCP", + "latest episode recall calculation method": "Diagnostic Test Date", + "latest episode recall episode type": "FOBT Screening", + "latest episode recall surveillance type": "Null", + "latest episode status": "Closed", + "latest episode status reason": "Discharged from Screening into Symptomatic care", + "latest event status": "A356 Handover into Symptomatic Care, Patient Unfit, GP Letter Printed", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Calculated FOBT due date", + "screening due date date of change": "Today", + "screening due date reason": "Discharged, Patient Unfit", + "screening status": "NOT: Surveillance", + "screening status date of change": "Today", + "screening status reason": "Discharged, Patient Unfit", + "surveillance due date": "Null", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Discharged, Patient Unfit", + "symptomatic procedure date": "Null", + "symptomatic procedure result": "Patient is unfit for a symptomatic procedure at this time", + "screening referral type": "Null", + }, + ) + + LogoutPage(page).log_out() From d6d993cf5438158f609c58756fca446f703c0831 Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Mon, 22 Dec 2025 10:29:32 +0000 Subject: [PATCH 6/9] Fixing SonarQube Issues --- investigation_dataset_ui.py | 107 ++++++++++++++++++--------------- utils/investigation_dataset.py | 7 ++- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/investigation_dataset_ui.py b/investigation_dataset_ui.py index fc0fe1a1..fda2ecb7 100644 --- a/investigation_dataset_ui.py +++ b/investigation_dataset_ui.py @@ -668,6 +668,51 @@ def _render_drug_entry(fields: list, index: int, result: dict) -> None: result[dose_field["key"]] = ddose +def _polyp_output_block( + pi: int, info_dict: dict, intervention: object, hist_dict: dict +) -> str: + """ + Generate the code block for a polyp's information, intervention(s), and histology. + Args: + pi (int): The polyp index (1-based). + info_dict (dict): The polyp information dictionary. + intervention (object): The polyp intervention(s), can be dict or list of dicts. + hist_dict (dict): The polyp histology dictionary. + Returns: + str: The generated code block. + """ + code_lines = [] + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_information({pretty_dict(info_dict)}, {pi})" + ) + # Intervention + if isinstance(intervention, list): + if len(intervention) > 1: + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_multiple_interventions({pretty_list(intervention)}, {pi})" + ) + elif len(intervention) == 1 and isinstance(intervention[0], dict): + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention[0])}, {pi})" + ) + else: + code_lines.append(f"# No intervention for polyp {pi}") + elif isinstance(intervention, dict): + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention)}, {pi})" + ) + else: + code_lines.append(f"# No intervention for polyp {pi}") + # Histology + if not hist_dict: + code_lines.append(f"# No histology for polyp {pi}") + else: + code_lines.append( + f"InvestigationDatasetCompletion(page).fill_polyp_x_histology({pretty_dict(hist_dict)}, {pi})" + ) + return "\n".join(code_lines) + + def show_polyp_information_and_intervention_and_histology() -> None: """ Show the Polyp Information, Intervention & Histology section, allowing multiple polyps and interventions. @@ -682,12 +727,11 @@ def show_polyp_information_and_intervention_and_histology() -> None: # Collect all fields for import analysis all_fields = polyp_info_fields + polyp_intervention_fields + polyp_histology_fields enums = get_enums_used(all_fields) - if enums: - import_block = ( - enum_import_string + new_indented_line_string.join(sorted(enums)) + "\n)\n" - ) - else: - import_block = "" + import_block = ( + enum_import_string + new_indented_line_string.join(sorted(enums)) + "\n)\n" + if enums + else "" + ) num_polyps = st.number_input( "Number of polyps", min_value=0, max_value=20, value=1, step=1 @@ -698,55 +742,22 @@ def show_polyp_information_and_intervention_and_histology() -> None: for pi in range(1, num_polyps + 1): st.markdown(f"### Polyp {pi}") - polyp_info = _render_polyp_info(polyp_info_fields, pi) - polyp_info_dicts[pi] = polyp_info + polyp_info_dicts[pi] = _render_polyp_info(polyp_info_fields, pi) interventions = _render_interventions(polyp_intervention_fields, pi) - # If interventions is a list of length 1, store as dict, else as list - if isinstance(interventions, list) and len(interventions) == 1: - polyp_interventions_dicts[pi] = interventions[0] - else: - polyp_interventions_dicts[pi] = interventions - polyp_histology = _render_histology(polyp_histology_fields, pi) - polyp_histology_dicts[pi] = polyp_histology + polyp_interventions_dicts[pi] = ( + interventions[0] + if isinstance(interventions, list) and len(interventions) == 1 + else interventions + ) + polyp_histology_dicts[pi] = _render_histology(polyp_histology_fields, pi) st.markdown("#### Output") - output_blocks = [] for pi in range(1, num_polyps + 1): info_dict = polyp_info_dicts[pi] hist_dict = polyp_histology_dicts[pi] intervention = polyp_interventions_dicts[pi] - code_lines = [] - # Information - code_lines.append( - f"InvestigationDatasetCompletion(page).fill_polyp_x_information({pretty_dict(info_dict)}, {pi})" - ) - # Intervention - if isinstance(intervention, list): - if len(intervention) > 1: - code_lines.append( - f"InvestigationDatasetCompletion(page).fill_polyp_x_multiple_interventions({pretty_list(intervention)}, {pi})" - ) - elif len(intervention) == 1 and isinstance(intervention[0], dict): - code_lines.append( - f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention[0])}, {pi})" - ) - else: - code_lines.append(f"# No intervention for polyp {pi}") - elif isinstance(intervention, dict): - code_lines.append( - f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention)}, {pi})" - ) - else: - code_lines.append(f"# No intervention for polyp {pi}") - # Histology - if not hist_dict: - code_lines.append(f"# No histology for polyp {pi}") - else: - code_lines.append( - f"InvestigationDatasetCompletion(page).fill_polyp_x_histology({pretty_dict(hist_dict)}, {pi})" - ) - output_blocks.append("\n".join(code_lines)) - st.code("\n".join(code_lines), language="python") + code_block = _polyp_output_block(pi, info_dict, intervention, hist_dict) + st.code(code_block, language="python") if import_block: st.code(import_block, language="python") diff --git a/utils/investigation_dataset.py b/utils/investigation_dataset.py index 7fd38057..aedad4dd 100644 --- a/utils/investigation_dataset.py +++ b/utils/investigation_dataset.py @@ -82,6 +82,7 @@ def __init__(self, page: Page): self.failure_reasons_string = "Failure Reasons" self.excision_technique_string = "Excision Technique" self.outcome_at_time_of_procedure_string = "Outcome at time of procedure" + self.proof_parameters_string = "Proof Parameters" self.investigation_datasets_pom = InvestigationDatasetsPage(self.page) @@ -203,7 +204,7 @@ def default_investigation_dataset_forms_continuation(self) -> None: self.investigation_datasets_pom.click_show_completion_proof_information() # Completion Proof Information DatasetFieldUtil(self.page).populate_select_locator_for_field( - "Proof Parameters", CompletionProofOptions.PHOTO_ILEO + self.proof_parameters_string, CompletionProofOptions.PHOTO_ILEO ) def investigation_datasets_failure_reason(self) -> None: @@ -373,7 +374,7 @@ def complete_dataset_with_args( if completion_information is not None: logging.info("Filling out completion proof information") DatasetFieldUtil(self.page).populate_select_locator_for_field( - "Proof Parameters", completion_information["completion proof"] + self.proof_parameters_string, completion_information["completion proof"] ) # Failure Information @@ -496,7 +497,7 @@ def fill_out_completion_information(self, completion_information: dict) -> None: logging.info("Filling out completion proof information") self.investigation_datasets_pom.click_show_completion_proof_information() DatasetFieldUtil(self.page).populate_select_locator_for_field( - "Proof Parameters", completion_information["completion proof"] + self.proof_parameters_string, completion_information["completion proof"] ) def fill_out_failure_information(self, failure_information: dict) -> None: From 9e2efc1e2765fc6b82e2e538bca6124820f28b74 Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Mon, 22 Dec 2025 14:42:26 +0000 Subject: [PATCH 7/9] Migrating scenario 13 of surveillance regression tests --- pages/datasets/investigation_dataset_page.py | 3 +- pages/datasets/subject_datasets_page.py | 19 +- .../diagnostic_test_outcome_page.py | 1 + .../test_surveillance_scenario_13.py | 714 ++++++++++++++++++ 4 files changed, 734 insertions(+), 3 deletions(-) create mode 100644 tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_13.py diff --git a/pages/datasets/investigation_dataset_page.py b/pages/datasets/investigation_dataset_page.py index 82078482..c8dcc994 100644 --- a/pages/datasets/investigation_dataset_page.py +++ b/pages/datasets/investigation_dataset_page.py @@ -491,7 +491,8 @@ def click_edit_dataset_button(self) -> None: This method is designed to click on the edit dataset button. It clicks on the edit dataset button. """ - self.click(self.edit_dataset_button) + if self.edit_dataset_button.is_visible(): + self.click(self.edit_dataset_button) def assert_polyp_algorithm_size( self, polyp_number: int, expected_value: Optional[str] diff --git a/pages/datasets/subject_datasets_page.py b/pages/datasets/subject_datasets_page.py index 5b146fa9..8fe58c5d 100644 --- a/pages/datasets/subject_datasets_page.py +++ b/pages/datasets/subject_datasets_page.py @@ -22,11 +22,16 @@ def __init__(self, page: Page): .get_by_role("link") ) self.add_link = self.page.get_by_role("link", name="Add") + self.view_link = self.page.get_by_role("link", name="View") def click_add_link(self) -> None: """Clicks on the first 'Add' link on the Subject Datasets Page.""" self.click(self.add_link.first) + def click_view_link(self) -> None: + """Clicks on the first 'View' link on the Subject Datasets Page.""" + self.click(self.view_link.first) + def click_colonoscopy_show_datasets(self) -> None: """ Clicks on the 'Show Dataset(s)' button for the Colonoscopy Assessment row on the Subject Datasets Page. @@ -64,9 +69,19 @@ def click_show_datasets_button(self, header: Locator) -> None: show_link = container.locator("a:has-text('Show Dataset')") show_link.wait_for(state="visible", timeout=10000) self.click(show_link) - # If plural, also click Add + # If plural, also click Add or View depending on visibility if dataset_count_text and "Datasets" in dataset_count_text: - self.click_add_link() + try: + self.add_link.first.wait_for(state="visible", timeout=2000) + self.click_add_link() + except: + try: + self.view_link.first.wait_for(state="visible", timeout=2000) + self.click_view_link() + except Exception: + raise Exception( + "Neither 'Add' nor 'View' link was found after clicking 'Show Datasets'." + ) def check_investigation_dataset_complete(self) -> None: """ diff --git a/pages/screening_subject_search/diagnostic_test_outcome_page.py b/pages/screening_subject_search/diagnostic_test_outcome_page.py index 90ab9715..c09baea8 100644 --- a/pages/screening_subject_search/diagnostic_test_outcome_page.py +++ b/pages/screening_subject_search/diagnostic_test_outcome_page.py @@ -154,6 +154,7 @@ class OutcomeOfDiagnosticTest(StrEnum): REFER_SURVEILLANCE = "20365" INVESTIGATION_COMPLETE = "20360" REFER_ANOTHER_DIAGNOSTIC_TEST = "20364" + REFER_MDT = "20367" class ReasonForSymptomaticReferral(StrEnum): diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_13.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_13.py new file mode 100644 index 00000000..7867649f --- /dev/null +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_13.py @@ -0,0 +1,714 @@ +import logging +from datetime import datetime +import pytest +from playwright.sync_api import Page +from pages.base_page import BasePage +from pages.datasets.colonoscopy_dataset_page import ( + ColonoscopyDatasetsPage, + FitForColonoscopySspOptions, +) +from pages.datasets.investigation_dataset_page import ( + AdenomaSubTypeOptions, + BowelPreparationQualityOptions, + ComfortOptions, + CompletionProofOptions, + DrugTypeOptions, + EndoscopyLocationOptions, + FailureReasonsOptions, + InsufflationOptions, + InvestigationDatasetsPage, + LateOutcomeOptions, + OutcomeAtTimeOfProcedureOptions, + PolypAccessOptions, + PolypClassificationOptions, + PolypDysplasiaOptions, + PolypExcisionCompleteOptions, + PolypInterventionDeviceOptions, + PolypInterventionExcisionTechniqueOptions, + PolypInterventionModalityOptions, + PolypInterventionRetrievedOptions, + PolypTypeOptions, + YesNoOptions, + YesNoUncertainOptions, +) +from pages.datasets.subject_datasets_page import SubjectDatasetsPage +from pages.logout.log_out_page import LogoutPage +from pages.organisations.organisations_page import OrganisationSwitchPage +from pages.screening_practitioner_appointments.appointment_detail_page import ( + AppointmentDetailPage, +) +from pages.screening_subject_search.advance_surveillance_episode_page import ( + AdvanceSurveillanceEpisodePage, +) +from pages.screening_subject_search.attend_diagnostic_test_page import ( + AttendDiagnosticTestPage, +) +from pages.screening_subject_search.contact_with_patient_page import ( + ContactWithPatientPage, +) +from pages.screening_subject_search.diagnostic_test_outcome_page import ( + DiagnosticTestOutcomePage, + OutcomeOfDiagnosticTest, +) +from pages.screening_subject_search.episode_events_and_notes_page import ( + EpisodeEventsAndNotesPage, +) +from pages.screening_subject_search.handover_into_symptomatic_care_page import ( + HandoverIntoSymptomaticCarePage, +) +from pages.screening_subject_search.reopen_surveillance_episode_page import ( + ReopenSurveillanceEpisodePage, +) +from pages.screening_subject_search.subject_screening_summary_page import ( + SubjectScreeningSummaryPage, +) +from utils import screening_subject_page_searcher +from utils.appointments import book_post_investigation_appointment +from utils.batch_processing import batch_processing +from utils.calendar_picker import CalendarPicker +from utils.generate_health_check_forms_util import GenerateHealthCheckFormsUtil +from utils.investigation_dataset import InvestigationDatasetCompletion +from utils.sspi_change_steps import SSPIChangeSteps +from utils.subject_assertion import subject_assertion +from utils.subject_demographics import SubjectDemographicUtil +from utils.user_tools import UserTools + + +@pytest.mark.vpn_required +@pytest.mark.regression +@pytest.mark.surveillance_regression_tests +def test_scenario_13(page: Page, general_properties: dict) -> None: + """ + Scenario: 13: Cancer from diagnostic tests + + X501-A99-A59-A259-A360-A410-A415-A416-A316-A345-A346-A63-C203 [SSCL18c] A416-A316-A345-A346-A63-X399-C203 [SSCL25a] + + This scenario takes an in-age Surveillance episode through to closure on Cancer result from diagnostic tests, returning the subject to FOBT screening. The diagnostic test outcome is only entered after the post-investigation appointment has been attended (and cannot be entered until the investigation dataset has been completed). The episode is then reopened and the subjectโ€™s date of birth changed in order to test closure on the same result for an over-age subject. This reopen is not available to an SSP, after closure on Cancer result, but is available to a Screening Centre Manager. + + Because we cannot know if we will be inviting a subject who has had previous FOBT episodes, or only a bowel scope episode, it is impossible to check if they will be set to Call or Recall; we can only check that they are not longer in Surveillance status. + + Scenario summary: + + > Run surveillance invitations for 1 subject > X500 (3.1) + > SSPI update changes subject to in-age at recall + > Process X500 letter batch > X505 (3.1) + > Complete the colonoscopy assessment dataset - fit for colonoscopy + > Record patient contact โ€“ contacted, suitable for colonoscopy > A99 (3.1) + > Invite for diagnostic test > A59 (2.1) + > Attend diagnostic test > A259 (2.1) + > Complete investigation dataset โ€“ Cancer (2.1) + > Post-investigation appointment required > A360 (2.1) + > Book post-investigation appointment > A410 (2.4) + > Process A410 letter batch > A415 (2.4) + > Attend post-investigation appointment > A416 (2.4) + > Enter diagnostic test outcome โ€“ refer MDT > A316 (2.4) > A345 (2.6) + > Handover into symptomatic care > A346 (2.7) + > Process A346 letter batch > A63 (2.7) > C203 (3.6) + > Check recall [SSCL18c] + > Reopen to confirm diagnostic test result and outcome > A416 (2.4) + > Manually change subject to over age + > Enter diagnostic test outcome โ€“ refer MDT > A316 (2.4) > A345 (2.6) + > Handover into symptomatic care > A346 (2.7) + > Process A346 letter batch > A63 (2.7) > X399 (3.5) > C203 (3.6) + > Check recall [SSCL25a] + """ + # Given I log in to BCSS "England" as user role "Specialist Screening Practitioner" + user_role = UserTools.user_login( + page, "Specialist Screening Practitioner at BCS009 & BCS001", True + ) + + OrganisationSwitchPage(page).select_organisation_by_id("BCS001") + OrganisationSwitchPage(page).click_continue() + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") + + # When I run surveillance invitations for 1 subject + org_id = general_properties["eng_screening_centre_id"] + nhs_no = GenerateHealthCheckFormsUtil(page).invite_surveillance_subjects_early( + org_id + ) + logging.info(f"[SUBJECT RETRIEVAL] Subject's NHS Number: {nhs_no}") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode status": "Open", + "latest episode type": "Surveillance", + "latest event status": "X500 Selected For Surveillance", + "responsible screening centre code": "User's screening centre", + "subject has unprocessed SSPI updates": "No", + "subject has user DOB updates": "No", + }, + user_role, + ) + + # And I receive an SSPI update to change their date of birth to "72" years old + SSPIChangeSteps().sspi_update_to_change_dob_received(nhs_no, 72) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"subject age": "72"}) + + # And there is a "X500" letter batch for my subject with the exact title "Surveillance Selection" + # When I process the open "X500" letter batch for my subject + batch_processing( + page, + "X500", + "Surveillance Selection", + ) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"latest event status": "X505 HealthCheck Form Printed"}) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Colonoscopy Assessment Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_colonoscopy_show_datasets() + + # And I update the Colonoscopy Assessment Dataset with the following values: + ColonoscopyDatasetsPage(page).select_fit_for_colonoscopy_option( + FitForColonoscopySspOptions.YES + ) + ColonoscopyDatasetsPage(page).click_dataset_complete_radio_button_yes() + + # And I save the Colonoscopy Assessment Dataset + ColonoscopyDatasetsPage(page).save_dataset() + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Record Contact with Patient" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_record_contact_with_patient_button() + + # And I record contact with the subject with outcome "Suitable for Endoscopic Test" + ContactWithPatientPage(page).record_contact("Suitable for Endoscopic Test") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A99 Suitable for Endoscopic Test", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the advance episode options + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select Diagnostic Test Type "Colonoscopy" + AdvanceSurveillanceEpisodePage(page).select_test_type_dropdown_option("Colonoscopy") + + # And I enter a Diagnostic Test First Offered Appointment Date of "today" + AdvanceSurveillanceEpisodePage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + + # And I advance the subject's episode for "Invite for Diagnostic Test >>" + AdvanceSurveillanceEpisodePage(page).click_invite_for_diagnostic_test_button() + + page.wait_for_timeout(500) # Timeout to allow subject to update on the DB + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A59 Invited for Diagnostic Test", + }, + ) + + # When I select the advance episode option for "Attend Diagnostic Test" + AdvanceSurveillanceEpisodePage(page).click_attend_diagnostic_test_button() + + # And I attend the subject's diagnostic test today + AttendDiagnosticTestPage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + AttendDiagnosticTestPage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A259 Attended Diagnostic Test"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Investigation Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # And I apply the "CancerDetected2" Investigation Dataset Scenario + # When I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "10", + "drug_type1": DrugTypeOptions.BISACODYL, + "drug_dose2": "20", + "drug_type2": DrugTypeOptions.CITRAFLEET, + } + ) + + # And I set the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": 1, + "aspirant endoscopist": 1, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "therapeutic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.ANASTOMOSIS, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.YES, + "start of intubation time": "09:00", + "start of extubation time": "09:15", + "end time of procedure": "09:30", + "scope id": "A1", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) + + # And I set the following completion proof values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_completion_information( + {"completion proof": CompletionProofOptions.VIDEO_ANASTOMOSIS} + ) + + # And I set the following failure reasons within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.NO_FAILURE_REASONS} + ) + + # And I add new polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_information( + { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.IIA, + "estimate of whole polyp size": "10", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + 1, + ) + + # And I add intervention 1 for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_intervention( + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": PolypInterventionRetrievedOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + }, + 1, + ) + + # And I update histology details for polyp 1 with the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_polyp_x_histology( + { + "date of receipt": datetime.today(), + "date of reporting": datetime.today(), + "pathology provider": -1, + "pathologist": -1, + "polyp type": PolypTypeOptions.ADENOMA, + "adenoma sub type": AdenomaSubTypeOptions.NOT_REPORTED, + "polyp excision complete": PolypExcisionCompleteOptions.R0, + "polyp size": "5", + "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, + "polyp carcinoma": YesNoUncertainOptions.YES, + }, + 1, + ) + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"latest episode accumulated result": "Null"}) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I advance the subject's episode for "Post-investigation Appointment Required" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_post_investigation_appointment_required_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, {"latest event status": "A360 Post-investigation Appointment Required"} + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I choose to book a practitioner clinic for my subject + SubjectScreeningSummaryPage(page).click_book_practitioner_clinic_button() + + # And I set the practitioner appointment date to "today" + # And I book the earliest available post investigation appointment on this date + book_post_investigation_appointment(page, "The Royal Hospital (Wolverhampton)") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A410 Post-investigation Appointment Made", + }, + ) + + # And there is a "A410" letter batch for my subject with the exact title "Post-Investigation Appointment Invitation Letter" + # When I process the open "A410" letter batch for my subject + batch_processing( + page, + "A410", + "Post-Investigation Appointment Invitation Letter", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the event history for the subject's latest episode + SubjectScreeningSummaryPage(page).expand_episodes_list() + SubjectScreeningSummaryPage(page).click_first_surveillance_episode_link() + + # And I view the latest practitioner appointment in the subject's episode + EpisodeEventsAndNotesPage(page).click_most_recent_view_appointment_link() + + # And I attend the subject's practitioner appointment "today" + AppointmentDetailPage(page).mark_appointment_as_attended(datetime.today()) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A416 Post-investigation Appointment Attended"}, + ) + + # Then I get a confirmation prompt that "contains" "It is not possible to progress this episode until the dataset has been marked as complete and a diagnostic test result written to the episode history." + AdvanceSurveillanceEpisodePage(page).assert_dialog_text( + "It is not possible to progress this episode until the dataset has been marked as complete and a diagnostic test result written to the episode history.", + True, + ) + + # When I select the advance episode option for "Enter Diagnostic Test Outcome" + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_enter_diagnostic_test_outcome_button() + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Investigation Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + InvestigationDatasetsPage(page).click_edit_dataset_button() + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "Cancer Detected" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog( + "Cancer Detected" + ) + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"latest episode accumulated result": "Cancer Detected"}) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Enter Diagnostic Test Outcome" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_enter_diagnostic_test_outcome_button() + + # And I select Outcome of Diagnostic Test "Refer MDT" + DiagnosticTestOutcomePage(page).select_test_outcome_option( + OutcomeOfDiagnosticTest.REFER_MDT + ) + + # And I save the Diagnostic Test Outcome + DiagnosticTestOutcomePage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode includes event status": "A316 Post-investigation Appointment Attended", + "latest event status": "A345 Cancer Result, Refer MDT", + }, + ) + + # When I view the advance episode options + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select the advance episode option for "Handover into Symptomatic Care" + AdvanceSurveillanceEpisodePage(page).click_handover_into_symptomatic_care_button() + + # And I fill in Handover into Symptomatic Care with Cancer details + HandoverIntoSymptomaticCarePage(page).fill_with_cancer_details() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, {"latest event status": "A346 Handover into Symptomatic Care"} + ) + + # And there is a "A346" letter batch for my subject with the exact title "Handover into Symptomatic Care (Cancer Diagnosis)" + # When I process the open "A346" letter batch for my subject + batch_processing( + page, + "A346", + "Handover into Symptomatic Care (Cancer Diagnosis)", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Latest not-void test in latest episode", + "calculated fobt due date": "2 years from episode end", + "calculated lynch due date": "Null", + "calculated surveillance due date": "Null", + "ceased confirmation date": "Null", + "ceased confirmation details": "Null", + "ceased confirmation user id": "Null", + "clinical reason for cease": "Null", + "diagnostic test has outcome": "Yes", + "latest episode accumulated result": "Cancer Detected", + "latest episode recall calculation method": "Episode end date", + "latest episode recall episode type": "FOBT Screening", + "latest episode recall surveillance type": "Null", + "latest episode status": "Closed", + "latest episode status reason": "Episode Complete", + "latest event status": "A63 Cancer", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Calculated FOBT Due Date", + "screening due date date of change": "Today", + "screening due date reason": "Result referred for cancer treatment", + "screening status": "NOT: Surveillance", + "screening status date of change": "Today", + "screening status reason": "Result referred for cancer treatment", + "surveillance due date": "Null", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Referred for Cancer treatment", + "symptomatic procedure date": "Null", + "symptomatic procedure result": "Null", + "screening referral type": "Null", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # Then I "cannot" reopen the subject's episode + SubjectScreeningSummaryPage(page).assert_reopen_episode_button_not_visible() + + # When I switch users to BCSS "England" as user role "Screening Centre Manager" + LogoutPage(page).log_out(close_page=False) + BasePage(page).go_to_log_in_page() + user_role = UserTools.user_login(page, "Screening Centre Manager at BCS001", True) + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I reopen the subject's episode for "Reopen to Confirm Diagnostic Test Result and Outcome" + SubjectScreeningSummaryPage(page).click_reopen_surveillance_episode_button() + ReopenSurveillanceEpisodePage( + page + ).click_reopen_to_confirm_diagnostic_test_result_and_outcome_button() + + # And I pause for "2" seconds to let the process complete + page.wait_for_timeout(2000) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Latest not-void test in latest episode", + "calculated fobt due date": "Null", + "calculated lynch due date": "Null", + "calculated surveillance due date": "As at episode start", + "ceased confirmation date": "Null", + "ceased confirmation details": "Null", + "ceased confirmation user id": "Null", + "clinical reason for cease": "Null", + "diagnostic test has outcome": "No", + "latest episode accumulated result": "Cancer Detected", + "latest episode includes event code": "E67 Reopen to Confirm Diagnostic Test Result and Outcome", + "latest episode recall calculation method": "Null", + "latest episode recall episode type": "Null", + "latest episode recall surveillance type": "Null", + "latest episode status": "Open", + "latest episode status reason": "Null", + "latest event status": "A416 Post-investigation Appointment Attended", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Null", + "screening due date date of change": "Today", + "screening due date reason": "Reopened episode", + "screening status": "Surveillance", + "screening status date of change": "Today", + "screening status reason": "Reopened episode", + "surveillance due date": "Calculated Surveillance due date", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Reopened episode", + "symptomatic procedure date": "Null", + "symptomatic procedure result": "Null", + "screening referral type": "Null", + }, + ) + + # When I view the subject + # And I update the subject's date of birth to make them 85 years old + # And I update the subject's postcode to "AA1 2BB" + # And I save my changes to the subject's demographics + SubjectDemographicUtil(page).updated_subject_demographics( + nhs_no, + 85, + "AA1 2BB", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "subject age": "85", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Enter Diagnostic Test Outcome" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_enter_diagnostic_test_outcome_button() + + # And I select Outcome of Diagnostic Test "Refer MDT" + DiagnosticTestOutcomePage(page).select_test_outcome_option( + OutcomeOfDiagnosticTest.REFER_MDT + ) + + # And I save the Diagnostic Test Outcome + DiagnosticTestOutcomePage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode includes event status": "A316 Post-investigation Appointment Attended", + "latest event status": "A345 Cancer Result, Refer MDT", + }, + ) + + # When I view the advance episode options + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select the advance episode option for "Handover into Symptomatic Care" + AdvanceSurveillanceEpisodePage(page).click_handover_into_symptomatic_care_button() + + # And I fill in Handover into Symptomatic Care with Cancer details + HandoverIntoSymptomaticCarePage(page).fill_with_cancer_details() + + # And my subject has been updated as follows: + subject_assertion( + nhs_no, {"latest event status": "A346 Handover into Symptomatic Care"} + ) + + # And there is a "A346" letter batch for my subject with the exact title "Handover into Symptomatic Care (Cancer Diagnosis)" + # When I process the open "A346" letter batch for my subject + batch_processing( + page, + "A346", + "Handover into Symptomatic Care (Cancer Diagnosis)", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Latest not-void test in latest episode", + "calculated fobt due date": "2 years from episode end", + "calculated lynch due date": "Null", + "calculated surveillance due date": "Null", + "ceased confirmation date": "Today", + "ceased confirmation details": "Handover notes for Cancer scenario", + "ceased confirmation user id": "User's ID", + "clinical reason for cease": "Null", + "diagnostic test has outcome": "Yes", + "latest episode accumulated result": "Cancer Detected", + "latest episode includes event status": "A63 Cancer", + "latest episode recall calculation method": "Episode end date", + "latest episode recall episode type": "FOBT Screening", + "latest episode recall surveillance type": "Null", + "latest episode status": "Closed", + "latest episode status reason": "Discharge from Surveillance - Age", + "latest event status": "X399 Discharged from Surveillance - National Guidelines Cease Screening", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Null", + "screening due date date of change": "Unchanged", + "screening due date reason": "Unchanged", + "screening status": "Ceased", + "screening status date of change": "Today", + "screening status reason": "Outside screening population", + "surveillance due date": "Null", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Discharge from Surveillance - Age", + "symptomatic procedure date": "Null", + "symptomatic procedure result": "Null", + "screening referral type": "Null", + }, + user_role, + ) + + LogoutPage(page).log_out() From fe4a86eabe69b5f408a810ddb5524568cb9a2bfe Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Mon, 22 Dec 2025 14:48:51 +0000 Subject: [PATCH 8/9] Addressing SonarQube issues --- pages/datasets/subject_datasets_page.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/datasets/subject_datasets_page.py b/pages/datasets/subject_datasets_page.py index 8fe58c5d..769de079 100644 --- a/pages/datasets/subject_datasets_page.py +++ b/pages/datasets/subject_datasets_page.py @@ -1,4 +1,4 @@ -from playwright.sync_api import Page, expect, Locator +from playwright.sync_api import Page, expect, Locator, TimeoutError from pages.base_page import BasePage @@ -74,12 +74,12 @@ def click_show_datasets_button(self, header: Locator) -> None: try: self.add_link.first.wait_for(state="visible", timeout=2000) self.click_add_link() - except: + except TimeoutError: try: self.view_link.first.wait_for(state="visible", timeout=2000) self.click_view_link() except Exception: - raise Exception( + raise TimeoutError( "Neither 'Add' nor 'View' link was found after clicking 'Show Datasets'." ) From 0dccfdfce11a85a8cceb83f4eae34ca59755725b Mon Sep 17 00:00:00 2001 From: Adriano Aru Date: Tue, 23 Dec 2025 10:21:51 +0000 Subject: [PATCH 9/9] Completing scenario 14 --- .../contact_with_patient_page.py | 15 + .../diagnostic_test_outcome_page.py | 24 +- .../subject_screening_summary_page.py | 7 + ...uncease_and_initiate_optin_episode_page.py | 39 + .../test_surveillance_scenario_14.py | 855 ++++++++++++++++++ 5 files changed, 938 insertions(+), 2 deletions(-) create mode 100644 pages/screening_subject_search/uncease_and_initiate_optin_episode_page.py create mode 100644 tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_14.py diff --git a/pages/screening_subject_search/contact_with_patient_page.py b/pages/screening_subject_search/contact_with_patient_page.py index 00f5954c..8e5eb6ff 100644 --- a/pages/screening_subject_search/contact_with_patient_page.py +++ b/pages/screening_subject_search/contact_with_patient_page.py @@ -186,3 +186,18 @@ def verify_outcome_select_options(self, options: list) -> None: f"Missing expected dropdown values in the outcome options: {missing}." f"Actual options: {actual_options}" ) + + def patient_outcome_dropdown_contains_options(self, options: List[str]) -> None: + """ + Asserts that all provided options are present in the Patient Outcome dropdown. + + Args: + options (List[str]): List of option strings to check. + """ + dropdown_options = [ + opt.inner_text() for opt in self.outcome_dropdown.locator("option").all() + ] + for item in options: + assert ( + item in dropdown_options + ), f"Dropdown is missing expected option: '{item}'" diff --git a/pages/screening_subject_search/diagnostic_test_outcome_page.py b/pages/screening_subject_search/diagnostic_test_outcome_page.py index c09baea8..846ec583 100644 --- a/pages/screening_subject_search/diagnostic_test_outcome_page.py +++ b/pages/screening_subject_search/diagnostic_test_outcome_page.py @@ -38,7 +38,7 @@ def __init__(self, page: Page): self.test_outcome_dropdown = self.page.get_by_label( "Outcome of Diagnostic Test" ) - self.reason_for_sympptomatic_referral_dropdown = self.page.get_by_label( + self.reason_for_symptomatic_referral_dropdown = self.page.get_by_label( "Reason for Symptomatic Referral" ) self.save_button = self.page.get_by_role("button", name="Save") @@ -102,6 +102,26 @@ def reason_for_onward_referral_dropdown_contains_options( item in dropdown_options ), f"Dropdown is missing expected option: '{item}'" + def reason_for_symptomatic_referral_dropdown_contains_options( + self, options: List[str] + ) -> None: + """ + Asserts that all provided options are present in the Reason for Symptomatic Referral dropdown. + + Args: + options (List[str]): List of option strings to check. + """ + dropdown_options = [ + opt.inner_text() + for opt in self.reason_for_symptomatic_referral_dropdown.locator( + "option" + ).all() + ] + for item in options: + assert ( + item in dropdown_options + ), f"Dropdown is missing expected option: '{item}'" + def verify_reason_for_symptomatic_referral(self, symptomatic_reason: str) -> None: """ Verify reason for symptomatic referral is visible. @@ -119,7 +139,7 @@ def select_reason_for_symptomatic_referral_option(self, option: str) -> None: Args: option (str): option (str): The option to select from the Reason For Symptomatic Referral options. """ - self.reason_for_sympptomatic_referral_dropdown.select_option(option) + self.reason_for_symptomatic_referral_dropdown.select_option(option) def click_save_button(self) -> None: """Click the 'Save' button.""" diff --git a/pages/screening_subject_search/subject_screening_summary_page.py b/pages/screening_subject_search/subject_screening_summary_page.py index 2142184e..07095386 100644 --- a/pages/screening_subject_search/subject_screening_summary_page.py +++ b/pages/screening_subject_search/subject_screening_summary_page.py @@ -87,6 +87,9 @@ def __init__(self, page: Page): self.postpone_surveillance_episode_button = self.page.get_by_role( "button", name="Postpone Surveillance Episode" ) + self.uncease_subject_button = self.page.get_by_role( + "button", name="Uncease Subject" + ) # List of Subject Episodes - page filters self.view_events_link = self.page.get_by_role("link", name="events") @@ -510,6 +513,10 @@ def can_postpone_surveillance_episode(self, able_to_click: bool = True) -> None: else: expect(self.postpone_surveillance_episode_button).not_to_be_visible() + def click_uncease_subject_button(self) -> None: + """Click the 'Uncease Subject' button.""" + self.click(self.uncease_subject_button) + class ChangeScreeningStatusOptions(StrEnum): """Enum for Change Screening Status options.""" diff --git a/pages/screening_subject_search/uncease_and_initiate_optin_episode_page.py b/pages/screening_subject_search/uncease_and_initiate_optin_episode_page.py new file mode 100644 index 00000000..a37de5a2 --- /dev/null +++ b/pages/screening_subject_search/uncease_and_initiate_optin_episode_page.py @@ -0,0 +1,39 @@ +from playwright.sync_api import Page +from pages.base_page import BasePage + + +class UnceaseAndInitiateOptinEpisodePage(BasePage): + """Uncease and Initiate Opt-in Episode Page locators, and methods for interacting with the page.""" + + def __init__(self, page: Page): + super().__init__(page) + self.page = page + self.notes_field = self.page.locator("#UI_NOTES_TEXT") + self.send_a_kit_button = self.page.get_by_role("button", name="Send a kit") + + def enter_notes(self, notes: str) -> None: + """ + Enter notes into the 'Notes' field. + Args: + notes (str): The notes to enter into the field. + """ + self.notes_field.fill(notes) + + def click_send_a_kit_button(self) -> None: + """ + Clicks the 'Send a kit' button. + """ + self.safe_accept_dialog(self.send_a_kit_button) + + def manually_uncease_the_subject(self, action: str) -> None: + """ + Uncease the subject and take the specified action. + Args: + action (str): The action to take after unceasing the subject. + """ + self.enter_notes( + f"Auto test scenario: manual unceasing test for age extension to {action}" + ) + match action: + case "send a new kit": + self.click_send_a_kit_button() diff --git a/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_14.py b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_14.py new file mode 100644 index 00000000..405c2828 --- /dev/null +++ b/tests/regression/regression_tests/surveillance_regression_tests/test_surveillance_scenario_14.py @@ -0,0 +1,855 @@ +import logging +from datetime import datetime, timedelta +import pytest +from classes.user.user import User +from classes.repositories.episode_repository import EpisodeRepository +from classes.repositories.person_repository import PersonRepository +from playwright.sync_api import Page, expect +from pages.base_page import BasePage +from pages.datasets.colonoscopy_dataset_page import ( + ColonoscopyDatasetsPage, + FitForColonoscopySspOptions, +) +from pages.datasets.investigation_dataset_page import ( + BowelPreparationQualityOptions, + ComfortOptions, + DrugTypeOptions, + EndoscopyLocationOptions, + FailureReasonsOptions, + InsufflationOptions, + InvestigationDatasetsPage, + LateOutcomeOptions, + OutcomeAtTimeOfProcedureOptions, + YesNoOptions, +) +from pages.datasets.subject_datasets_page import SubjectDatasetsPage +from pages.logout.log_out_page import LogoutPage +from pages.organisations.organisations_page import OrganisationSwitchPage +from pages.screening_practitioner_appointments.appointment_detail_page import ( + AppointmentDetailPage, +) +from pages.screening_subject_search.advance_surveillance_episode_page import ( + AdvanceSurveillanceEpisodePage, +) +from pages.screening_subject_search.attend_diagnostic_test_page import ( + AttendDiagnosticTestPage, +) +from pages.screening_subject_search.contact_with_patient_page import ( + ContactWithPatientPage, +) +from pages.screening_subject_search.diagnostic_test_outcome_page import ( + DiagnosticTestOutcomePage, + OutcomeOfDiagnosticTest, + ReasonForOnwardReferral, +) +from pages.screening_subject_search.episode_events_and_notes_page import ( + EpisodeEventsAndNotesPage, +) +from pages.screening_subject_search.lnpcp_result_from_symptomatic_procedure_page import ( + LnpcpResultFromSymptomaticProcedure, +) +from pages.screening_subject_search.record_request_to_cease_page import ( + RecordRequestToCeasePage, +) +from pages.screening_subject_search.reopen_surveillance_episode_page import ( + ReopenSurveillanceEpisodePage, +) +from pages.screening_subject_search.return_from_symptomatic_referral_page import ( + ReturnFromSymptomaticReferralPage, +) +from pages.screening_subject_search.subject_screening_summary_page import ( + SubjectScreeningSummaryPage, +) +from pages.screening_subject_search.uncease_and_initiate_optin_episode_page import ( + UnceaseAndInitiateOptinEpisodePage, +) +from utils import screening_subject_page_searcher +from utils.appointments import book_post_investigation_appointment +from utils.batch_processing import batch_processing +from utils.calendar_picker import CalendarPicker +from utils.generate_health_check_forms_util import GenerateHealthCheckFormsUtil +from utils.investigation_dataset import InvestigationDatasetCompletion +from utils.oracle.oracle import OracleDB +from utils.sspi_change_steps import SSPIChangeSteps +from utils.subject_assertion import subject_assertion +from utils.user_tools import UserTools + + +@pytest.mark.vpn_required +@pytest.mark.regression +@pytest.mark.surveillance_regression_tests +def test_scenario_14(page: Page, general_properties: dict) -> None: + """ + Scenario: 14: LNPCP result from symptomatic procedure, refer another diagnostic test + + X500-X505-A99-A59-A259-A315-A361-A323-A317-A353-A372-A373-A374-A157-C203 [SSCL52b] [SSUN9.7] A372-A373-A389-A360-A410-A415-A416-A316-A319-A395 + + This scenario tests a subject being referred for symptomatic procedure following a "No result" diagnostic test. The symptomatic result is LNPCP, keeping the in-age subject in Surveillance. After the episode has closed, manually ceasing then unceasing the subject returns the subject to FOBT screening, as the user must use the Opt-in to Send a Kit option to uncease them: because their calculated FOBT due date is now in the past, they are given an immediate FOBT screening due date. Note also than when manually ceasing a subject their FOBT due date reason is set to "Ceased" even though it is not changing, and when manually unceasing a subject, they come back into the FOBT pathway with status Opt-in - which seems a little odd, but still! + + BCSS-17906 NOTE: The pathway for referring for another diagnostic test following symptomatic procedure is currently incomplete, so stopping at A360 + + Scenario summary: + + > Run surveillance invitations for 1 subject > X500 (3.1) + > SSPI update changes subject to in-age at recall + > Process X500 letter batch > X505 (3.1) + > Complete the colonoscopy assessment dataset - fit for colonoscopy + > Record patient contact โ€“ contacted, suitable for colonoscopy > A99 (3.1) + > Invite for diagnostic test > A59 (2.1) + > Attend diagnostic test > A259 (2.1) + > Complete investigation dataset โ€“ No result (2.1) + > Enter diagnostic test outcome โ€“ refer symptomatic > A315 (2.1) + > Post-investigation appointment not required > A361 (2.1) + > Record patient contact โ€“ post-investigation appointment not required > A323 (2.1) > A317 (2.5) + > MDT not required > A353 (2.6) + > Process A353 letter batch > A372 (2.6) + > Record symptomatic result โ€“ LNPCP > A373 (2.7) + > Refer Surveillance > A374 (2.7) + > Process A374 letter batch > A157 (2.7) > C203 (3.6) + > Check recall [SSCL52b] + > Manually cease subject + > Manually uncease subject (Opt-in to Send a Kit) [SSUN9.7] + > Reopen to Re-record Outcome from Symptomatic Referral > A372 (2.7) + > Record symptomatic result - non-neoplastic > A373 (2.7) + > Refer another diagnostic test > A389 (2.7) + > Post-investigation appointment required > A360 (2.1) + > Book post-investigation appointment > A410 (2.4) + > Process A410 letter batch > A415 (2.4) + > Attend post-investigation appointment > A416 > A316 > A319 (2.4) + > Process A319 letter batch > A395 (2.4) + """ + # Given I log in to BCSS "England" as user role "Specialist Screening Practitioner" + user_role = UserTools.user_login( + page, "Specialist Screening Practitioner at BCS009 & BCS001", True + ) + + OrganisationSwitchPage(page).select_organisation_by_id("BCS001") + OrganisationSwitchPage(page).click_continue() + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") + + # When I run surveillance invitations for 1 subject + org_id = general_properties["eng_screening_centre_id"] + nhs_no = GenerateHealthCheckFormsUtil(page).invite_surveillance_subjects_early( + org_id + ) + logging.info(f"[SUBJECT RETRIEVAL] Subject's NHS Number: {nhs_no}") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode status": "Open", + "latest episode type": "Surveillance", + "latest event status": "X500 Selected For Surveillance", + "responsible screening centre code": "User's screening centre", + "subject has unprocessed SSPI updates": "No", + "subject has user DOB updates": "No", + }, + user_role, + ) + + # And I receive an SSPI update to change their date of birth to "72" years old + SSPIChangeSteps().sspi_update_to_change_dob_received(nhs_no, 72) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"subject age": "72"}) + + # And there is a "X500" letter batch for my subject with the exact title "Surveillance Selection" + # When I process the open "X500" letter batch for my subject + batch_processing( + page, + "X500", + "Surveillance Selection", + ) + + # Then my subject has been updated as follows: + subject_assertion(nhs_no, {"latest event status": "X505 HealthCheck Form Printed"}) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Colonoscopy Assessment Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_colonoscopy_show_datasets() + + # And I update the Colonoscopy Assessment Dataset with the following values: + ColonoscopyDatasetsPage(page).select_fit_for_colonoscopy_option( + FitForColonoscopySspOptions.YES + ) + ColonoscopyDatasetsPage(page).click_dataset_complete_radio_button_yes() + + # And I save the Colonoscopy Assessment Dataset + ColonoscopyDatasetsPage(page).save_dataset() + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Record Contact with Patient" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_record_contact_with_patient_button() + + # And I record contact with the subject with outcome "Suitable for Endoscopic Test" + ContactWithPatientPage(page).record_contact("Suitable for Endoscopic Test") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A99 Suitable for Endoscopic Test", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the advance episode options + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select Diagnostic Test Type "Colonoscopy" + AdvanceSurveillanceEpisodePage(page).select_test_type_dropdown_option("Colonoscopy") + + # And I enter a Diagnostic Test First Offered Appointment Date of "today" + AdvanceSurveillanceEpisodePage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + + # And I advance the subject's episode for "Invite for Diagnostic Test >>" + AdvanceSurveillanceEpisodePage(page).click_invite_for_diagnostic_test_button() + + page.wait_for_timeout(500) # Timeout to allow subject to update on the DB + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A59 Invited for Diagnostic Test", + }, + ) + + # When I select the advance episode option for "Attend Diagnostic Test" + AdvanceSurveillanceEpisodePage(page).click_attend_diagnostic_test_button() + + # And I attend the subject's diagnostic test today + AttendDiagnosticTestPage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + AttendDiagnosticTestPage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A259 Attended Diagnostic Test"}, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I edit the Investigation Dataset for this subject + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + # Confirm on the investigation Datasets Page + InvestigationDatasetsPage(page).bowel_cancer_screening_page_title_contains_text( + "Investigation Datasets" + ) + + # And I open all minimized sections on the dataset + InvestigationDatasetsPage(page).open_all_minimized_sections() + + # When I add the following bowel preparation drugs and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_drug_information( + { + "drug_dose1": "3", + "drug_type1": DrugTypeOptions.MANNITOL, + } + ) + + # And there is a clinician who meets the following criteria: + user = User.from_user_role_type(user_role) + criteria = { + "Person has current role": "Accredited Screening Colonoscopist", + "Person has current role in organisation": "User's SC", + "Resect & Discard accreditation status": "None", + } + query = PersonRepository().build_person_selection_query( + criteria=criteria, person=None, required_person_count=1, user=user, subject=None + ) + df = OracleDB().execute_query(query) + person_name = ( + f"{df["person_family_name"].iloc[0]} {df["person_given_name"].iloc[0]}" + ) + + # And I set the following fields and values within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_general_information( + { + "practitioner": 1, + "site": 1, + "testing clinician": person_name, + "aspirant endoscopist": None, + } + ) + + InvestigationDatasetCompletion(page).fill_endoscopy_information( + { + "endoscope inserted": "yes", + "procedure type": "diagnostic", + "bowel preparation quality": BowelPreparationQualityOptions.GOOD, + "comfort during recovery": ComfortOptions.NO_DISCOMFORT, + "comfort during examination": ComfortOptions.NO_DISCOMFORT, + "endoscopist defined extent": EndoscopyLocationOptions.DESCENDING_COLON, + "scope imager used": YesNoOptions.YES, + "retroverted view": YesNoOptions.YES, + "start of intubation time": "09:00", + "start of extubation time": "09:30", + "end time of procedure": "10:00", + "scope id": "Autotest", + "insufflation": InsufflationOptions.AIR, + "outcome at time of procedure": OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT, + "late outcome": LateOutcomeOptions.NO_COMPLICATIONS, + } + ) + + # And I set the following failure reasons within the Investigation Dataset for this subject: + InvestigationDatasetCompletion(page).fill_out_failure_information( + {"failure reasons": FailureReasonsOptions.PAIN} + ) + + # And I mark the Investigation Dataset as completed + InvestigationDatasetsPage(page).check_dataset_complete_checkbox() + + # When I press the save Investigation Dataset button + # Then the Investigation Dataset result message, which I will cancel, is "No Result" + InvestigationDatasetsPage(page).click_save_dataset_button_assert_dialog("No Result") + + # When I press the save Investigation Dataset button + InvestigationDatasetsPage(page).click_save_dataset_button() + + # And I confirm the Episode Result is "No result" + EpisodeRepository().confirm_episode_result(nhs_no, "No Result") + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Enter Diagnostic Test Outcome" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage(page).click_enter_diagnostic_test_outcome_button() + + # Then I confirm the Outcome Of Diagnostic Test dropdown has the following options: + DiagnosticTestOutcomePage(page).test_outcome_dropdown_contains_options( + [ + "Failed Test - Refer Another", + "Refer Symptomatic", + ], + ) + + # When I select Outcome of Diagnostic Test "Refer Symptomatic" + DiagnosticTestOutcomePage(page).select_test_outcome_option( + OutcomeOfDiagnosticTest.REFER_SYMPTOMATIC + ) + + # Then the text "Diagnostic Test Date resulting in a recall due date" is not visible + expect( + page.get_by_text("Diagnostic Test Date resulting in a recall due date") + ).not_to_be_visible() + + # And I confirm the Reason for Symptomatic Referral dropdown has the following options: + DiagnosticTestOutcomePage( + page + ).reason_for_symptomatic_referral_dropdown_contains_options( + [ + "Polyp Excision", + "Corrective Surgery", + "Suspected Cancer Surgery", + ], + ) + + # When I select Reason for Symptomatic Referral value "Suspected Cancer Surgery" + DiagnosticTestOutcomePage(page).select_reason_for_symptomatic_referral_option( + ReasonForOnwardReferral.SUSPECTED_CANCER_SURGERY + ) + + # And I save the Diagnostic Test Outcome + DiagnosticTestOutcomePage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A315 Diagnostic Test Outcome Entered", + }, + ) + + # When I advance the subject's episode for "Other Post-investigation Contact Required" + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_other_post_investigation_contact_required_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A361 Other Post-investigation Contact Required", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I select the advance episode option for "Record other post-investigation contact" + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_record_other_post_investigation_contact_button() + + # Then I confirm the patient outcome dropdown has the following options: + ContactWithPatientPage(page).patient_outcome_dropdown_contains_options( + [ + "Post-investigation Appointment Not Required", + "Post-investigation Appointment Required", + "No outcome", + ], + ) + + # When I record contact with the subject with outcome "Post-investigation Appointment Not Required" + ContactWithPatientPage(page).record_post_investigation_appointment_not_required() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode includes event status": "A323 Post-investigation Appointment NOT Required", + "latest event status": "A317 Post-investigation Contact Made", + }, + ) + + # When I view the advance episode options + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I advance the subject's episode for "MDT Referral Not Required" + AdvanceSurveillanceEpisodePage(page).click_mdt_referral_not_required_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A353 MDT Referral Not Required", + }, + ) + + # And there is a "A353" letter batch for my subject with the exact title "GP Letter Indicating Referral to Symptomatic" + # When I process the open "A353" letter batch for my subject + batch_processing( + page, + "A353", + "GP Letter Indicating Referral to Symptomatic", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A372 Refer Symptomatic, GP Letter Printed", + }, + ) + + # When I view the advance episode options + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select the advance episode option for "LNPCP Result from Symptomatic Procedure" + AdvanceSurveillanceEpisodePage( + page + ).click_lnpcp_result_from_symptomatic_procedure_button() + + # And I set the Date of Symptomatic Procedure to "yesterday" + LnpcpResultFromSymptomaticProcedure(page).enter_date_of_symptomatic_procedure( + datetime.today() - timedelta(days=1) + ) + + # And the Screening Interval is 36 months + LnpcpResultFromSymptomaticProcedure(page).assert_text_in_alert_textbox( + "recall interval of 36 months" + ) + + # And I select test number 1 + LnpcpResultFromSymptomaticProcedure(page).select_test_number(1) + + # And I save the Result from Symptomatic Procedure + LnpcpResultFromSymptomaticProcedure(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Latest not-void test in latest episode", + "latest episode accumulated result": "LNPCP", + "latest event status": "A373 Symptomatic result recorded", + "symptomatic procedure date": "Yesterday", + "symptomatic procedure result": "LNPCP", + }, + ) + + # When I advance the subject's episode for "Refer to Surveillance after Symptomatic Referral" + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_refer_to_surveillance_after_symptomatic_referral_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A374 Refer to Surveillance after Symptomatic Referral", + }, + ) + + # And there is a "A374" letter batch for my subject with the exact title "Return Surveillance Letter after Referral to Symptomatic" + # When I process the open "A374" letter batch for my subject + batch_processing( + page, + "A374", + "Return Surveillance Letter after Referral to Symptomatic", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Latest not-void test in latest episode", + "calculated fobt due date": "Unchanged", + "calculated lynch due date": "Null", + "calculated surveillance due date": "3 years from symptomatic procedure", + "ceased confirmation date": "Null", + "ceased confirmation details": "Null", + "ceased confirmation user id": "Null", + "clinical reason for cease": "Null", + "diagnostic test has result": "No result", + "latest episode accumulated result": "LNPCP", + "latest episode recall calculation method": "Symptomatic Procedure date", + "latest episode recall episode type": "Surveillance - LNPCP", + "latest episode recall surveillance type": "LNPCP", + "latest episode status": "Closed", + "latest episode status reason": "Episode Complete", + "latest event status": "A157 LNPCP", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Null", + "screening due date date of change": "Unchanged", + "screening due date reason": "Unchanged", + "screening referral type": "Null", + "screening status": "Surveillance", + "screening status date of change": "Unchanged", + "screening status reason": "Unchanged", + "surveillance due date": "Calculated Surveillance Due Date", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Result - LNPCP", + "symptomatic procedure date": "Yesterday", + "symptomatic procedure result": "LNPCP", + }, + ) + + # When I switch users to BCSS "England" as user role "Hub Manager" + LogoutPage(page).log_out(close_page=False) + BasePage(page).go_to_log_in_page() + user_role = UserTools.user_login(page, "Hub Manager at BCS01", True) + + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I manually cease the subject with reason "No Colon (subject request)" + SubjectScreeningSummaryPage(page).click_request_cease_button() + RecordRequestToCeasePage(page).cease_subject_with_reason( + "No Colon (subject request)" + ) + + # Then my subject has been updated as follows + subject_assertion( + nhs_no, + { + "calculated fobt due date": "Unchanged", + "calculated lynch due date": "Unchanged", + "calculated surveillance due date": "Unchanged", + "ceased confirmation date": "Today", + "ceased confirmation details": "AUTO TESTING: confirm not-immediate manual cease", + "ceased confirmation user id": "User's ID", + "clinical reason for cease": "Null", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Null", + "screening due date date of change": "Unchanged", + "screening due date reason": "Ceased", + "screening status": "Ceased", + "screening status date of change": "Today", + "screening status reason": "No Colon (subject request)", + "surveillance due date": "Null", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Ceased", + }, + user_role, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I manually uncease the subject to "send a new kit" + SubjectScreeningSummaryPage(page).click_uncease_subject_button() + UnceaseAndInitiateOptinEpisodePage(page).manually_uncease_the_subject( + "send a new kit" + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "calculated fobt due date": "Unchanged", + "calculated lynch due date": "Null", + "calculated surveillance due date": "Unchanged", + "ceased confirmation date": "Null", + "ceased confirmation details": "Null", + "ceased confirmation user id": "Null", + "clinical reason for cease": "Null", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Today", + "screening due date date of change": "Today", + "screening due date reason": "Opt (Back) into Screening Programme", + "screening status": "Opt-in", + "screening status date of change": "Today", + "screening status reason": "Opt (Back) into Screening Programme", + "surveillance due date": "Null", + "surveillance due date date of change": "Unchanged", + "surveillance due date reason": "Null", + }, + ) + + # When Comment: + logging.info( + "The Surveillance episode can be reopened, taking the subject back to Surveillance status" + ) + logging.info( + "NB the Calculated FOBT due date is nullified during the reopen, which seems odd!" + ) + + # When I switch users to BCSS "England" as user role "Screening Centre Manager" + LogoutPage(page).log_out(close_page=False) + BasePage(page).go_to_log_in_page() + user_role = UserTools.user_login(page, "Screening Centre Manager at BCS001", True) + if user_role is None: + raise ValueError("User cannot be assigned to a UserRoleType") + + # And I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I reopen the subject's episode for "Reopen to Re-record Outcome from Symptomatic Referral" + SubjectScreeningSummaryPage(page).click_reopen_surveillance_episode_button() + ReopenSurveillanceEpisodePage( + page + ).click_reopen_to_rerecord_outcome_from_symptomatic_referral_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "calculated fobt due date": "Null", + "calculated lynch due date": "Null", + "calculated surveillance due date": "As at episode start", + "ceased confirmation date": "Null", + "ceased confirmation details": "Null", + "ceased confirmation user id": "Null", + "clinical reason for cease": "Null", + "latest episode accumulated result": "No Result", + "latest episode recall calculation method": "Symptomatic Procedure date", + "latest episode recall episode type": "Null", + "latest episode recall surveillance type": "LNPCP", + "latest episode status": "Open", + "latest episode status reason": "Null", + "latest event status": "A372 Refer Symptomatic, GP Letter Printed", + "lynch due date": "Null", + "lynch due date date of change": "Unchanged", + "lynch due date reason": "Unchanged", + "screening due date": "Null", + "screening due date date of change": "Today", + "screening due date reason": "Reopened Episode", + "screening status": "Surveillance", + "screening status date of change": "Today", + "screening status reason": "Reopened Episode", + "surveillance due date": "As at episode start", + "surveillance due date date of change": "Today", + "surveillance due date reason": "Reopened Episode", + }, + ) + + # When I view the advance episode options + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + + # And I select the advance episode option for "LNPCP Result from Symptomatic Procedure" + AdvanceSurveillanceEpisodePage( + page + ).click_lnpcp_result_from_symptomatic_procedure_button() + + # And I set the Date of Symptomatic Procedure to "today" + LnpcpResultFromSymptomaticProcedure(page).enter_date_of_symptomatic_procedure( + datetime.today() + ) + + # And the Screening Interval is 36 months + LnpcpResultFromSymptomaticProcedure(page).assert_text_in_alert_textbox( + "recall interval of 36 months" + ) + + # And I select test number 1 + LnpcpResultFromSymptomaticProcedure(page).select_test_number(1) + + # And I save the Result from Symptomatic Procedure + LnpcpResultFromSymptomaticProcedure(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "which diagnostic test": "Latest not-void test in latest episode", + "latest episode accumulated result": "LNPCP", + "latest event status": "A373 Symptomatic result recorded", + "symptomatic procedure date": "Today", + "symptomatic procedure result": "LNPCP", + }, + ) + + # When I select the advance episode option for "Refer Another Diagnostic Test after return from Symptomatic Referral" + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_refer_another_diagnostic_test_after_return_from_symptomatic_referral_button() + + # And I select Referral Type of "Radiological" for the Diagnostic Test Referral Following Symptomatic Procedure + # And I select Referral Type of "Radiological" for the Diagnostic Test Referral Following Symptomatic Procedure + ReturnFromSymptomaticReferralPage( + page + ).select_radiological_or_endoscopic_referral_option("Radiological") + + # And I select Reason for Onward Referral of "Further Clinical Assessment" for the Diagnostic Test Referral Following Symptomatic Procedure + ReturnFromSymptomaticReferralPage(page).select_reason_for_onward_referral_option( + "Further Clinical Assessment" + ) + + # And I save the Diagnostic Test Referral Following Symptomatic Procedure + ReturnFromSymptomaticReferralPage(page).click_save_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A389 Refer Another Diagnostic Test after return from Symptomatic Referral" + }, + ) + + # When Comment: + logging.info( + "Temporary pathway until the Return from Symptomatic Referral - Refer Another Diagnostic Test screen is built in BCSS-16246" + ) + + # When I advance the subject's episode for "Post-investigation Appointment Required" + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_surveillance_episode_button() + AdvanceSurveillanceEpisodePage( + page + ).click_post_investigation_appointment_required_button() + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A360 Post-investigation Appointment Required", + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I choose to book a practitioner clinic for my subject + SubjectScreeningSummaryPage(page).click_book_practitioner_clinic_button() + + # And I set the practitioner appointment date to "today" + # And I book the earliest available post investigation appointment on this date + book_post_investigation_appointment(page, "The Royal Hospital (Wolverhampton)") + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + {"latest event status": "A410 Post-investigation Appointment Made"}, + ) + + # And there is a "A410" letter batch for my subject with the exact title "Post-Investigation Appointment Invitation Letter" + # When I process the open "A410" letter batch for my subject + batch_processing( + page, + "A410", + "Post-Investigation Appointment Invitation Letter", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A415 Post-investigation Appointment Invitation Letter Printed" + }, + ) + + # When I view the subject + screening_subject_page_searcher.navigate_to_subject_summary_page(page, nhs_no) + + # And I view the event history for the subject's latest episode + SubjectScreeningSummaryPage(page).expand_episodes_list() + SubjectScreeningSummaryPage(page).click_first_surveillance_episode_link() + + # And I view the latest practitioner appointment in the subject's episode + EpisodeEventsAndNotesPage(page).click_most_recent_view_appointment_link() + + # And I attend the subject's practitioner appointment "today" + AppointmentDetailPage(page).mark_appointment_as_attended(datetime.today()) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode includes event status": "A416 Post-investigation Appointment Attended", + }, + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest episode includes event status": "A316 Post-investigation Appointment Attended", + "latest event status": "A319 Refer follow-up test after return from symptomatic referral letter (Patient & GP)", + }, + ) + + # And there is a "A319" letter batch for my subject with the exact title "Result Letters - Refer another test after symptomatic referral" + # When I process the open "A319" letter batch for my subject + batch_processing( + page, + "A319", + "Result Letters - Refer another test after symptomatic referral", + ) + + # Then my subject has been updated as follows: + subject_assertion( + nhs_no, + { + "latest event status": "A395 Refer Another Diagnostic Test", + }, + ) + + LogoutPage(page).log_out()