Skip to content

Commit 12fc4cb

Browse files
committed
Initial commit - scaffolding done
1 parent 64c6b51 commit 12fc4cb

File tree

4 files changed

+197
-0
lines changed

4 files changed

+197
-0
lines changed

tests/bcss_tests.properties

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,9 @@ episode_closed_date=22/09/2020
2727
# ----------------------------------
2828
daily_invitation_rate=6
2929
weekly_invitation_rate=130
30+
31+
# ----------------------------------
32+
# CREATE SUBJECT REGRESSION TEST DATA
33+
# ----------------------------------
34+
hub_code=23159
35+
region=England
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import pytest
2+
from pages.base_page import BasePage
3+
from utils.user_tools import UserTools
4+
from datetime import timedelta
5+
from pages.call_and_recall.call_and_recall_page import CallAndRecallPage
6+
from pages.call_and_recall.create_a_plan_page import CreateAPlanPage
7+
from pages.call_and_recall.invitations_monitoring_page import InvitationsMonitoringPage
8+
from pages.call_and_recall.invitations_plans_page import InvitationsPlansPage
9+
from utils.subject_utils import (
10+
get_active_invitation_plan,
11+
calculate_subject_shortfall,
12+
create_subject,
13+
)
14+
from utils.date_time_utils import DateTimeUtils
15+
from utils.subject_utils import get_active_invitation_plan
16+
17+
random_offset = DateTimeUtils.random_offset
18+
from playwright.sync_api import Page
19+
20+
@pytest.fixture
21+
def db_connection():
22+
"""
23+
Temporary stub for the database connection fixture.
24+
Replace with actual database session or connection as needed.
25+
"""
26+
return None # Or a mock object if needed
27+
28+
29+
@pytest.fixture(scope="function", autouse=True)
30+
def before_each(page: Page):
31+
"""
32+
Before every test is executed, this fixture logs in to BCSS as a test user and navigates to the call and recall page
33+
"""
34+
# Log in to BCSS
35+
UserTools.user_login(page, "Hub Manager State Registered at BCS01")
36+
37+
# Go to call and recall page
38+
BasePage(page).go_to_call_and_recall_page()
39+
40+
41+
@pytest.mark.wip
42+
@pytest.mark.regression
43+
@pytest.mark.call_and_recall
44+
def test_add_subjects_and_create_invitation_plan(
45+
page: Page, db_connection, general_properties: dict
46+
) -> None:
47+
"""
48+
# Feature: Create Subjects
49+
50+
# Narrative Description:
51+
# As a system administrator,
52+
# I want add new subjects into the system,
53+
# so that I have enough subjects to process during the smoke screen tests
54+
55+
# Scenario: Add new people into the invitation plan, people who will turn 60 in the next 20 months in England
56+
# screening center "Wolverhampton SC" in hub "Midlands and NW Hub" (England)
57+
"""
58+
59+
# Given there were less than "28" subjects to invite per day in the active invitation plan for screening center "23162" hub "23159" in region "England"
60+
sc_code = general_properties["screening_centre_code"]
61+
hub_code = general_properties["hub_code"]
62+
region = general_properties["region"]
63+
daily_target = int(general_properties["daily_invitation_rate"])
64+
65+
active_plan = get_active_invitation_plan(hub_code, sc_code, db_connection)
66+
assert active_plan, "No active invitation plan found"
67+
print(
68+
f"Active Plan → start: {active_plan.start_date}, end: {active_plan.end_date}, "
69+
f"per day: {active_plan.invitations_per_day}, due: {active_plan.invitations_due}"
70+
)
71+
72+
# When sufficient additional subjects are created so that there are at least "28" subjects to invite per day in the active invitation plan for screening center "23162" hub "23159" in region "England"
73+
if active_plan.invitations_per_day < daily_target:
74+
subjects_needed = calculate_subject_shortfall(active_plan, daily_target)
75+
for _ in range(subjects_needed):
76+
birth_date = (
77+
active_plan.start_date
78+
+ timedelta(
79+
DateTimeUtils.random_offset(
80+
active_plan.start_date, active_plan.end_date
81+
)
82+
)
83+
- timedelta(days=365 * 60)
84+
)
85+
create_subject(
86+
birth_date=birth_date,
87+
screening_centre=sc_code,
88+
hub=hub_code,
89+
region=region,
90+
)
91+
92+
# And a new invitation plan is created if there are less than "28" subjects to invite per day in the active invitation plan for screening centre "23162" "BCS001" hub "23159" in region "England"
93+
CallAndRecallPage(page).go_to_planning_and_monitoring_page()
94+
InvitationsMonitoringPage(page).go_to_invitation_plan_page(sc_code)
95+
InvitationsPlansPage(page).go_to_create_a_plan_page()
96+
CreateAPlanPage(page).click_set_all_button()
97+
CreateAPlanPage(page).fill_daily_invitation_rate_field(str(daily_target))
98+
CreateAPlanPage(page).click_update_button()
99+
100+
# Then there are at least "28" subjects to invite per day in the active invitation plan for screening center "23162" hub "23159" in region "England"
101+
expected_weekly_rate = str(daily_target * 5) # Assuming 5-day weeks
102+
CreateAPlanPage(page).verify_weekly_invitation_rate_for_weeks(
103+
1, 50, expected_weekly_rate
104+
)

utils/date_time_utils.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,21 @@ def generate_unique_weekday_date(start_year: int = 2025) -> str:
152152
base_date += timedelta(days=1)
153153

154154
return base_date.strftime("%d/%m/%Y")
155+
156+
@staticmethod
157+
def random_offset(start_date: datetime, end_date: datetime) -> int:
158+
"""
159+
Returns a random integer offset (in days) between the given start and end dates.
160+
161+
This can be used to shift a date within a range, e.g., when generating birthdates
162+
to ensure subject age aligns with eligibility criteria.
163+
164+
Args:
165+
start_date (datetime): The beginning of the valid date range.
166+
end_date (datetime): The end of the valid date range.
167+
168+
Returns:
169+
int: A random offset in days between start_date and end_date.
170+
"""
171+
delta_days = (end_date - start_date).days
172+
return random.randint(0, max(delta_days, 0))

utils/subject_utils.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from datetime import datetime, timedelta
2+
from dataclasses import dataclass
3+
from datetime import datetime
4+
5+
6+
@dataclass
7+
class InvitationPlan:
8+
"""
9+
Represents a structured view of an active invitation plan returned by
10+
`get_active_invitation_plan()` in the subject_utils module.
11+
12+
This dataclass is used primarily in the `test_add_subjects_and_create_invitation_plan`
13+
test case to verify, augment, and operate on the subject pool for a
14+
given screening centre and hub. It provides strongly-typed access to
15+
core scheduling parameters required for dynamic test setup.
16+
17+
Attributes:
18+
start_date (datetime): The start date of the invitation plan.
19+
end_date (datetime): The end date of the invitation plan.
20+
invitations_per_day (int): How many subjects are currently scheduled per day.
21+
invitations_due (int): The total number of subjects planned across the duration.
22+
"""
23+
24+
start_date: datetime
25+
end_date: datetime
26+
invitations_per_day: int
27+
invitations_due: int
28+
29+
30+
def get_active_invitation_plan(hub_code, sc_code, db_connection) -> InvitationPlan:
31+
"""
32+
Retrieves the currently active invitation plan for a given hub and screening centre.
33+
Replace with real DB logic using your ORM or SQL execution layer.
34+
35+
Returns:
36+
InvitationPlan: Structured representation of the current active plan.
37+
"""
38+
return InvitationPlan(
39+
start_date=datetime.now(),
40+
end_date=datetime.now() + timedelta(days=300),
41+
invitations_per_day=20,
42+
invitations_due=4000,
43+
)
44+
45+
46+
def calculate_subject_shortfall(active_plan: InvitationPlan, daily_target: int) -> int:
47+
"""
48+
Based on the active plan and the desired daily rate,
49+
calculate how many new subjects should be added.
50+
"""
51+
invitations_per_day = active_plan.invitations_per_day
52+
invitations_due = active_plan.invitations_due
53+
plan_duration_days = (active_plan.end_date - active_plan.start_date).days
54+
55+
estimated_total = int(
56+
(daily_target / invitations_per_day) * invitations_due * 1.01 - invitations_due
57+
)
58+
return max(0, estimated_total)
59+
60+
61+
def create_subject(birth_date, screening_centre, hub, region):
62+
"""
63+
Creates a new subject in the database.
64+
You’ll likely want to use your existing data generation utilities or raw SQL here.
65+
"""
66+
# TODO: Implement subject creation logic
67+
print(
68+
f"[create_subject] Created subject born {birth_date} for {screening_centre} in {region}"
69+
)

0 commit comments

Comments
 (0)