diff --git a/docs/utility-guides/InvestigationDataset.md b/docs/utility-guides/InvestigationDataset.md index 3521bbf1..6e866463 100644 --- a/docs/utility-guides/InvestigationDataset.md +++ b/docs/utility-guides/InvestigationDataset.md @@ -162,33 +162,33 @@ after_investigation.progress_episode_based_on_result(result, younger) You can initialise the class and use its method as follows: ```python -from utils.investigation_dataset_completion import InvestigationDatasetCompletion +from utils.investigation_dataset import InvestigationDatasetCompletion completion_utility = InvestigationDatasetCompletion(page) completion_utility.complete_dataset_with_args( - general_information=..., - drug_information=..., - endoscopy_information=..., - failure_information=..., - completion_information=..., - polyp_1_information=..., - polyp_1_intervention=..., - polyp_1_histology=... + general_information=general_information, + drug_information=drug_information, + endoscopy_information=endoscopy_information, + failure_information=failure_information, + polyp_information=polyp_information, # List of dicts, one per polyp + polyp_intervention=polyp_intervention, # List of dicts, one per polyp + polyp_histology=polyp_histology # List of dicts, one per polyp ) ``` ### Required Args All fields are `dict` objects containing key-value pairs that match the expected form inputs. +For polyps, you now pass **lists of dictionaries** (one per polyp) for `polyp_information`, `polyp_intervention`, and `polyp_histology`. - `general_information` (required): Information about site, practitioner, and endoscopist. - `drug_information` (required): Drugs used during the procedure. - `endoscopy_information` (required): Field-value pairs describing procedure details. - `failure_information` (required): Reasons for dataset failure. - `completion_information` (optional): Completion proof values. -- `polyp_1_information` (optional): Data for a polyp entry. -- `polyp_1_intervention` (optional): Data for a polyp intervention. -- `polyp_1_histology` (optional): Histology data for the polyp. +- `polyp_information` (optional): **List** of dicts, each for a polyp entry. +- `polyp_intervention` (optional): **List** of dicts, each for a polyp intervention. +- `polyp_histology` (optional): **List** of dicts, each for a polyp's histology. ### How to use this method @@ -196,7 +196,7 @@ Call the `complete_dataset_with_args()` method to populate and submit the invest - Navigates to relevant form sections. - Inputs field values using select/input locators. -- Handles optional sub-sections (e.g., polyps, interventions). +- Handles optional sub-sections (e.g., polyps, interventions, histology) for **multiple polyps**. - Handles conditional logic for field population. - Submits the form once complete. @@ -204,68 +204,166 @@ Call the `complete_dataset_with_args()` method to populate and submit the invest ### Example Usage +Below is a real-world example based on the `test_identify_diminutive_rectal_hyperplastic_polyp_from_histology_a` test: + ```python -completion_utility = InvestigationDatasetCompletion(page) +from datetime import datetime +from utils.investigation_dataset import InvestigationDatasetCompletion +from pages.datasets.investigation_dataset_page import ( + DrugTypeOptions, BowelPreparationQualityOptions, ComfortOptions, + EndoscopyLocationOptions, YesNoOptions, InsufflationOptions, + OutcomeAtTimeOfProcedureOptions, LateOutcomeOptions, FailureReasonsOptions, + PolypClassificationOptions, PolypAccessOptions, PolypInterventionModalityOptions, + PolypInterventionDeviceOptions, PolypInterventionExcisionTechniqueOptions, + PolypTypeOptions, SerratedLesionSubTypeOptions, PolypExcisionCompleteOptions +) -completion_utility.complete_dataset_with_args( - general_information={ - "site": -1, - "practitioner": -1, - "testing clinician": -1, - "aspirant endoscopist": None - }, - drug_information = { - "drug_type1": DrugTypeOptions.MANNITOL, - "drug_dose1": "3", - }, - 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, - }, - failure_information={ - "failure reasons": FailureReasonsOptions.ADHESION +general_information = { + "site": -1, + "practitioner": -1, + "testing clinician": -1, + "aspirant endoscopist": None, +} + +drug_information = { + "drug_type1": DrugTypeOptions.MANNITOL, + "drug_dose1": "3", +} + +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.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, +} + +failure_information = { + "failure reasons": FailureReasonsOptions.ADHESION, +} + +# Example for 4 polyps +polyp_information = [ + { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.IP, + "estimate of whole polyp size": "6", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, }, - completion_information={ - "completion proof": CompletionProofOptions.VIDEO_APPENDIX + { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.ISP, + "estimate of whole polyp size": "1", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, }, - polyp_1_information={ - "location": EndoscopyLocationOptions.APPENDIX, + { + "location": EndoscopyLocationOptions.RECTUM, "classification": PolypClassificationOptions.IS, - "estimate of whole polyp size": "8", + "estimate of whole polyp size": "2", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + }, + { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.IIC, + "estimate of whole polyp size": "5", "polyp access": PolypAccessOptions.EASY, "left in situ": YesNoOptions.NO, }, - polyp_1_intervention={ +] + +polyp_intervention = [ + { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + }, + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + }, + { + "modality": PolypInterventionModalityOptions.ESD, + "device": PolypInterventionDeviceOptions.ENDOSCOPIC_KNIFE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + }, + { "modality": PolypInterventionModalityOptions.POLYPECTOMY, - "device": PolypInterventionDeviceOptions.COLD_SNARE, + "device": PolypInterventionDeviceOptions.HOT_SNARE, "excised": YesNoOptions.YES, "retrieved": YesNoOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + }, +] + +polyp_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", + }, + { + "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": "1", + }, + { + "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": "3", }, - polyp_1_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.MIXED_POLYP, + "serrated lesion sub type": SerratedLesionSubTypeOptions.HYPERPLASTIC_POLYP, "polyp excision complete": PolypExcisionCompleteOptions.R1, - "polyp size": "10", - "polyp dysplasia": PolypDysplasiaOptions.NOT_REPORTED, - "polyp carcinoma": YesNoUncertainOptions.NO, - } + "polyp size": "4", + }, +] + +completion_utility = InvestigationDatasetCompletion(page) +completion_utility.complete_dataset_with_args( + general_information=general_information, + drug_information=drug_information, + endoscopy_information=endoscopy_information, + failure_information=failure_information, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) ``` @@ -275,79 +373,89 @@ completion_utility.complete_dataset_with_args( #### General Information -| Field | Type | Description | -|------------------------|---------|--------------------------------------| -| site | `int` | Index in the site dropdown | -| practitioner | `int` | Index in the practitioner dropdown | -| testing clinician | `int` | Index in the clinician dropdown | -| aspirant endoscopist | `int or None` | Index or skip check if None | +| Field | Type | Example Value | Description | +|-----------------------|---------|-----------------------------------------------|--------------------------------------| +| site | `int` | -1 | Index in the site dropdown | +| practitioner | `int` | -1 | Index in the practitioner dropdown | +| testing clinician | `int` | -1 | Index in the clinician dropdown | +| aspirant endoscopist | `int or None` | None | Index or skip check if None | #### Drug Information -| Field | Type | Description | -|--------------|-------|------------------------------------| -| drug_type1 | str | Drug name | -| drug_dose1 | str | Dose | +| Field | Type | Example Value | Description | +|--------------|-------|-----------------------------|------------------------------------| +| drug_type1 | str | DrugTypeOptions.MANNITOL | Drug name | +| drug_dose1 | str | "3" | Dose | #### Endoscopy Information - -Supports dynamic keys like: - -- `"endoscope inserted"`: `"yes"` or `"no"` -- `"procedure type"`: `"diagnostic"` or `"therapeutic"` -- `"bowel preparation quality"`: Option from dropdown -- `"start of intubation time"`: `"09:00"` -- `"scope id"`: Free text - + +| Field | Type | Example Value | Description | +|------------------------------|---------|-------------------------------------------------------|--------------------------------------| +| endoscope inserted | str | "yes" | "yes" or "no" | +| procedure type | str | "therapeutic" | "diagnostic" or "therapeutic" | +| bowel preparation quality | enum | BowelPreparationQualityOptions.GOOD | Option from dropdown | +| comfort during examination | enum | ComfortOptions.NO_DISCOMFORT | Option from dropdown | +| comfort during recovery | enum | ComfortOptions.NO_DISCOMFORT | Option from dropdown | +| endoscopist defined extent | enum | EndoscopyLocationOptions.DESCENDING_COLON | Option from dropdown | +| scope imager used | enum | YesNoOptions.YES | Option from dropdown | +| retroverted view | enum | YesNoOptions.NO | Option from dropdown | +| start of intubation time | str | "09:00" | Time string | +| start of extubation time | str | "09:30" | Time string | +| end time of procedure | str | "10:00" | Time string | +| scope id | str | "Autotest" | Free text | +| insufflation | enum | InsufflationOptions.AIR | Option from dropdown | +| outcome at time of procedure | enum | OutcomeAtTimeOfProcedureOptions.LEAVE_DEPARTMENT | Option from dropdown | +| late outcome | enum | LateOutcomeOptions.NO_COMPLICATIONS | Option from dropdown | + #### Failure Information - -| Field | Type | Description | -|-------------------|-------|------------------------------------------| -| failure reasons | str | Reason text for dataset failure | - + +| Field | Type | Example Value | Description | +|--------------------|-------|-------------------------------------|------------------------------------------| +| failure reasons | enum | FailureReasonsOptions.ADHESION | Reason text for dataset failure | + #### Completion Proof Information - -| Field | Type | Description | -|-------------------|-------|------------------------------------------| -| completion proof | str | Value for the "Proof Parameters" field | - + +| Field | Type | Example Value | Description | +|--------------------|-------|-------------------------------------|------------------------------------------| +| completion proof | enum | CompletionProofOptions.VIDEO_APPENDIX| Value for the "Proof Parameters" field | + #### Polyp Information (Optional) -| Field | Type | Description | -|-----------------------------|-------|--------------------------------------| -| location | str | Polyp location | -| classification | str | Polyp classification | -| estimate of whole polyp size| str | Size in mm | -| polyp access | str | Access difficulty | -| left in situ | str | `"Yes"` or `"No"` | +| Field | Type | Example Value | Description | +|------------------------------|-------|-----------------------------------------------|--------------------------------------| +| location | enum | EndoscopyLocationOptions.RECTUM | Polyp location | +| classification | enum | PolypClassificationOptions.IP | Polyp classification | +| estimate of whole polyp size | str | "6" | Size in mm | +| polyp access | enum | PolypAccessOptions.EASY | Access difficulty | +| left in situ | enum | YesNoOptions.NO | "Yes" or "No" | #### Polyp Intervention (Optional) - -| Field | Type | Description | -|----------------------------------------|-------|---------------------------------| -| modality | str | E.g., `"Polypectomy"` | -| device | str | E.g., `"Cold snare"` | -| excised | str | `"Yes"` or `"No"` | -| retrieved | str | `"Yes"` or `"No"` | -| excision technique | str | Optional technique detail | -| polyp appears fully resected endoscopically | str | Option from dropdown | - + +| Field | Type | Example Value | Description | +|------------------------------------------|-------|-------------------------------------------------------|---------------------------------| +| modality | enum | PolypInterventionModalityOptions.POLYPECTOMY | E.g., "Polypectomy" | +| device | enum | PolypInterventionDeviceOptions.HOT_SNARE | E.g., "Hot snare" | +| excised | enum | YesNoOptions.YES | "Yes" or "No" | +| retrieved | enum | YesNoOptions.YES | "Yes" or "No" | +| excision technique | enum | PolypInterventionExcisionTechniqueOptions.PIECE_MEAL | Optional technique detail | +| polyp appears fully resected endoscopically | enum | YesNoOptions.YES | Option from dropdown | + #### Polyp Histology (Optional) - -| Field | Type | Description | -|--------------------------|-------------|-------------------------------------| -| date of receipt | `datetime` | Date of receipt | -| date of reporting | `datetime` | Date of reporting | -| pathology provider | `int` | Index for provider | -| pathologist | `int` | Index for pathologist | -| polyp type | `str` | E.g., `"Serrated Lesion"` | -| serrated lesion sub type | `str` | Subtype of serrated lesion | -| adenoma sub type | `str` | Subtype of adenoma | -| polyp excision complete | `str` | Completion status | -| polyp size | `str` | Size in mm | -| polyp dysplasia | `str` | Dysplasia report | -| polyp carcinoma | `str` | `"Yes"`, `"No"`, or `"Uncertain"` | - + +| Field | Type | Example Value | Description | +|---------------------------|-------------|-------------------------------------------------------|-------------------------------------| +| date of receipt | `datetime` | datetime.today() | Date of receipt | +| date of reporting | `datetime` | datetime.today() | Date of reporting | +| pathology provider | `int` | -1 | Index for provider | +| pathologist | `int` | -1 | Index for pathologist | +| polyp type | enum | PolypTypeOptions.SERRATED_LESION | E.g., "Serrated Lesion" | +| serrated lesion sub type | enum | SerratedLesionSubTypeOptions.HYPERPLASTIC_POLYP | Subtype of serrated lesion | +| adenoma sub type | enum | AdenomaSubTypeOptions.TUBULAR_ADENOMA | Subtype of adenoma | +| polyp excision complete | enum | PolypExcisionCompleteOptions.R1 | Completion status | +| polyp size | str | "5" | Size in mm | +| polyp dysplasia | enum | PolypDysplasiaOptions.NOT_REPORTED | Dysplasia report | +| polyp carcinoma | enum | YesNoUncertainOptions.NO | "Yes", "No", or "Uncertain" | + --- For more details on each function's implementation, refer to the source code in `utils/investigation_dataset.py`. diff --git a/pages/datasets/investigation_dataset_page.py b/pages/datasets/investigation_dataset_page.py index 269de654..7bfd0171 100644 --- a/pages/datasets/investigation_dataset_page.py +++ b/pages/datasets/investigation_dataset_page.py @@ -6,6 +6,7 @@ get_investigation_dataset_polyp_algorithm_size, ) from typing import Optional +import logging class InvestigationDatasetsPage(BasePage): @@ -15,6 +16,8 @@ def __init__(self, page: Page): super().__init__(page) self.page = page + self.add_intervention_string = "Add Intervention" + # Investigation datasets page locators self.site_lookup_link = self.page.locator("#UI_SITE_SELECT_LINK") self.practitioner_link = self.page.locator("#UI_SSP_PIO_SELECT_LINK") @@ -47,11 +50,11 @@ def __init__(self, page: Page): self.show_failure_information_details = self.page.locator("#anchorFailure") self.add_polyp_button = self.page.get_by_role("button", name="Add Polyp") self.polyp1_add_intervention_button = self.page.get_by_role( - "link", name="Add Intervention" + "link", name=self.add_intervention_string ) self.polyp2_add_intervention_button = self.page.locator( "#spanPolypInterventionLink2" - ).get_by_role("link", name="Add Intervention") + ).get_by_role("link", name=self.add_intervention_string) self.dataset_complete_checkbox = self.page.locator("#radDatasetCompleteYes") self.dataset_incomplete_checkbox = self.page.locator("#radDatasetCompleteNo") self.save_dataset_button = self.page.locator( @@ -361,6 +364,21 @@ def select_polyp1_pathologist_option_index(self, option: int) -> None: option_elements.nth(option).wait_for(state="visible") self.click(option_elements.nth(option)) + def select_loopup_option_index(self, option: int) -> None: + """ + This method is designed to select a lookup option by index. + It clicks on the lookup link and selects the given option by index. + + Args: + option (int): The index of the option to select from the lookup options. + """ + select_locator = self.page.locator(self.visible_ui_results_string) + select_locator.first.wait_for(state="visible") + # Find all option elements inside the select and click the one at the given index + option_elements = select_locator.first.locator("option") + option_elements.nth(option).wait_for(state="visible") + self.click(option_elements.nth(option)) + def click_edit_dataset_button(self) -> None: """ This method is designed to click on the edit dataset button. @@ -387,6 +405,10 @@ def assert_polyp_alogrithm_size( ) # Assert that the actual value matches the expected value + logging.info( + f"Checking Polyp {polyp_number} algorithm size: actual={actual_value}, expected={expected_value}" + ) + if actual_value is None or expected_value is None: assert ( actual_value == expected_value @@ -415,6 +437,10 @@ def assert_polyp_categrory( ) # Assert that the actual value matches the expected value + logging.info( + f"Checking Polyp {polyp_number} category: actual={actual_value}, expected={expected_value}" + ) + if actual_value is None or expected_value is None: assert ( actual_value == expected_value @@ -443,6 +469,20 @@ def get_dataset_id(self) -> int: dataset_id = -1 return dataset_id + def click_polyp_add_intervention_button(self, polyp_number: int) -> None: + """ + Clicks the add intervention button for the specified polyp number. + + Args: + polyp_number (int): The number of the polyp. + """ + + self.click( + self.page.locator(f"#spanPolypInterventionLink{polyp_number}").get_by_role( + "link", name=self.add_intervention_string + ) + ) + class SiteLookupOptions(StrEnum): """Enum for site lookup options""" diff --git a/pages/screening_subject_search/contact_with_patient_page.py b/pages/screening_subject_search/contact_with_patient_page.py index e2714038..7ce3e3fe 100644 --- a/pages/screening_subject_search/contact_with_patient_page.py +++ b/pages/screening_subject_search/contact_with_patient_page.py @@ -1,5 +1,7 @@ from playwright.sync_api import Page from pages.base_page import BasePage +from utils.calendar_picker import CalendarPicker +from datetime import datetime class ContactWithPatientPage(BasePage): @@ -84,3 +86,19 @@ def select_outcome_dropdown_option(self, outcome: str) -> None: def click_save_button(self) -> None: """Click the 'Save' button to save the contact with patient form.""" self.click(self.save_button) + + def record_post_investigation_appointment_not_required(self) -> None: + """ + Record a post-investigation appointment not required contact. + """ + self.select_direction_dropdown_option("To patient") + self.select_caller_id_dropdown_index_option(1) + self.click_calendar_button() + CalendarPicker(self.page).v1_calender_picker(datetime.today()) + self.enter_start_time("11:00") + self.enter_end_time("12:00") + self.enter_discussion_record_text("Test Automation") + self.select_outcome_dropdown_option( + "Post-investigation Appointment Not Required" + ) + self.click_save_button() diff --git a/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_advanced_colorectal_polyp.py b/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_advanced_colorectal_polyp.py index 8471a7b2..88aa4ce6 100644 --- a/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_advanced_colorectal_polyp.py +++ b/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_advanced_colorectal_polyp.py @@ -1,11 +1,8 @@ import logging import pytest -import pandas as pd from pytest import FixtureRequest from datetime import datetime from playwright.sync_api import Page -from classes.subject import Subject -from classes.user import User from pages.base_page import BasePage from pages.datasets.investigation_dataset_page import ( InvestigationDatasetsPage, @@ -33,32 +30,21 @@ ) from pages.datasets.subject_datasets_page import SubjectDatasetsPage from pages.logout.log_out_page import LogoutPage -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.subject_screening_summary_page import ( SubjectScreeningSummaryPage, ) -from pages.screening_subject_search.advance_fobt_screening_episode_page import ( - AdvanceFOBTScreeningEpisodePage, -) -from utils.batch_processing import batch_processing -from utils.calendar_picker import CalendarPicker from utils.investigation_dataset import ( InvestigationDatasetCompletion, ) -from utils.oracle.oracle import OracleDB -from utils.oracle.subject_selection_query_builder import SubjectSelectionQueryBuilder from utils.screening_subject_page_searcher import ( search_subject_episode_by_nhs_number, ) +from utils.datasets.investigation_datasets import ( + get_subject_with_investigation_dataset_ready, + go_from_investigation_dataset_complete_to_a259_status, + get_subject_with_a99_status, + go_from_a99_status_to_a259_status, +) from utils.user_tools import UserTools # Defining dictionaries used in tests @@ -108,7 +94,7 @@ def before_test(page: Page, request: FixtureRequest) -> None: """ if request.node.get_closest_marker("skip_before_test"): return - df = obtain_test_data() + df = get_subject_with_investigation_dataset_ready() nhs_no = df.iloc[0]["subject_nhs_number"] logging.info(f"NHS Number: {nhs_no}") @@ -151,14 +137,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_a(page: Page) -> None ) del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + InvestigationDatasetCompletion(page).complete_dataset_with_args( general_information=general_information, drug_information=drug_information, endoscopy_information=endoscopy_information, failure_information=failure_information, - polyp_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "9") @@ -192,15 +182,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_b(page: Page) -> None ) del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "8") @@ -230,15 +223,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_c(page: Page) -> None polyp_1_histology = make_polyp_1_histology() del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "10") @@ -272,15 +268,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_d(page: Page) -> None ) del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "11") @@ -319,15 +318,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_e(page: Page) -> None del polyp_1_histology["polyp carcinoma"] del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "11") @@ -363,15 +365,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_f(page: Page) -> None del polyp_1_histology["polyp dysplasia"] del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "10") @@ -405,15 +410,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_g(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "10") @@ -449,15 +457,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_h(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "12") @@ -496,15 +507,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_i(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "11") @@ -537,15 +551,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_j(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "13") @@ -580,15 +597,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_k(page: Page) -> None ) del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "7") @@ -624,15 +644,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_l(page: Page) -> None ) del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "6") @@ -668,15 +691,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_m(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "5") @@ -714,15 +740,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_n(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "4") @@ -761,15 +790,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_o(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "3") @@ -806,15 +838,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_p(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "2") @@ -850,15 +885,18 @@ def test_identify_advanced_colorectal_polyp_from_histology_q(page: Page) -> None ) del polyp_1_histology["serrated lesion sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "20") @@ -872,59 +910,13 @@ def test_identify_advanced_colorectal_polyp_from_histology_r(page: Page) -> None """ This test identifies an advanced colorectal polyp from histology results (BCSS-5567 - R). """ - criteria = { - "latest episode has colonoscopy assessment dataset": "yes_complete", - "latest episode has diagnostic test": "no", - "latest event status": "A99", - "latest episode type": "FOBT", - "latest episode started": "less than 4 years ago", - } - user = User() - subject = Subject() - - builder = SubjectSelectionQueryBuilder() - - query, bind_vars = builder.build_subject_selection_query( - criteria=criteria, - user=user, - subject=subject, - subjects_to_retrieve=1, - ) - - df = OracleDB().execute_query(query, bind_vars) + df = get_subject_with_a99_status() nhs_no = df.iloc[0]["subject_nhs_number"] logging.info(f"NHS Number: {nhs_no}") UserTools.user_login(page, "Screening Centre Manager at BCS001") - BasePage(page).click_main_menu_link() - BasePage(page).go_to_screening_subject_search_page() - search_subject_episode_by_nhs_number(page, nhs_no) - SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() - - AdvanceFOBTScreeningEpisodePage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - - AdvanceFOBTScreeningEpisodePage(page).select_test_type_dropdown_option( - "Colonoscopy" - ) - - AdvanceFOBTScreeningEpisodePage(page).click_invite_for_diagnostic_test_button() - AdvanceFOBTScreeningEpisodePage(page).verify_latest_event_status_value( - "A59 - Invited for Diagnostic Test" - ) - - AdvanceFOBTScreeningEpisodePage(page).click_attend_diagnostic_test_button() - - AttendDiagnosticTestPage(page).select_actual_type_of_test_dropdown_option( - "Colonoscopy" - ) - AttendDiagnosticTestPage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - AttendDiagnosticTestPage(page).click_save_button() - SubjectScreeningSummaryPage(page).verify_latest_event_status_value( - "A259 - Attended Diagnostic Test" - ) + go_from_a99_status_to_a259_status(page, nhs_no) SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() @@ -954,99 +946,21 @@ def test_identify_advanced_colorectal_polyp_from_histology_r(page: Page) -> None ) del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, - ) - - # Enter the test outcome > A315 - BasePage(page).click_back_button() - BasePage(page).click_back_button() - SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() - AdvanceFOBTScreeningEpisodePage(page).click_enter_diagnostic_test_outcome_button() - DiagnosticTestOutcomePage(page).select_test_outcome_option( - OutcomeOfDiagnosticTest.FAILED_TEST_REFER_ANOTHER - ) - DiagnosticTestOutcomePage(page).click_save_button() - SubjectScreeningSummaryPage(page).verify_latest_event_status_value( - "A315 - Diagnostic Test Outcome Entered" - ) - - # Make post investigation contact > A361 - SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() - AdvanceFOBTScreeningEpisodePage(page).click_other_post_investigation_button() - AdvanceFOBTScreeningEpisodePage(page).verify_latest_event_status_value( - "A361 - Other Post-investigation Contact Required" - ) - - AdvanceFOBTScreeningEpisodePage( - page - ).click_record_other_post_investigation_contact_button() - ContactWithPatientPage(page).select_direction_dropdown_option("To patient") - ContactWithPatientPage(page).select_caller_id_dropdown_index_option(1) - ContactWithPatientPage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - ContactWithPatientPage(page).enter_start_time("11:00") - ContactWithPatientPage(page).enter_end_time("12:00") - ContactWithPatientPage(page).enter_discussion_record_text("Test Automation") - ContactWithPatientPage(page).select_outcome_dropdown_option( - "Post-investigation Appointment Not Required" - ) - ContactWithPatientPage(page).click_save_button() - BasePage(page).click_back_button() - SubjectScreeningSummaryPage(page).verify_latest_event_status_value( - "A318 - Post-investigation Appointment NOT Required - Result Letter Created" - ) - - # Process the A318 letters > A380 - batch_processing( - page, - "A318", - "Result Letters - No Post-investigation Appointment", - "A380 - Failed Diagnostic Test - Refer Another", - ) - - # Another contact to bring the subject back to A99 - SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() - AdvanceFOBTScreeningEpisodePage(page).click_record_contact_with_patient_button() - ContactWithPatientPage(page).select_direction_dropdown_option("To patient") - ContactWithPatientPage(page).select_caller_id_dropdown_index_option(1) - ContactWithPatientPage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - ContactWithPatientPage(page).enter_start_time("11:00") - ContactWithPatientPage(page).enter_end_time("12:00") - ContactWithPatientPage(page).enter_discussion_record_text("Test Automation") - ContactWithPatientPage(page).select_outcome_dropdown_option( - "Suitable for Endoscopic Test" - ) - ContactWithPatientPage(page).click_save_button() - AdvanceFOBTScreeningEpisodePage(page).verify_latest_event_status_value( - "A99 - Suitable for Endoscopic Test" - ) - - # Invite for 2nd diagnostic test > A59 - check options - AdvanceFOBTScreeningEpisodePage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - AdvanceFOBTScreeningEpisodePage(page).select_test_type_dropdown_option_2( - "Colonoscopy" - ) - AdvanceFOBTScreeningEpisodePage(page).click_invite_for_diagnostic_test_button() - AdvanceFOBTScreeningEpisodePage(page).click_attend_diagnostic_test_button() - AttendDiagnosticTestPage(page).select_actual_type_of_test_dropdown_option( - "Colonoscopy" - ) - AttendDiagnosticTestPage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - AttendDiagnosticTestPage(page).click_save_button() - SubjectScreeningSummaryPage(page).verify_latest_event_status_value( - "A259 - Attended Diagnostic Test" + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) + + go_from_investigation_dataset_complete_to_a259_status(page) SubjectScreeningSummaryPage(page).click_datasets_link() SubjectDatasetsPage(page).click_investigation_show_datasets() @@ -1055,10 +969,9 @@ def test_identify_advanced_colorectal_polyp_from_histology_r(page: Page) -> None drug_information=drug_information, endoscopy_information=endoscopy_information, failure_information=failure_information, - completion_information=completion_information, - polyp_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "6") @@ -1092,46 +1005,23 @@ def test_identify_advanced_colorectal_polyp_from_histology_s(page: Page) -> None ) del polyp_1_histology["adenoma sub type"] + polyp_information = [polyp_1_information] + polyp_intervention = [polyp_1_intervention] + polyp_histology = [polyp_1_histology] + 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_1_information=polyp_1_information, - polyp_1_intervention=polyp_1_intervention, - polyp_1_histology=polyp_1_histology, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, ) assert_test_results(page, "32") -def obtain_test_data() -> pd.DataFrame: - """ - This function builds a query to retrieve subjects based on specific criteria - and returns a DataFrame containing the results. - """ - criteria = { - "latest episode status": "open", - "latest episode latest investigation dataset": "colonoscopy_new", - "latest episode started": "less than 4 years ago", - } - user = User() - subject = Subject() - - builder = SubjectSelectionQueryBuilder() - - query, bind_vars = builder.build_subject_selection_query( - criteria=criteria, - user=user, - subject=subject, - subjects_to_retrieve=1, - ) - - df = OracleDB().execute_query(query, bind_vars) - return df - - def make_polyp_1_information(**overrides): """ Create a dictionary containing default information about Polyp 1. diff --git a/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_diminutive_rectal_hyperplastic_polyp.py b/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_diminutive_rectal_hyperplastic_polyp.py new file mode 100644 index 00000000..0c5613ca --- /dev/null +++ b/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_diminutive_rectal_hyperplastic_polyp.py @@ -0,0 +1,345 @@ +import logging +import pytest +from datetime import datetime +from playwright.sync_api import Page +from pages.base_page import BasePage +from pages.datasets.investigation_dataset_page import ( + InvestigationDatasetsPage, + DrugTypeOptions, + BowelPreparationQualityOptions, + ComfortOptions, + EndoscopyLocationOptions, + YesNoOptions, + InsufflationOptions, + OutcomeAtTimeOfProcedureOptions, + LateOutcomeOptions, + FailureReasonsOptions, + PolypClassificationOptions, + PolypAccessOptions, + PolypInterventionModalityOptions, + PolypInterventionDeviceOptions, + PolypInterventionExcisionTechniqueOptions, + PolypTypeOptions, + SerratedLesionSubTypeOptions, + PolypExcisionCompleteOptions, +) +from pages.datasets.subject_datasets_page import SubjectDatasetsPage +from pages.logout.log_out_page import LogoutPage +from pages.screening_subject_search.subject_screening_summary_page import ( + SubjectScreeningSummaryPage, +) +from utils.investigation_dataset import ( + InvestigationDatasetCompletion, +) +from utils.screening_subject_page_searcher import ( + search_subject_episode_by_nhs_number, +) +from utils.user_tools import UserTools +from utils.datasets.investigation_datasets import ( + get_subject_with_investigation_dataset_ready, + go_from_investigation_dataset_complete_to_a259_status, + get_subject_with_a99_status, + go_from_a99_status_to_a259_status, +) + +general_information = { + "site": -1, + "practitioner": -1, + "testing clinician": -1, + "aspirant endoscopist": None, +} + +drug_information = { + "drug_type1": DrugTypeOptions.MANNITOL, + "drug_dose1": "3", +} + +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.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, +} + +failure_information = { + "failure reasons": FailureReasonsOptions.ADHESION, +} + + +@pytest.mark.vpn_required +@pytest.mark.regression +@pytest.mark.investigation_dataset_tests +def test_identify_diminutive_rectal_hyperplastic_polyp_from_histology_a( + page: Page, +) -> None: + """ + This test identifies a diminutive rectal hyperplastic polyp from histology results. (BCSS-4659 - A) + """ + df = get_subject_with_investigation_dataset_ready() + nhs_no = df.iloc[0]["subject_nhs_number"] + logging.info(f"NHS Number: {nhs_no}") + + UserTools.user_login(page, "Screening Centre Manager at BCS001") + BasePage(page).click_main_menu_link() + BasePage(page).go_to_screening_subject_search_page() + search_subject_episode_by_nhs_number(page, nhs_no) + + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + polyp_1_information = { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.IP, + "estimate of whole polyp size": "6", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + } + + polyp_1_intervention = { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + } + + polyp_1_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", + } + + polyp_2_information = { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.ISP, + "estimate of whole polyp size": "1", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + } + + polyp_2_intervention = { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + } + + polyp_2_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": "1", + } + + polyp_3_information = { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.IS, + "estimate of whole polyp size": "2", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + } + + polyp_3_intervention = { + "modality": PolypInterventionModalityOptions.ESD, + "device": PolypInterventionDeviceOptions.ENDOSCOPIC_KNIFE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + } + + polyp_3_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": "3", + } + + polyp_4_information = { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.IIC, + "estimate of whole polyp size": "5", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + } + + polyp_4_intervention = { + "modality": PolypInterventionModalityOptions.POLYPECTOMY, + "device": PolypInterventionDeviceOptions.HOT_SNARE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.PIECE_MEAL, + } + + polyp_4_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": "4", + } + + polyp_information = [ + polyp_1_information, + polyp_2_information, + polyp_3_information, + polyp_4_information, + ] + polyp_intervention = [ + polyp_1_intervention, + polyp_2_intervention, + polyp_3_intervention, + polyp_4_intervention, + ] + polyp_histology = [ + polyp_1_histology, + polyp_2_histology, + polyp_3_histology, + polyp_4_histology, + ] + + InvestigationDatasetCompletion(page).complete_dataset_with_args( + general_information=general_information, + drug_information=drug_information, + endoscopy_information=endoscopy_information, + failure_information=failure_information, + polyp_information=polyp_information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, + ) + + polyp_category_string = "Diminutive rectal hyperplastic polyp" + InvestigationDatasetsPage(page).expect_text_to_be_visible("Abnormal") + InvestigationDatasetsPage(page).assert_polyp_alogrithm_size(1, "5") + InvestigationDatasetsPage(page).assert_polyp_categrory(1, polyp_category_string) + InvestigationDatasetsPage(page).assert_polyp_alogrithm_size(2, "1") + InvestigationDatasetsPage(page).assert_polyp_categrory(2, polyp_category_string) + InvestigationDatasetsPage(page).assert_polyp_alogrithm_size(3, "3") + InvestigationDatasetsPage(page).assert_polyp_categrory(3, polyp_category_string) + InvestigationDatasetsPage(page).assert_polyp_alogrithm_size(4, "5") + InvestigationDatasetsPage(page).assert_polyp_categrory(4, polyp_category_string) + + logging.info("Marking investigation dataset not complete") + InvestigationDatasetsPage(page).click_edit_dataset_button() + InvestigationDatasetsPage(page).check_dataset_incomplete_checkbox() + InvestigationDatasetsPage(page).click_save_dataset_button() + for polyp_number in range(1, 5): + InvestigationDatasetsPage(page).assert_polyp_alogrithm_size(polyp_number, None) + InvestigationDatasetsPage(page).assert_polyp_categrory(polyp_number, None) + + LogoutPage(page).log_out() + + +@pytest.mark.vpn_required +@pytest.mark.regression +@pytest.mark.investigation_dataset_tests +def test_identify_diminutive_rectal_hyperplastic_polyp_from_histology_b( + page: Page, +) -> None: + """ + This test identifies a diminutive rectal hyperplastic polyp from histology results. (BCSS-4659 - B) + """ + df = get_subject_with_a99_status() + nhs_no = df.iloc[0]["subject_nhs_number"] + logging.info(f"NHS Number: {nhs_no}") + + UserTools.user_login(page, "Screening Centre Manager at BCS001") + + go_from_a99_status_to_a259_status(page, nhs_no) + + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + polyp__information = [ + { + "location": EndoscopyLocationOptions.RECTUM, + "classification": PolypClassificationOptions.LST_NG, + "estimate of whole polyp size": "4", + "polyp access": PolypAccessOptions.EASY, + "left in situ": YesNoOptions.NO, + } + ] + polyp_intervention = [ + { + "modality": PolypInterventionModalityOptions.EMR, + "device": PolypInterventionDeviceOptions.COLD_SNARE, + "excised": YesNoOptions.YES, + "retrieved": YesNoOptions.YES, + "excision technique": PolypInterventionExcisionTechniqueOptions.EN_BLOC, + } + ] + polyp_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": "2", + } + ] + + InvestigationDatasetCompletion(page).complete_dataset_with_args( + general_information=general_information, + drug_information=drug_information, + endoscopy_information=endoscopy_information, + failure_information=failure_information, + polyp_information=polyp__information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, + ) + # Enter the test outcome > A315 + go_from_investigation_dataset_complete_to_a259_status(page) + SubjectScreeningSummaryPage(page).click_datasets_link() + SubjectDatasetsPage(page).click_investigation_show_datasets() + + # Complete the investigation dataset + InvestigationDatasetCompletion(page).complete_dataset_with_args( + general_information=general_information, + drug_information=drug_information, + endoscopy_information=endoscopy_information, + failure_information=failure_information, + polyp_information=polyp__information, + polyp_intervention=polyp_intervention, + polyp_histology=polyp_histology, + ) + + InvestigationDatasetsPage(page).expect_text_to_be_visible("Abnormal") + InvestigationDatasetsPage(page).assert_polyp_alogrithm_size(1, "2") + InvestigationDatasetsPage(page).assert_polyp_categrory( + 1, "Diminutive rectal hyperplastic polyp" + ) + + logging.info("Marking investigation dataset not complete") + InvestigationDatasetsPage(page).click_edit_dataset_button() + InvestigationDatasetsPage(page).check_dataset_incomplete_checkbox() + InvestigationDatasetsPage(page).click_save_dataset_button() + InvestigationDatasetsPage(page).assert_polyp_alogrithm_size(1, None) + InvestigationDatasetsPage(page).assert_polyp_categrory(1, None) + LogoutPage(page).log_out() diff --git a/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_setup.py b/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_setup.py index ba0673ac..42400dd0 100644 --- a/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_setup.py +++ b/tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_setup.py @@ -35,9 +35,6 @@ from pages.screening_subject_search.advance_fobt_screening_episode_page import ( AdvanceFOBTScreeningEpisodePage, ) -from pages.screening_subject_search.attend_diagnostic_test_page import ( - AttendDiagnosticTestPage, -) from pages.screening_subject_search.episode_events_and_notes_page import ( EpisodeEventsAndNotesPage, ) @@ -61,6 +58,7 @@ verify_subject_event_status_by_nhs_no, ) from utils.user_tools import UserTools +from utils.datasets.investigation_datasets import go_from_a99_status_to_a259_status @pytest.fixture(scope="function", autouse=True) @@ -169,36 +167,8 @@ def test_setup_subjects_as_a259(page: Page, subjects_to_run_for: int) -> None: for _, row in df.iterrows(): nhs_no = row["nhs_number"] - - verify_subject_event_status_by_nhs_no( - page, nhs_no, "A99 - Suitable for Endoscopic Test" - ) - - SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() - - AdvanceFOBTScreeningEpisodePage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - - AdvanceFOBTScreeningEpisodePage(page).select_test_type_dropdown_option( - "Colonoscopy" - ) - - AdvanceFOBTScreeningEpisodePage(page).click_invite_for_diagnostic_test_button() - AdvanceFOBTScreeningEpisodePage(page).verify_latest_event_status_value( - "A59 - Invited for Diagnostic Test" - ) - - AdvanceFOBTScreeningEpisodePage(page).click_attend_diagnostic_test_button() - - AttendDiagnosticTestPage(page).select_actual_type_of_test_dropdown_option( - "Colonoscopy" - ) - AttendDiagnosticTestPage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - AttendDiagnosticTestPage(page).click_save_button() - SubjectScreeningSummaryPage(page).verify_latest_event_status_value( - "A259 - Attended Diagnostic Test" - ) + BasePage(page).click_main_menu_link() + go_from_a99_status_to_a259_status(page, nhs_no) LogoutPage(page).log_out() diff --git a/tests/smokescreen/test_compartment_5.py b/tests/smokescreen/test_compartment_5.py index 7fa355bd..29ba887f 100644 --- a/tests/smokescreen/test_compartment_5.py +++ b/tests/smokescreen/test_compartment_5.py @@ -190,17 +190,9 @@ def test_compartment_5(page: Page, smokescreen_properties: dict) -> None: page ).click_record_other_post_investigation_contact_button() - ContactWithPatientPage(page).select_direction_dropdown_option("To patient") - ContactWithPatientPage(page).select_caller_id_dropdown_index_option(1) - ContactWithPatientPage(page).click_calendar_button() - CalendarPicker(page).v1_calender_picker(datetime.today()) - ContactWithPatientPage(page).enter_start_time("11:00") - ContactWithPatientPage(page).enter_end_time("12:00") - ContactWithPatientPage(page).enter_discussion_record_text("Test Automation") - ContactWithPatientPage(page).select_outcome_dropdown_option( - "Post-investigation Appointment Not Required" - ) - ContactWithPatientPage(page).click_save_button() + ContactWithPatientPage( + page + ).record_post_investigation_appointment_not_required() verify_subject_event_status_by_nhs_no( page, nhs_no, "A323 - Post-investigation Appointment NOT Required" diff --git a/utils/dataset_field_util.py b/utils/dataset_field_util.py index 9956f51c..b8068b66 100644 --- a/utils/dataset_field_util.py +++ b/utils/dataset_field_util.py @@ -16,11 +16,9 @@ def get_input_locator_for_field(self, text: str) -> Locator: Returns: Locator: the locator of the input """ - return self.page.locator(f'input:right-of(:text(\"{text}\"))').first + return self.page.locator(f'input:right-of(:text("{text}"))').first - def populate_input_locator_for_field( - self, text: str, value: str - ) -> None: + def populate_input_locator_for_field(self, text: str, value: str) -> None: """ Inputs a value into an input to the right of any element matching the inner selector, at any vertical position. @@ -41,11 +39,9 @@ def get_select_locator_for_field(self, text: str) -> Locator: Returns: Locator: the locator of the input """ - return self.page.locator(f'select:right-of(:text(\"{text}\"))').first + return self.page.locator(f'select:right-of(:text("{text}"))').first - def populate_select_locator_for_field( - self, text: str, option: str - ) -> None: + def populate_select_locator_for_field(self, text: str, option: str) -> None: """ Matches select elements that are to the right of any element matching the inner selector, at any vertical position. @@ -68,7 +64,7 @@ def get_input_locator_for_field_inside_div(self, text: str, div: str) -> Locator Locator: the locator of the input """ container = self.page.locator(f"div#{div}") - return container.locator(f'input:right-of(:text(\"{text}\"))').first + return container.locator(f'input:right-of(:text("{text}"))').first def populate_input_locator_for_field_inside_div( self, text: str, div: str, value: str @@ -96,7 +92,7 @@ def get_select_locator_for_field_inside_div(self, text: str, div: str) -> Locato Locator: the locator of the input """ container = self.page.locator(f"div#{div}") - return container.locator(f'select:right-of(:text(\"{text}\"))').first + return container.locator(f'select:right-of(:text("{text}"))').first def populate_select_locator_for_field_inside_div( self, text: str, div: str, option: str @@ -111,3 +107,19 @@ def populate_select_locator_for_field_inside_div( """ locator = self.get_select_locator_for_field_inside_div(text, div) locator.select_option(option) + + def click_lookup_link_inside_div(self, text: str, div: str) -> None: + """ + Finds and clicks the 'lookup' link (anchor tag) that is in the same row/section + as the provided label text within a given div container. + + Args: + text (str): The label text that appears before the 'lookup' link (e.g., "Pathology Provider") + div (str): The ID of the outer div container to scope the search within + """ + container = self.page.locator(f"div#{div}") + row = container.locator( + f"xpath=//span[contains(@class,'label') and contains(normalize-space(), '{text}')]/ancestor::div[contains(@class,'noTableRow')]" + ) + lookup_link = row.locator("a:text('lookup')").first + lookup_link.click() diff --git a/utils/datasets/investigation_datasets.py b/utils/datasets/investigation_datasets.py new file mode 100644 index 00000000..1c1d8d6d --- /dev/null +++ b/utils/datasets/investigation_datasets.py @@ -0,0 +1,195 @@ +import pandas as pd +from classes.user import User +from classes.subject import Subject +from datetime import datetime +from playwright.sync_api import Page +from pages.base_page import BasePage +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.subject_screening_summary_page import ( + SubjectScreeningSummaryPage, +) +from pages.screening_subject_search.advance_fobt_screening_episode_page import ( + AdvanceFOBTScreeningEpisodePage, +) +from utils.batch_processing import batch_processing +from utils.calendar_picker import CalendarPicker +from utils.oracle.oracle import OracleDB +from utils.oracle.subject_selection_query_builder import SubjectSelectionQueryBuilder +from utils.screening_subject_page_searcher import ( + search_subject_episode_by_nhs_number, +) + + +def get_subject_with_investigation_dataset_ready() -> pd.DataFrame: + """ + This functions obtains 1 subject who is ready to have their investigation dataset complete + """ + criteria = { + "latest episode status": "open", + "latest episode latest investigation dataset": "colonoscopy_new", + "latest episode started": "less than 4 years ago", + } + user = User() + subject = Subject() + + builder = SubjectSelectionQueryBuilder() + + query, bind_vars = builder.build_subject_selection_query( + criteria=criteria, + user=user, + subject=subject, + subjects_to_retrieve=1, + ) + + df = OracleDB().execute_query(query, bind_vars) + return df + + +def get_subject_with_a99_status() -> pd.DataFrame: + """ + This functions obtains 1 subject who has the latest episode status A99 - Suitable for Endoscopic Test + """ + criteria = { + "latest episode has colonoscopy assessment dataset": "yes_complete", + "latest episode has diagnostic test": "no", + "latest event status": "A99", + "latest episode type": "FOBT", + "latest episode started": "less than 4 years ago", + } + user = User() + subject = Subject() + + builder = SubjectSelectionQueryBuilder() + + query, bind_vars = builder.build_subject_selection_query( + criteria=criteria, + user=user, + subject=subject, + subjects_to_retrieve=1, + ) + + df = OracleDB().execute_query(query, bind_vars) + return df + + +def go_from_a99_status_to_a259_status(page: Page, nhs_no: str) -> None: + """ + Takes a subject who has the latest episode status A99 - Suitable for Endoscopic Test + and takes them to A259 - Attended Diagnostic Test. + + Args: + nhs_no (str): The NHS number of the subject. + """ + BasePage(page).go_to_screening_subject_search_page() + search_subject_episode_by_nhs_number(page, nhs_no) + SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() + + AdvanceFOBTScreeningEpisodePage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + + AdvanceFOBTScreeningEpisodePage(page).select_test_type_dropdown_option( + "Colonoscopy" + ) + + AdvanceFOBTScreeningEpisodePage(page).click_invite_for_diagnostic_test_button() + AdvanceFOBTScreeningEpisodePage(page).verify_latest_event_status_value( + "A59 - Invited for Diagnostic Test" + ) + + AdvanceFOBTScreeningEpisodePage(page).click_attend_diagnostic_test_button() + + AttendDiagnosticTestPage(page).select_actual_type_of_test_dropdown_option( + "Colonoscopy" + ) + AttendDiagnosticTestPage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + AttendDiagnosticTestPage(page).click_save_button() + SubjectScreeningSummaryPage(page).verify_latest_event_status_value( + "A259 - Attended Diagnostic Test" + ) + + +def go_from_investigation_dataset_complete_to_a259_status(page: Page) -> None: + """ + Takes a subject who has just had thier investigation dataset compelted to having the event status A259 - Attended Diagnostic Test. + """ + BasePage(page).click_back_button() + BasePage(page).click_back_button() + SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() + AdvanceFOBTScreeningEpisodePage(page).click_enter_diagnostic_test_outcome_button() + DiagnosticTestOutcomePage(page).select_test_outcome_option( + OutcomeOfDiagnosticTest.FAILED_TEST_REFER_ANOTHER + ) + DiagnosticTestOutcomePage(page).click_save_button() + SubjectScreeningSummaryPage(page).verify_latest_event_status_value( + "A315 - Diagnostic Test Outcome Entered" + ) + + # Make post investigation contact > A361 + SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() + AdvanceFOBTScreeningEpisodePage(page).click_other_post_investigation_button() + AdvanceFOBTScreeningEpisodePage(page).verify_latest_event_status_value( + "A361 - Other Post-investigation Contact Required" + ) + + AdvanceFOBTScreeningEpisodePage( + page + ).click_record_other_post_investigation_contact_button() + ContactWithPatientPage(page).record_post_investigation_appointment_not_required() + BasePage(page).click_back_button() + SubjectScreeningSummaryPage(page).verify_latest_event_status_value( + "A318 - Post-investigation Appointment NOT Required - Result Letter Created" + ) + + # Process the A318 letters > A380 + batch_processing( + page, + "A318", + "Result Letters - No Post-investigation Appointment", + "A380 - Failed Diagnostic Test - Refer Another", + ) + + # Another contact to bring the subject back to A99 + SubjectScreeningSummaryPage(page).click_advance_fobt_screening_episode_button() + AdvanceFOBTScreeningEpisodePage(page).click_record_contact_with_patient_button() + ContactWithPatientPage(page).select_direction_dropdown_option("To patient") + ContactWithPatientPage(page).select_caller_id_dropdown_index_option(1) + ContactWithPatientPage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + ContactWithPatientPage(page).enter_start_time("11:00") + ContactWithPatientPage(page).enter_end_time("12:00") + ContactWithPatientPage(page).enter_discussion_record_text("Test Automation") + ContactWithPatientPage(page).select_outcome_dropdown_option( + "Suitable for Endoscopic Test" + ) + ContactWithPatientPage(page).click_save_button() + AdvanceFOBTScreeningEpisodePage(page).verify_latest_event_status_value( + "A99 - Suitable for Endoscopic Test" + ) + + # Invite for 2nd diagnostic test > A59 - check options + AdvanceFOBTScreeningEpisodePage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + AdvanceFOBTScreeningEpisodePage(page).select_test_type_dropdown_option_2( + "Colonoscopy" + ) + AdvanceFOBTScreeningEpisodePage(page).click_invite_for_diagnostic_test_button() + AdvanceFOBTScreeningEpisodePage(page).click_attend_diagnostic_test_button() + AttendDiagnosticTestPage(page).select_actual_type_of_test_dropdown_option( + "Colonoscopy" + ) + AttendDiagnosticTestPage(page).click_calendar_button() + CalendarPicker(page).v1_calender_picker(datetime.today()) + AttendDiagnosticTestPage(page).click_save_button() + SubjectScreeningSummaryPage(page).verify_latest_event_status_value( + "A259 - Attended Diagnostic Test" + ) diff --git a/utils/investigation_dataset.py b/utils/investigation_dataset.py index d677023d..78f9f97a 100644 --- a/utils/investigation_dataset.py +++ b/utils/investigation_dataset.py @@ -326,9 +326,9 @@ def complete_dataset_with_args( endoscopy_information: dict, failure_information: dict, completion_information: Optional[dict] = None, - polyp_1_information: Optional[dict] = None, - polyp_1_intervention: Optional[dict] = None, - polyp_1_histology: Optional[dict] = None, + polyp_information: Optional[list] = None, + polyp_intervention: Optional[list] = None, + polyp_histology: Optional[list] = None, ) -> None: """This method completes the investigation dataset with the provided dictionaries. Args: @@ -337,9 +337,9 @@ def complete_dataset_with_args( endoscopy_information (dict): A dictionary containing the endoscopy information to be filled in the form. failure_information (dict): A dictionary containing the failure information to be filled in the form. completion_information (Optional[dict]): An optional dictionary containing the completion information to be filled in the form. - polyp_1_information (Optional[dict]): An optional dictionary containing the polyp 1 information to be filled in the form. - polyp_1_intervention (Optional[dict]): An optional dictionary containing the polyp 1 intervention to be filled in the form. - polyp_1_histology (Optional[dict]): An optional dictionary containing the polyp 1 histology to be filled in the form. + polyp_information (Optional[list]): An optional list containing the polyp information to be filled in the form. + polyp_intervention (Optional[list]): An optional list containing the polyp intervention to be filled in the form. + polyp_histology (Optional[list]): An optional list containing the polyp histology to be filled in the form. """ logging.info("Completing investigation dataset with the provided dictionaries") # Investigation Dataset @@ -397,17 +397,24 @@ def complete_dataset_with_args( failure_information["failure reasons"], ) - if polyp_1_information: - logging.info("Filling out polyp 1 information") - self.fill_polyp_1_information(polyp_1_information) + if polyp_information: + for polyp_number, polyp_info in enumerate(polyp_information, start=1): + logging.info(f"Filling out polyp {polyp_number} information") + self.fill_polyp_x_information(polyp_info, polyp_number) - if polyp_1_intervention: - logging.info("Filling out polyp 1 intervention") - self.fill_polyp_1_intervention(polyp_1_intervention) + if polyp_intervention: + for polyp_number, polyp_intervention_info in enumerate( + polyp_intervention, start=1 + ): + logging.info(f"Filling out polyp {polyp_number} intervention") + self.fill_polyp_x_intervention(polyp_intervention_info, polyp_number) - if polyp_1_histology: - logging.info("Filling out polyp 1 histology") - self.fill_polyp_1_histology(polyp_1_histology) + if polyp_histology: + for polyp_number, polyp_histology_info in enumerate( + polyp_histology, start=1 + ): + logging.info(f"Filling out polyp {polyp_number} histology") + self.fill_polyp_x_histology(polyp_histology_info, polyp_number) logging.info("Saving the investigation dataset") InvestigationDatasetsPage(self.page).check_dataset_complete_checkbox() @@ -497,35 +504,37 @@ def fill_endoscopy_information(self, endoscopy_information: dict) -> None: "Late outcome", value ) - def fill_polyp_1_information(self, polyp_1_information: dict) -> None: + def fill_polyp_x_information( + self, polyp_information: dict, polyp_number: int + ) -> None: """ - Fills out the polyp 1 information section of the investigation dataset. + Fills out the polyp information section of the investigation dataset for any polyp. Args: polyp_1_information (dict): A dictionary containing the polyp 1 information to be filled in the form. """ # Polyp Information InvestigationDatasetsPage(self.page).click_add_polyp_button() - for key, value in polyp_1_information.items(): + for key, value in polyp_information.items(): match key: case "location": DatasetFieldUtil( self.page ).populate_select_locator_for_field_inside_div( - "Location", "divPolypNumber1Section", value + "Location", f"divPolypNumber{polyp_number}Section", value ) case "classification": DatasetFieldUtil( self.page ).populate_select_locator_for_field_inside_div( - "Classification", "divPolypNumber1Section", value + "Classification", f"divPolypNumber{polyp_number}Section", value ) case "estimate of whole polyp size": DatasetFieldUtil( self.page ).populate_input_locator_for_field_inside_div( self.estimate_whole_polyp_size_string, - "divPolypNumber1Section", + f"divPolypNumber{polyp_number}Section", value, ) case "polyp access": @@ -533,7 +542,7 @@ def fill_polyp_1_information(self, polyp_1_information: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( self.polyp_access_string, - "divPolypNumber1Section", + f"divPolypNumber{polyp_number}Section", value, ) case "secondary piece": @@ -542,7 +551,7 @@ def fill_polyp_1_information(self, polyp_1_information: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Secondary Piece", - "divPolypSecondaryPiece1", + f"divPolypSecondaryPiece{polyp_number}", value, ) case "left in situ": @@ -550,26 +559,30 @@ def fill_polyp_1_information(self, polyp_1_information: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Left in Situ", - "divLeftInSitu1", + f"divLeftInSitu{polyp_number}", value, ) - def fill_polyp_1_intervention(self, polyp_1_intervention: dict) -> None: + def fill_polyp_x_intervention( + self, polyp_intervention: dict, polyp_number: int + ) -> None: """ Fills out the polyp 1 intervention section of the investigation dataset. Args: polyp_1_intervention (dict): A dictionary containing the polyp 1 intervention to be filled in the form. """ - InvestigationDatasetsPage(self.page).click_polyp1_add_intervention_button() - for key, value in polyp_1_intervention.items(): + InvestigationDatasetsPage(self.page).click_polyp_add_intervention_button( + polyp_number + ) + for key, value in polyp_intervention.items(): match key: case "modality": DatasetFieldUtil( self.page ).populate_select_locator_for_field_inside_div( "Modality", - "divPolypTherapy1_1Section", + f"divPolypTherapy{polyp_number}_1Section", value, ) case "device": @@ -577,21 +590,21 @@ def fill_polyp_1_intervention(self, polyp_1_intervention: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Device", - "divPolypTherapy1_1Section", + f"divPolypTherapy{polyp_number}_1Section", value, ) case "excised": DatasetFieldUtil( self.page ).populate_select_locator_for_field_inside_div( - "Excised", "divPolypResected1_1", value + "Excised", f"divPolypResected{polyp_number}_1", value ) case "retrieved": DatasetFieldUtil( self.page ).populate_select_locator_for_field_inside_div( "Retrieved", - "divPolypTherapy1_1Section", + f"divPolypTherapy{polyp_number}_1Section", value, ) case "excision technique": @@ -599,7 +612,7 @@ def fill_polyp_1_intervention(self, polyp_1_intervention: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( self.excision_technique_string, - "divPolypTherapy1_1Section", + f"divPolypTherapy{polyp_number}_1Section", value, ) case "polyp appears fully resected endoscopically": @@ -607,25 +620,25 @@ def fill_polyp_1_intervention(self, polyp_1_intervention: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Polyp appears fully resected endoscopically", - "divPolypAppearsFullyResected1_1", + f"divPolypAppearsFullyResected{polyp_number}_1", value, ) - def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: + def fill_polyp_x_histology(self, polyp_histology: dict, polyp_number: int) -> None: """ - Fills out the polyp 1 histology section of the investigation dataset. + Fills out the polyp histology section of the investigation dataset. Args: - polyp_1_histology (dict): A dictionary containing the polyp 1 histology to be filled in the form. + polyp_histology (dict): A dictionary containing the polyp 1 histology to be filled in the form. """ - for key, value in polyp_1_histology.items(): + for key, value in polyp_histology.items(): match key: case "date of receipt": DatasetFieldUtil( self.page ).populate_input_locator_for_field_inside_div( "Date of Receipt", - "divPolypHistology1_1Details", + f"divPolypHistology{polyp_number}_1Details", value.strftime("%d/%m/%Y"), ) case "date of reporting": @@ -633,23 +646,31 @@ def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: self.page ).populate_input_locator_for_field_inside_div( "Date of Reporting", - "divPolypHistology1_1Details", + f"divPolypHistology{polyp_number}_1Details", value.strftime("%d/%m/%Y"), ) case "pathology provider": - InvestigationDatasetsPage( - self.page - ).select_polyp1_pathology_provider_option_index(value) + DatasetFieldUtil(self.page).click_lookup_link_inside_div( + "Pathology Provider", + f"divPolypHistology{polyp_number}_1Details", + ) + InvestigationDatasetsPage(self.page).select_loopup_option_index( + value + ) case "pathologist": - InvestigationDatasetsPage( - self.page - ).select_polyp1_pathologist_option_index(value) + DatasetFieldUtil(self.page).click_lookup_link_inside_div( + "Pathologist", + f"divPolypHistology{polyp_number}_1Details", + ) + InvestigationDatasetsPage(self.page).select_loopup_option_index( + value + ) case "polyp type": DatasetFieldUtil( self.page ).populate_select_locator_for_field_inside_div( "Polyp Type", - "divPolypHistology1_1Details", + f"divPolypHistology{polyp_number}_1Details", value, ) case "serrated lesion sub type": @@ -657,7 +678,7 @@ def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Polyp Sub Type", - "divSubTypeSerratedLesion1_1", + f"divSubTypeSerratedLesion{polyp_number}_1", value, ) case "adenoma sub type": @@ -665,7 +686,7 @@ def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Polyp Sub Type", - "divSubTypeAdenoma1_1", + f"divSubTypeAdenoma{polyp_number}_1", value, ) case "polyp excision complete": @@ -673,7 +694,7 @@ def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Polyp Excision Complete", - "divExcisionComplete1_1", + f"divExcisionComplete{polyp_number}_1", value, ) case "polyp size": @@ -681,7 +702,7 @@ def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: self.page ).populate_input_locator_for_field_inside_div( "Polyp Size", - "divPolypHistology1_1Details", + f"divPolypHistology{polyp_number}_1Details", value, ) case "polyp dysplasia": @@ -689,7 +710,7 @@ def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Polyp Dysplasia", - "divTumourFindings1_1", + f"divTumourFindings{polyp_number}_1", value, ) case "polyp carcinoma": @@ -697,7 +718,7 @@ def fill_polyp_1_histology(self, polyp_1_histology: dict) -> None: self.page ).populate_select_locator_for_field_inside_div( "Polyp Carcinoma", - "divTumourFindings1_1", + f"divTumourFindings{polyp_number}_1", value, )