Skip to content

Commit 6c51163

Browse files
Feature/bcss 20860 selenium to playwright nohistology (#109)
<!-- markdownlint-disable-next-line first-line-heading --> ## Description <!-- Describe your changes in detail. --> Migrating all of the scenarios from the no histology feature files into playwright. ## Context <!-- Why is this change required? What problem does it solve? --> Migrating all of the scenarios from the no histology feature files into playwright. ## Type of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply. --> - [x] Refactoring (non-breaking change) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would change existing functionality) - [ ] Bug fix (non-breaking change which fixes an issue) ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [x] I am familiar with the [contributing guidelines](https://github.com/nhs-england-tools/playwright-python-blueprint/blob/main/CONTRIBUTING.md) - [x] I have followed the code style of the project - [x] I have added tests to cover my changes (where appropriate) - [x] I have updated the documentation accordingly - [ ] This PR is a result of pair or mob programming --- ## Sensitive Information Declaration To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including [PII (Personal Identifiable Information) / PID (Personal Identifiable Data)](https://digital.nhs.uk/data-and-information/keeping-data-safe-and-benefitting-the-public) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter. - [x] I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes.
1 parent 83e54a7 commit 6c51163

File tree

8 files changed

+2743
-1004
lines changed

8 files changed

+2743
-1004
lines changed

pages/base_page.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,16 +250,23 @@ def safe_accept_dialog(self, locator: Locator) -> None:
250250
except Exception as e:
251251
logging.error(f"Click failed: {e}")
252252

253-
def assert_dialog_text(self, expected_text: str) -> None:
253+
def assert_dialog_text(self, expected_text: str, accept: bool = False) -> None:
254254
"""
255255
Asserts that a dialog appears and contains the expected text.
256256
If no dialog appears, logs an error.
257257
Args:
258258
expected_text (str): The text that should be present in the dialog.
259+
accept (bool): Set to True if you want to accept the dialog, by deafult is is set to False.
259260
"""
260261
self._dialog_assertion_error = None
261262

262-
def handle_dialog(dialog: Dialog):
263+
def handle_dialog(dialog: Dialog, accept: bool = False):
264+
"""
265+
Handles the dialog and asserts that the dialog contains the expected text.
266+
Args:
267+
dialog (Dialog): the playwright dialog object
268+
accept (bool): Set to True if you want to accept the dialog, by deafult is is set to False.
269+
"""
263270
logging.info(f"Dialog appeared with message: {dialog.message}")
264271
actual_text = dialog.message
265272
try:
@@ -268,9 +275,12 @@ def handle_dialog(dialog: Dialog):
268275
), f"Expected '{expected_text}', but got '{actual_text}'"
269276
except AssertionError as e:
270277
self._dialog_assertion_error = e
271-
dialog.dismiss() # Dismiss dialog
278+
if accept:
279+
dialog.accept()
280+
else:
281+
dialog.dismiss() # Dismiss dialog
272282

273-
self.page.once("dialog", handle_dialog)
283+
self.page.once("dialog", lambda dialog: handle_dialog(dialog, accept))
274284

275285
def go_to_log_in_page(self) -> None:
276286
"""Click on the Log in button to navigate to the login page."""

pages/datasets/investigation_dataset_page.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,29 @@ def click_polyp_add_intervention_button(self, polyp_number: int) -> None:
483483
)
484484
)
485485

486+
def populate_select_by_id(
487+
self, field_base: str, polyp_number: int, option: str
488+
) -> None:
489+
"""
490+
Populates a <select> element using a predictable ID pattern based on field name and polyp number.
491+
492+
This method is useful when label-based selectors (e.g., using `right-of(:text(...))`) are unreliable
493+
due to ambiguous or repeated text labels on the page.
494+
495+
Args:
496+
field_base (str): The base name of the field (e.g., "POLYP_PATHOLOGY_LOST").
497+
polyp_number (int): The polyp index (e.g., 1 for the first polyp).
498+
option (str): The value to be selected from the dropdown.
499+
500+
Example:
501+
populate_select_by_id("POLYP_PATHOLOGY_LOST", 1, YesNoOptions.YES)
502+
# Selects 'Yes' in <select id="UI_POLYP_PATHOLOGY_LOST1_1">
503+
"""
504+
field_id = f"UI_{field_base.upper()}{polyp_number}_1"
505+
locator = self.page.locator(f"select#{field_id}")
506+
locator.wait_for(state="visible")
507+
locator.select_option(option)
508+
486509

487510
class SiteLookupOptions(StrEnum):
488511
"""Enum for site lookup options"""
@@ -685,6 +708,12 @@ class PolypInterventionModalityOptions(StrEnum):
685708
POLYPECTOMY = "17189~Resection"
686709
EMR = "17193~Resection"
687710
ESD = "17520~Resection"
711+
BIOPSY = "17190~Suspicion of cancer"
712+
CHROMOSCOPY = "17198"
713+
HAEMOSTATIC_TECHNIQUE = "17194"
714+
SUBMUCOSAL_LIFT = "203005"
715+
TATTOOING = "17192"
716+
TISSUE_DESTRUCTION = "17191"
688717

689718

690719
class PolypInterventionDeviceOptions(StrEnum):
@@ -695,6 +724,9 @@ class PolypInterventionDeviceOptions(StrEnum):
695724
COLD_SNARE = "17072"
696725
COLD_BIOPSY = "17073~En-bloc"
697726
ENDOSCOPIC_KNIFE = "17531"
727+
HOT_BIOPSY_FORCEPS = "17071~En-bloc"
728+
ARGON_BEAM = "17077"
729+
LASER = "17078"
698730

699731

700732
class PolypInterventionExcisionTechniqueOptions(StrEnum):
@@ -768,3 +800,27 @@ class YesNoUncertainOptions(StrEnum):
768800
YES = "17058"
769801
NO = "17059"
770802
UNCERTAIN = "17105"
803+
804+
805+
class ReasonPathologyLostOptions(StrEnum):
806+
"""Enum for reason pathology lost options"""
807+
808+
LOST_IN_TRANSIT = "200561~~204337"
809+
DESTROYED_DURING_PROCESSING = "200562~~204337"
810+
811+
812+
class PolypInterventionSuccessOptions(StrEnum):
813+
"""Enum for polyp intervention success options"""
814+
815+
SUCCESSFUL = "17200"
816+
UNSUCCESSFUL = "17201"
817+
818+
819+
class PolypReasonLeftInSituOptions(StrEnum):
820+
"""Enum for reasons a polyp was left in situ"""
821+
822+
POLYP_TYPE = "200556"
823+
REQUIRES_ANOTHER_PROCEDURE = "200557"
824+
REQUIRES_SURGICAL_RESECTION = "200558"
825+
CANNOT_FIND_POLYP_ON_WITHDRAWAL = "200559"
826+
CLINICAL_DECISION_NOT_TO_EXCISE = "203082"

0 commit comments

Comments
 (0)