Skip to content

Commit 7200a4e

Browse files
adrianoaru-nhsAndyg79
authored andcommitted
Adding new util and fixture to setup appointments (#122)
<!-- markdownlint-disable-next-line first-line-heading --> ## Description <!-- Describe your changes in detail. --> Adding a new utility and pytest fixture to be able to setup SSP appointments for any test. This fixture will only run once per day to reduce repetition and will setup appointments for all available practitioners. This also ensures that the parameters around these appointments are set correctly to allow more appointment slots. ## Context <!-- Why is this change required? What problem does it solve? --> Allows tests that require the same setup to call a common pytest fixture. Also ensures that the same setup is not run multiple times a day which is not needed. ## 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 de63e84 commit 7200a4e

File tree

4 files changed

+203
-66
lines changed

4 files changed

+203
-66
lines changed

conftest.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
from utils.load_properties_file import PropertiesFile
1515
from _pytest.config.argparsing import Parser
1616
from _pytest.fixtures import FixtureRequest
17+
from playwright.sync_api import Page
18+
from utils.oracle.oracle_specific_functions import (
19+
set_org_parameter_value,
20+
check_parameter,
21+
)
22+
from utils.last_test_run import has_test_run_today
23+
from utils.appointments import setup_appointments
1724

1825
# Environment Variable Handling
1926

@@ -106,3 +113,39 @@ def subjects_to_run_for(request: FixtureRequest) -> int:
106113
int: The number of subjects specified via the CLI or default (10).
107114
"""
108115
return int(request.config.getoption("--subjects-to-run-for")) # type: ignore
116+
117+
118+
@pytest.fixture(scope="function")
119+
def setup_org_and_appointments(
120+
page: Page, request: FixtureRequest, general_properties: dict
121+
) -> None:
122+
"""
123+
Ensures required org parameters and appointments are set up.
124+
Only runs once per day per environment, regardless of which test calls it.
125+
126+
This fixture is designed to be used in tests that require a specific setup of the organisation and appointments.
127+
128+
Example usage:
129+
130+
@pytest.mark.usefixtures("setup_org_and_appointments")
131+
def test_my_function(page: Page):
132+
# Your test code here
133+
134+
def test_my_function(page: Page, setup_org_and_appointments):
135+
# Your test code here
136+
"""
137+
org_id = general_properties["eng_screening_centre_id"]
138+
param_12_set_correctly = check_parameter(12, org_id, "10")
139+
param_28_set_correctly = check_parameter(28, org_id, "07:00")
140+
param_29_set_correctly = check_parameter(29, org_id, "20:00")
141+
if not param_12_set_correctly:
142+
set_org_parameter_value(12, "10", org_id)
143+
if not param_28_set_correctly:
144+
set_org_parameter_value(28, "07:00", org_id)
145+
if not param_29_set_correctly:
146+
set_org_parameter_value(29, "20:00", org_id)
147+
148+
base_url = request.config.getoption("--base-url")
149+
fixture_name = "setup_org_and_appointments"
150+
if not has_test_run_today(fixture_name, base_url): # type: ignore
151+
setup_appointments(page, 0, max=True)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Utility Guide: Appointments Utility
2+
3+
This guide explains the purpose and usage of the `setup_appointments` utility found in [`utils/appointments.py`](../../utils/appointments.py).
4+
It is designed to automate the setup of practitioner appointments at a screening centre using Playwright.
5+
6+
---
7+
8+
## Table of Contents
9+
10+
- [Utility Guide: Appointments Utility](#utility-guide-appointments-utility)
11+
- [Table of Contents](#table-of-contents)
12+
- [Overview](#overview)
13+
- [Required Arguments](#required-arguments)
14+
- [How It Works](#how-it-works)
15+
- [Example Usage](#example-usage)
16+
- [Best Practices](#best-practices)
17+
18+
---
19+
20+
## Overview
21+
22+
The `setup_appointments` function automates the process of logging in as a Screening Centre Manager, navigating through the appointments workflow, and creating appointment slots for multiple practitioners at a specified screening centre.
23+
It is useful for preparing test data and ensuring practitioners have available appointment slots for test scenarios.
24+
25+
---
26+
27+
## Required Arguments
28+
29+
```python
30+
def setup_appointments(page: Page, no_of_practitioners: int, max: bool = False) -> None:
31+
```
32+
33+
- `page` (`Page`): The Playwright page object.
34+
- `no_of_practitioners` (`int`): Number of practitioners to set up appointments for.
35+
- `max` (`bool`, optional): If `True`, sets up appointments for all practitioners at the site. Defaults to `False`.
36+
37+
---
38+
39+
## How It Works
40+
41+
1. **Login**
42+
43+
Logs in as "Screening Centre Manager at BCS001" using the `UserTools` utility.
44+
45+
2. **Determine Practitioner Count**
46+
47+
If `max=True`, navigates to the practitioner availability page, selects the site, and counts the number of practitioners available.
48+
49+
3. **Appointment Setup Loop**
50+
51+
For each practitioner:
52+
- Navigates to the practitioner appointments workflow.
53+
- Selects the site and practitioner.
54+
- Opens the calendar and selects today's date.
55+
- Sets start and end times, calculates slots, and saves the appointment for one week.
56+
57+
4. **Logout**
58+
59+
Logs out after all appointments are set.
60+
61+
---
62+
63+
## Example Usage
64+
65+
```python
66+
from playwright.sync_api import Page
67+
from utils.appointments import setup_appointments
68+
69+
def test_setup_practitioner_appointments(page: Page):
70+
# Set up appointments for the first 5 practitioners
71+
setup_appointments(page, no_of_practitioners=5)
72+
73+
def test_setup_all_practitioner_appointments(page: Page):
74+
# Set up appointments for all practitioners at the site
75+
setup_appointments(page, no_of_practitioners=0, max=True)
76+
```
77+
78+
---
79+
80+
## Best Practices
81+
82+
- Use this utility in test setup steps to ensure practitioners have available slots before running appointment-related tests.
83+
- Use `max=True` for bulk setup, or specify `no_of_practitioners` for targeted setup.
84+
85+
---

tests/regression/subject/episodes/datasets/investigation/endoscopy/polypcategories/test_setup.py

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from datetime import datetime, timedelta
22
import pandas as pd
33
import pytest
4-
from _pytest.fixtures import FixtureRequest
54
import logging
65
from playwright.sync_api import Page
76
from classes.subject import Subject
@@ -23,15 +22,6 @@
2322
from pages.screening_practitioner_appointments.book_appointment_page import (
2423
BookAppointmentPage,
2524
)
26-
from pages.screening_practitioner_appointments.practitioner_availability_page import (
27-
PractitionerAvailabilityPage,
28-
)
29-
from pages.screening_practitioner_appointments.screening_practitioner_appointments_page import (
30-
ScreeningPractitionerAppointmentsPage,
31-
)
32-
from pages.screening_practitioner_appointments.set_availability_page import (
33-
SetAvailabilityPage,
34-
)
3525
from pages.screening_subject_search.advance_fobt_screening_episode_page import (
3626
AdvanceFOBTScreeningEpisodePage,
3727
)
@@ -44,13 +34,10 @@
4434
from utils.batch_processing import batch_processing
4535
from utils.calendar_picker import CalendarPicker
4636
from utils.fit_kit import FitKitGeneration
47-
from utils.last_test_run import has_test_run_today
4837
from utils.oracle.oracle import OracleDB
4938
from utils.oracle.oracle_specific_functions import (
5039
update_kit_service_management_entity,
5140
execute_fit_kit_stored_procedures,
52-
set_org_parameter_value,
53-
check_parameter,
5441
)
5542
from utils.oracle.subject_selection_query_builder import SubjectSelectionQueryBuilder
5643
from utils.screening_subject_page_searcher import (
@@ -61,30 +48,7 @@
6148
from utils.datasets.investigation_datasets import go_from_a99_status_to_a259_status
6249

6350

64-
@pytest.fixture(scope="function", autouse=True)
65-
def before_each(page: Page, request: FixtureRequest) -> None:
66-
"""
67-
Checks that the required organization parameters are set correctly before each test.
68-
If not, it sets them to the expected values.
69-
Also sets up appointments if the test has not been run today.
70-
"""
71-
param_12_set_correctly = check_parameter(12, "23162", "10")
72-
param_28_set_correctly = check_parameter(28, "23162", "07:00")
73-
param_29_set_correctly = check_parameter(29, "23162", "20:00")
74-
if not param_12_set_correctly:
75-
set_org_parameter_value(12, "10", "23162")
76-
if not param_28_set_correctly:
77-
set_org_parameter_value(28, "07:00", "23162")
78-
if not param_29_set_correctly:
79-
set_org_parameter_value(29, "20:00", "23162")
80-
81-
base_url = request.config.getoption("--base-url")
82-
if not has_test_run_today(
83-
"subject/episodes/datasets/investigation/endoscopy/polypcategories/test_setup", base_url # type: ignore
84-
):
85-
setup_appointments(page)
86-
87-
51+
@pytest.mark.usefixtures("setup_org_and_appointments")
8852
@pytest.mark.vpn_required
8953
def test_setup_subjects_as_a99(page: Page, subjects_to_run_for: int) -> None:
9054
"""
@@ -115,6 +79,7 @@ def test_setup_subjects_as_a99(page: Page, subjects_to_run_for: int) -> None:
11579
LogoutPage(page).log_out()
11680

11781

82+
@pytest.mark.usefixtures("setup_org_and_appointments")
11883
@pytest.mark.vpn_required
11984
def test_setup_subjects_as_a259(page: Page, subjects_to_run_for: int) -> None:
12085
"""
@@ -173,35 +138,6 @@ def test_setup_subjects_as_a259(page: Page, subjects_to_run_for: int) -> None:
173138
LogoutPage(page).log_out()
174139

175140

176-
def setup_appointments(page: Page) -> None:
177-
"""
178-
Set up appointments for multiple practitioners at a screening centre.
179-
This function logs in as a Screening Centre Manager, sets availability for
180-
practitioners, and creates appointments for the next 10 practitioners.
181-
"""
182-
UserTools.user_login(page, "Screening Centre Manager at BCS001")
183-
for index in range(10):
184-
BasePage(page).go_to_screening_practitioner_appointments_page()
185-
ScreeningPractitionerAppointmentsPage(page).go_to_set_availability_page()
186-
SetAvailabilityPage(page).go_to_practitioner_availability_page()
187-
PractitionerAvailabilityPage(page).select_site_dropdown_option(
188-
"THE ROYAL HOSPITAL (WOLVERHAMPTON)"
189-
)
190-
PractitionerAvailabilityPage(
191-
page
192-
).select_practitioner_dropdown_option_from_index(index + 1)
193-
PractitionerAvailabilityPage(page).click_calendar_button()
194-
CalendarPicker(page).select_day(datetime.today())
195-
PractitionerAvailabilityPage(page).click_show_button()
196-
PractitionerAvailabilityPage(page).enter_start_time("07:00")
197-
PractitionerAvailabilityPage(page).enter_end_time("20:00")
198-
PractitionerAvailabilityPage(page).click_calculate_slots_button()
199-
PractitionerAvailabilityPage(page).enter_number_of_weeks("1")
200-
PractitionerAvailabilityPage(page).click_save_button()
201-
BasePage(page).click_main_menu_link()
202-
LogoutPage(page).log_out()
203-
204-
205141
def setup_a99_status(page: Page, df: pd.DataFrame) -> pd.DataFrame:
206142
"""
207143
Set up subjects to have status A99 - Suitable for Endoscopic Test.

utils/appointments.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import logging
2+
from playwright.sync_api import Page
3+
from pages.base_page import BasePage
4+
from pages.logout.log_out_page import LogoutPage
5+
from pages.screening_practitioner_appointments.practitioner_availability_page import (
6+
PractitionerAvailabilityPage,
7+
)
8+
from pages.screening_practitioner_appointments.screening_practitioner_appointments_page import (
9+
ScreeningPractitionerAppointmentsPage,
10+
)
11+
from pages.screening_practitioner_appointments.set_availability_page import (
12+
SetAvailabilityPage,
13+
)
14+
from utils.calendar_picker import CalendarPicker
15+
from utils.user_tools import UserTools
16+
from datetime import datetime
17+
18+
19+
def setup_appointments(page: Page, no_of_practitioners: int, max: bool = False) -> None:
20+
"""
21+
Set up appointments for multiple practitioners at a screening centre.
22+
This function logs in as a Screening Centre Manager, sets availability for
23+
practitioners, and creates appointments for the next 10 practitioners.
24+
25+
Args:
26+
no_of_practitioners (int): The number of practitioners to set up appointments for.
27+
max (bool): If True, sets up appointments for all practitioners. Defaults to False.
28+
"""
29+
UserTools.user_login(page, "Screening Centre Manager at BCS001")
30+
31+
if max:
32+
go_to_appointments_page_and_select_site(page)
33+
total_practitioners = (
34+
PractitionerAvailabilityPage(page)
35+
.screening_practitioner_dropdown.locator("option")
36+
.count()
37+
)
38+
no_of_practitioners = total_practitioners - 1 # Exclude the first option
39+
BasePage(page).click_main_menu_link()
40+
41+
logging.info(f"Setting up appointments for {no_of_practitioners} practitioners")
42+
for index in range(no_of_practitioners):
43+
logging.info(f"Setting up appointments for practitioner {index + 1}")
44+
go_to_appointments_page_and_select_site(page)
45+
PractitionerAvailabilityPage(
46+
page
47+
).select_practitioner_dropdown_option_from_index(index + 1)
48+
PractitionerAvailabilityPage(page).click_calendar_button()
49+
CalendarPicker(page).select_day(datetime.today())
50+
PractitionerAvailabilityPage(page).click_show_button()
51+
PractitionerAvailabilityPage(page).enter_start_time("07:00")
52+
PractitionerAvailabilityPage(page).enter_end_time("20:00")
53+
PractitionerAvailabilityPage(page).click_calculate_slots_button()
54+
PractitionerAvailabilityPage(page).enter_number_of_weeks("1")
55+
PractitionerAvailabilityPage(page).click_save_button()
56+
logging.info(f"Appointments set for practitioner {index + 1} at BCS001")
57+
BasePage(page).click_main_menu_link()
58+
LogoutPage(page).log_out()
59+
60+
61+
def go_to_appointments_page_and_select_site(page: Page) -> None:
62+
"""
63+
Navigate to the Screening Practitioner Appointments page.
64+
65+
Args:
66+
page (Page): The Playwright page object.
67+
"""
68+
BasePage(page).go_to_screening_practitioner_appointments_page()
69+
ScreeningPractitionerAppointmentsPage(page).go_to_set_availability_page()
70+
SetAvailabilityPage(page).go_to_practitioner_availability_page()
71+
PractitionerAvailabilityPage(page).select_site_dropdown_option(
72+
"THE ROYAL HOSPITAL (WOLVERHAMPTON)"
73+
)

0 commit comments

Comments
 (0)