diff --git a/.gitleaksignore b/.gitleaksignore index baf75d325..758f21c5c 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -6,3 +6,4 @@ bc0e944855d5b2ec35de75c79b6215d56b18ed99:requirements.txt:ipv4:5 648c714b8fd9d6a9bb0102649b1b9a04171dd6b5:requirements.txt:ipv4:5 148da0f8b77440ea672e1fe856056900a9454b2c:requirements.txt:ipv4:5 571ab217807cd146bbb1ac6d55648b6acbe778f4:requirements.txt:ipv4:5 +040cfd7c3e8ab821a7f36c2e28cfbf9df82a2630:requirements.txt:ipv4:5 diff --git a/conftest.py b/conftest.py index 56b5187d0..e05d01d07 100644 --- a/conftest.py +++ b/conftest.py @@ -42,6 +42,7 @@ pytest.mark.addvaccine = pytest.mark.mark(addvaccine=True) pytest.mark.addbatches = pytest.mark.mark(addbatches=True) pytest.mark.reports = pytest.mark.mark(reports=True) +pytest.mark.usermanagement = pytest.mark.mark(usermanagement=True) @pytest.fixture(scope='function', autouse=True) def report_browser_version(request): @@ -486,6 +487,11 @@ def step_search_for_patient(shared_data): nhs_number = shared_data["nhs_number"] click_find_a_patient_and_search_with_nhs_number(nhs_number) +@given(parse("I see the patient's address {address} and gender {gender}")) +def step_save_address_and_gender_to_shared_data(shared_data, address, gender): + shared_data["address"] = address + shared_data["gender"] = gender + @given(parse("I open the patient record by clicking on patient {name}")) @then(parse("I open the patient record by clicking on patient {name}")) def step_search_for_patient(shared_data, name): @@ -497,7 +503,10 @@ def step_search_for_patient(shared_data, name): @when(parse("I click choose vaccine button and choose the {chosen_vaccine}, {batch_number} with {batch_expiry_date} and click continue")) def step_choose_vaccine_and_vaccine_type(shared_data, chosen_vaccine, batch_number, batch_expiry_date): time.sleep(3) - assert check_vaccine_history_not_available_label_element_exists() == False + if shared_data["nhs_number"] != "9727840361": + assert check_vaccine_history_not_available_label_element_exists() == False + else: + assert check_vaccine_history_not_available_label_element_exists() == True attach_screenshot("checked_vaccine_history_not_available_label_element_exists") immunisation_history_records_count_before_vaccination = click_on_patient_search_result_and_click_choose_vaccine(shared_data['patient_name'], chosen_vaccine) shared_data["immunisation_history_records_count_before_vaccination"] = immunisation_history_records_count_before_vaccination @@ -591,6 +600,8 @@ def step_see_patient_details_on_check_and_confirm_screen(shared_data, name, dob, attach_screenshot("check_and_confirm_screen_before_assertion") assert get_patient_name_value() == shared_data["patient_name"] assert get_patient_address_value() == address + shared_data["gender"] = get_patient_gender_value() + shared_data["address"] = address assert get_patient_vaccination_dose_amount_value() == shared_data["dose_amount"] assert get_patient_vaccinated_chosen_vaccine_value() == shared_data["chosen_vaccine"] assert get_patient_vaccinated_chosen_vaccine_product_value() == shared_data["chosen_vaccine_type"] diff --git a/features/reports.feature b/features/reports.feature index 9cc8e742b..33005d17b 100644 --- a/features/reports.feature +++ b/features/reports.feature @@ -183,6 +183,7 @@ Scenario Outline: User can download the report And I login to RAVS and set vaccinator details with and and get patient details for with option and choose to vaccinate with vaccine details as , with And I search for a patient with the NHS number in the find a patient screen And I open the patient record by clicking on patient + And I see the patient's address
and gender When I click choose vaccine button and choose the , with and click continue And I assess the patient's with the details and date as and click continue to record consent screen button And I record with the details and click continue to vaccinate button @@ -201,5 +202,28 @@ Scenario Outline: User can download the report Then the report is downloaded successfully and contains the vaccine record for Examples: - | index | nhs_number | site | care_model | eligibility | assess_date | consent | vaccination | vaccination_date | name | dob | address | chosen_vaccine | batch_number | batch_expiry_date | - | 4 | 9437541817 | KINGSTON HOUSE | Outreach event | yes | today | yes | no | today | FLORINDA DUNNER | 27/3/1957 | 32 HOLLAND ROAD, MANCHESTER, M8 4NP | Flu | AUTOMATION-SJ1 | 19/10/2026 | + | index | nhs_number | site | care_model | eligibility | assess_date | consent | vaccination | vaccination_date | name | dob | address | chosen_vaccine | batch_number | batch_expiry_date | gender | + | 4 | 9437541817 | KINGSTON HOUSE | Outreach event | yes | today | yes | no | today | FLORINDA DUNNER | 27/3/1957 | 32 HOLLAND ROAD, MANCHESTER, M8 4NP | Flu | AUTOMATION-SJ1 | 19/10/2026 | female | + + + Scenario Outline: User should be able to filter vaccine event data before creating a report + Given I am logged into the RAVS app + When I click the reports navigation link + And I click the create report button + And I click the radio button and click Continue + And I select the vaccine type and click continue + And I select the site and click continue + And I select the data to filter and click continue + And I click Confirm and create report button in the check and confirm page + And I click download report button + Then the report is downloaded successfully and it should not contain the data that was selected for filtering + + Examples: + |vaccineType | site | day | data | + | COVID-19 | Albert House | Last 31 days (includes today) | Patients | + | Flu | Albert House | Last 31 days (includes today) | Staff | + | Pertussis | Albert House | Last 7 days (includes today) | Site or delivery team | + | Respiratory syncytial virus (RSV) | Albert House | Last 14 days (includes today) | Assessment and consent | + | COVID-19 | Albert House | Last 31 days (includes today) | Vaccination | + + diff --git a/features/user_management.feature b/features/user_management.feature new file mode 100644 index 000000000..a4663d2c7 --- /dev/null +++ b/features/user_management.feature @@ -0,0 +1,7 @@ +Feature: User Management + +@usermanagement +Scenario: Manage users page is displayed + Given I am logged into the RAVS app + When I click the manage users navigation link + Then the manage users page should be displayed diff --git a/helpers/playwrightHelper.py b/helpers/playwrightHelper.py index dd70b4fff..654912d15 100644 --- a/helpers/playwrightHelper.py +++ b/helpers/playwrightHelper.py @@ -294,6 +294,12 @@ def find_element_and_perform_action(self, locator_or_element, action, inputValue print("Checkbox checked successfully.") elif element.is_checked(): print("Checkbox is already checked.") + elif action.lower() == "uncheck": + if element.is_visible() and element.is_checked(): + element.uncheck() + print("Checkbox un-checked successfully.") + elif not element.is_checked(): + print("Checkbox is already un-checked.") elif action.lower() == "select_option": if element.is_visible(): if isinstance(inputValue, int): diff --git a/pages/check_and_confirm_vaccinated_record_page.py b/pages/check_and_confirm_vaccinated_record_page.py index c1416e181..f21d0fbc9 100644 --- a/pages/check_and_confirm_vaccinated_record_page.py +++ b/pages/check_and_confirm_vaccinated_record_page.py @@ -63,6 +63,9 @@ def click_cancel_confirm_details_button(): def get_patient_name_value(): return find_element_and_perform_action(PATIENT_NAME_LABEL_ELEMENT, "get_text") +def get_patient_gender_value(): + return find_element_and_perform_action(PATIENT_GENDER_LABEL_ELEMENT, "get_text") + def get_patient_dob_value(): return find_element_and_perform_action(PATIENT_DOB_LABEL_ELEMENT, "get_text") diff --git a/pages/manage_users_home_page.py b/pages/manage_users_home_page.py new file mode 100644 index 000000000..f48e40fab --- /dev/null +++ b/pages/manage_users_home_page.py @@ -0,0 +1,14 @@ +from init_helpers import * + +PAGE_LOADING_ELEMENT = ("text", "Loading...Loading...") +ADD_USER_BUTTON = ("role", "button", "Add user") + +def check_add_user_button_exists(): + wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) + wait_for_element_to_appear(ADD_USER_BUTTON) + return check_element_exists(ADD_USER_BUTTON) + +def click_add_user_button(): + wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) + wait_for_element_to_appear(ADD_USER_BUTTON) + find_element_and_perform_action(ADD_USER_BUTTON, "click") diff --git a/pages/patient_details_page.py b/pages/patient_details_page.py index ce8268039..b6a8c88b8 100644 --- a/pages/patient_details_page.py +++ b/pages/patient_details_page.py @@ -28,6 +28,9 @@ VACCINATION_HISTORY_NOT_AVAILABLE = ("role", "heading", "No vaccination history available") def check_vaccine_history_not_available_label_element_exists(): + time.sleep(2) + wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) + time.sleep(3) wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) wait_for_element_to_appear(CHOOSE_VACCINE_BUTTON) return check_element_exists(VACCINATION_HISTORY_NOT_AVAILABLE) @@ -50,6 +53,7 @@ def check_pertussis_history_element_exists(): def get_count_of_immunisation_history_records(chosen_vaccine): count = 0 + time.sleep(3) wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) time.sleep(3) wait_for_element_to_appear(CHOOSE_VACCINE_BUTTON) @@ -139,7 +143,7 @@ def click_delete_history_button(vaccine, index): find_element_and_perform_action(element, "click") def click_delete_history_link(vaccine): - element = (f"//h3[contains(text(), '{vaccine}')]/following-sibling::div//a/span[text()='Delete']") + element = (f"//h2[contains(text(), '{vaccine}')]/following-sibling::div//a/span[text()='Delete']") find_element_and_perform_action(element, "click") def click_edit_history_button(vaccine, index): diff --git a/pages/reports_data_selection_page.py b/pages/reports_data_selection_page.py index 8e47a0a48..0dcc41e7b 100644 --- a/pages/reports_data_selection_page.py +++ b/pages/reports_data_selection_page.py @@ -5,6 +5,12 @@ SELECT_DATA_FOR_REPORT_ERROR_MESSAGE_TEXT = ("text", "Select data for report") CONTINUE_TO_REPORTS_CHECK_AND_CONFIRM_BUTTON = ("role", "button", "Continue") BACK_TO_SELECT_SITE_BUTTON = ("role", "button", "Back") +PATIENTS_CHECKBOX_ELEMENT = ("label", "Patients") +STAFF_CHECKBOX_ELEMENT = ("label", "Staff") +SITE_DELIVERY_TEAM_CHECKBOX_ELEMENT = ("label", "Site or delivery team") +ASSESSMENT_AND_CONSENT_CHECKBOX_ELEMENT = ("label", "Assessment and consent") +VACCINATION_CHECKBOX_ELEMENT = ("label", "Vaccination") + def check_reports_data_check_box_checked(data): wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) @@ -12,18 +18,32 @@ def check_reports_data_check_box_checked(data): wait_for_element_to_appear(element) return check_element_checked(element) +def uncheck_all_data_filters(): + wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) + find_element_and_perform_action(PATIENTS_CHECKBOX_ELEMENT, "uncheck") + find_element_and_perform_action(STAFF_CHECKBOX_ELEMENT, "uncheck") + find_element_and_perform_action(SITE_DELIVERY_TEAM_CHECKBOX_ELEMENT, "uncheck") + find_element_and_perform_action(ASSESSMENT_AND_CONSENT_CHECKBOX_ELEMENT, "uncheck") + find_element_and_perform_action(VACCINATION_CHECKBOX_ELEMENT, "uncheck") + def check_reports_data_check_box_exists(data): wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) element = ("label", data) wait_for_element_to_appear(element) return check_element_exists(element) -def click_reports_data_check_box(data): +def check_reports_data_check_box(data): wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) element = ("label", data) wait_for_element_to_appear(element) find_element_and_perform_action(element, "check") +def uncheck_reports_data_check_box(data): + wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) + element = ("label", data) + wait_for_element_to_appear(element) + find_element_and_perform_action(element, "uncheck") + def check_reports_select_site_error_message_text_exists(): wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) wait_for_element_to_appear(SELECT_DATA_FOR_REPORT_ERROR_MESSAGE_TEXT) @@ -42,7 +62,7 @@ def check_continue_to_reports_check_and_confirm_button_exists(): wait_for_element_to_appear(CONTINUE_TO_REPORTS_CHECK_AND_CONFIRM_BUTTON) return check_element_exists(CONTINUE_TO_REPORTS_CHECK_AND_CONFIRM_BUTTON) -def click_continue_to_reports_select_data_button(): +def click_continue_to_reports_check_and_confirm_button(): wait_for_element_to_disappear(PAGE_LOADING_ELEMENT) wait_for_element_to_appear(CONTINUE_TO_REPORTS_CHECK_AND_CONFIRM_BUTTON) find_element_and_perform_action(CONTINUE_TO_REPORTS_CHECK_AND_CONFIRM_BUTTON, "click") diff --git a/test_data/record_vaccine_data_all_yes_9470040228.json b/test_data/record_vaccine_data_all_yes_9470040228.json deleted file mode 100644 index d39096362..000000000 --- a/test_data/record_vaccine_data_all_yes_9470040228.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "vaccinator_organisation": "NHS ARDEN AND GREATER EAST MIDLANDS COMMISSIONING SUPPORT UNIT", - "vaccinator_site": "NEELIMA HOUSE", - "vaccinator_care_model": "Vaccination Centre", - "nhs_number": "9470040228", - "chosen_vaccine": "COVID-19", - "chosen_vaccine_type": "Comirnaty 30 Omicron XBB.1.5", - "eligible_decision": "Yes", - "eligibility_type": "Residents in care homes", - "eligibility_assessing_clinician": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "eligibility_assessment_date": "today", - "eligibility_assessment_outcome": "Give vaccine", - "eligibility_assessment_no_vaccine_given_reason": "Give vaccine", - "assessment_comments": "", - "consent_decision": "Yes", - "consent_given_by": "Patient (informed consent)", - "name_of_person_consenting": "Patient's parent/guardian", - "relationship_to_patient": "Parent", - "consent_clinician_details": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "no_consent_reason": "Having elsewhere / Had Vaccination", - "vaccinated_decision": "Yes", - "vaccination_date": "today", - "vaccine_type2": "Comirnaty Original/Omicron BA.4-5", - "vaccination_route": "Left upper arm", - "batch_number": "SDYY2-12", - "batch_number_to_select": "SDYY2-12 - 19/10/2025", - "batch_expiry_date": "19/10/2025", - "dose_amount": "0.3", - "legal_mechanism": "National Protocol (NP)", - "vaccinator": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "no_vaccination_reason": "Not appropriate to vaccinate today, patient advised to rebook", - "vaccination_comments": "", - "patient_name": "HERBERT HAAG", - "date_of_birth": "14/12/1922", - "address": "10 COASTAL ROAD, HEST BANK, LANCASTER, LA2 6HN" -} diff --git a/test_data/record_vaccine_data_all_yes_9470057589.json b/test_data/record_vaccine_data_all_yes_9470057589.json deleted file mode 100644 index 3d9027f82..000000000 --- a/test_data/record_vaccine_data_all_yes_9470057589.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "vaccinator_organisation": "NHS ARDEN AND GREATER EAST MIDLANDS COMMISSIONING SUPPORT UNIT", - "vaccinator_site": "NEELIMA HOUSE", - "vaccinator_care_model": "Vaccination Centre", - "nhs_number": "9470057589", - "chosen_vaccine": "COVID-19", - "chosen_vaccine_type": "Comirnaty 30 Omicron XBB.1.5", - "eligible_decision": "Yes", - "eligibility_type": "Staff working in care homes", - "eligibility_assessing_clinician": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "eligibility_assessment_date": "today-1", - "eligibility_assessment_outcome": "Give vaccine", - "eligibility_assessment_no_vaccine_given_reason": "Give vaccine", - "assessment_comments": "Automated vaccine_data_all_yes - Patient is eligible and consented, assessment comments", - "consent_decision": "Yes", - "consent_given_by": "Person with parental responsibility", - "name_of_person_consenting": "Patient's parent/guardian", - "relationship_to_patient": "Parent", - "consent_clinician_details": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "no_consent_reason": "Having elsewhere / Had Vaccination", - "vaccinated_decision": "Yes", - "vaccination_date": "today-1", - "vaccine_type2": "Comirnaty 30 Omicron XBB.1.5", - "vaccination_route": "Left upper arm", - "batch_number": "sb12345-12", - "batch_number_to_select": "sb12345-12 - 19/2/2026", - "batch_expiry_date": "19/2/2026", - "dose_amount": "0.3", - "legal_mechanism": "Patient Group Directions (PGD)", - "vaccinator": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "no_vaccination_reason": "Not appropriate to vaccinate today, patient advised to rebook", - "vaccination_comments": "", - "patient_name": "ROGER SEABORNE", - "date_of_birth": "13/12/1922", - "address": "10 ANN STREET, DALTON-IN-FURNESS, CUMBRIA, LA15 8BG" -} diff --git a/test_data/record_vaccine_data_all_yes_9472710255.json b/test_data/record_vaccine_data_all_yes_9472710255.json deleted file mode 100644 index 96d8d5577..000000000 --- a/test_data/record_vaccine_data_all_yes_9472710255.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "vaccinator_organisation": "NHS ARDEN AND GREATER EAST MIDLANDS COMMISSIONING SUPPORT UNIT", - "vaccinator_site": "NEELIMA HOUSE", - "vaccinator_care_model": "Vaccination Centre", - "nhs_number": "9470057589", - "chosen_vaccine": "COVID-19", - "chosen_vaccine_type": "Spikevax XBB.1.5", - "eligible_decision": "Yes", - "eligibility_type": "Healthcare workers", - "staff_role": "Qualified Nurse / Midwife", - "eligibility_assessing_clinician": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "eligibility_assessment_date": "today-1", - "eligibility_assessment_outcome": "Give vaccine", - "eligibility_assessment_no_vaccine_given_reason": "Give vaccine", - "assessment_comments": "Automated vaccine_data_all_yes - Patient is eligible and consented, assessment comments", - "consent_decision": "Yes", - "consent_given_by": "Person with parental responsibility", - "name_of_person_consenting": "Patient's parent/guardian", - "relationship_to_patient": "Parent", - "consent_clinician_details": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "no_consent_reason": "Having elsewhere / Had Vaccination", - "vaccinated_decision": "Yes", - "vaccination_date": "today-1", - "vaccine_type2": "Spikevax XBB.1.5", - "vaccination_route": "Left upper arm", - "batch_number": "sb12345-12", - "batch_number_to_select": "sb12345-12 - 19/2/2026", - "batch_expiry_date": "19/2/2026", - "dose_amount": "0.3", - "legal_mechanism": "Patient Group Directions (PGD)", - "vaccinator": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "no_vaccination_reason": "Not appropriate to vaccinate today, patient advised to rebook", - "vaccination_comments": "", - "patient_name": "ROGER SEABORNE", - "date_of_birth": "13/12/1922", - "address": "10 ANN STREET, DALTON-IN-FURNESS, CUMBRIA, LA15 8BG" -} diff --git a/test_data/record_vaccine_data_all_yes_9693632109.json b/test_data/record_vaccine_data_all_yes_9693632109.json deleted file mode 100644 index 3c9836634..000000000 --- a/test_data/record_vaccine_data_all_yes_9693632109.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "vaccinator_organisation": "NHS ARDEN AND GREATER EAST MIDLANDS COMMISSIONING SUPPORT UNIT", - "vaccinator_site": "NEELIMA HOUSE", - "vaccinator_care_model": "Vaccination Centre", - "nhs_number": "9693632109", - "chosen_vaccine": "COVID-19", - "chosen_vaccine_type": "Comirnaty 30 Omicron XBB.1.5", - "eligible_decision": "Yes", - "eligibility_type": "Staff working in care homes", - "staff_role": "Qualified Nurse / Midwife", - "eligibility_assessing_clinician": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "eligibility_assessment_date": "today", - "eligibility_assessment_outcome": "Give vaccine", - "eligibility_assessment_no_vaccine_given_reason": "Give vaccine", - "assessment_comments": "Automated vaccine_data_all_yes - Patient is eligible and consented, assessment comments", - "consent_decision": "Yes", - "consent_given_by": "Patient (informed consent)", - "name_of_person_consenting": "Patient's parent/guardian", - "relationship_to_patient": "Parent", - "consent_clinician_details": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "no_consent_reason": "Having elsewhere / Had Vaccination", - "vaccinated_decision": "Yes", - "vaccination_date": "today", - "vaccine_type2": "Comirnaty Original/Omicron BA.4-5", - "vaccination_route": "Left upper arm", - "batch_number": "SDYY2-12", - "batch_number_to_select": "SDYY2-12 - 19/10/2025", - "batch_expiry_date": "19/10/2025", - "dose_amount": "0.3", - "legal_mechanism": "National Protocol (NP)", - "vaccinator": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "no_vaccination_reason": "Not appropriate to vaccinate today, patient advised to rebook", - "vaccination_comments": "Automated vaccine_data_all_yes - Patient is eligible and consented and vaccinated, vaccination comments", - "patient_name": "Bill GARTON", - "date_of_birth": "23/6/1946", - "address": "1 MOUNT AVENUE, BARTON-UPON-HUMBER, S HUMBERSIDE, DN18 5DW" -} diff --git a/test_data/record_vaccine_data_not_eligible_consented_vaccinated.json b/test_data/record_vaccine_data_not_eligible_consented_vaccinated.json deleted file mode 100644 index 440fe3537..000000000 --- a/test_data/record_vaccine_data_not_eligible_consented_vaccinated.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "vaccinator_organisation": "NHS ARDEN AND GREATER EAST MIDLANDS COMMISSIONING SUPPORT UNIT", - "vaccinator_site": "NEELIMA HOUSE", - "vaccinator_care_model": "Vaccination Centre", - "nhs_number": "9693632109", - "chosen_vaccine": "COVID-19", - "chosen_vaccine_type": "Comirnaty 30 Omicron XBB.1.5", - "eligible_decision": "No", - "eligibility_type": "Staff working in care homes", - "eligibility_assessing_clinician": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "eligibility_assessment_date": "today", - "eligibility_assessment_outcome": "Give vaccine", - "eligibility_assessment_no_vaccine_given_reason": "Give vaccine", - "assessment_comments": "Automated vaccine_data_not_eligible_consented_vaccinated - Patient is not eligible and consented, assessment comments", - "consent_decision": "Yes", - "consent_given_by": "Patient (informed consent)", - "name_of_person_consenting": "Patient's parent/guardian", - "relationship_to_patient": "Parent", - "consent_clinician_details": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "no_consent_reason": "Having elsewhere / Had Vaccination", - "vaccinated_decision": "Yes", - "vaccination_date": "today", - "vaccine_type2": "Comirnaty Original/Omicron BA.4-5", - "vaccination_route": "Left upper arm", - "batch_number": "SDYY2-12", - "batch_number_to_select": "SDYY2-12 - 19/10/2025", - "batch_expiry_date": "19/10/2025", - "dose_amount": "0.3", - "legal_mechanism": "National Protocol (NP)", - "vaccinator": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "no_vaccination_reason": "Not appropriate to vaccinate today, patient advised to rebook", - "vaccination_comments": "Automated record_vaccine_data_not_eligible_consented_vaccinated - Patient is not eligible and consented and vaccinated, vaccination comments", - "patient_name": "Bill GARTON", - "date_of_birth": "23/6/1946", - "address": "1 MOUNT AVENUE, BARTON-UPON-HUMBER, S HUMBERSIDE, DN18 5DW" -} diff --git a/test_data/record_vaccine_data_not_eligible_not_consented.json b/test_data/record_vaccine_data_not_eligible_not_consented.json deleted file mode 100644 index 8ab39c48b..000000000 --- a/test_data/record_vaccine_data_not_eligible_not_consented.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "vaccinator_organisation": "NHS ARDEN AND GREATER EAST MIDLANDS COMMISSIONING SUPPORT UNIT", - "vaccinator_site": "NEELIMA HOUSE", - "vaccinator_care_model": "Vaccination Centre", - "nhs_number": "9693632109", - "chosen_vaccine": "COVID-19", - "chosen_vaccine_type": "Comirnaty 30 Omicron XBB.1.5", - "eligible_decision": "No", - "eligibility_type": "Staff working in care homes", - "eligibility_assessing_clinician": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "eligibility_assessment_date": "today", - "eligibility_assessment_outcome": "Give vaccine", - "eligibility_assessment_no_vaccine_given_reason": "Give vaccine", - "assessment_comments": "Automated vaccine_data_not_eligible_not_consented - Patient is not eligible and consented, assessment comments", - "consent_decision": "No", - "consent_given_by": "Patient (informed consent)", - "name_of_person_consenting": "Patient's parent/guardian", - "relationship_to_patient": "Parent", - "consent_clinician_details": "Frazer Brindley - NMC (Nursing and Midwifery Council), NMC005", - "no_consent_reason": "Having elsewhere / Had Vaccination", - "vaccinated_decision": "No", - "vaccination_date": "today", - "vaccine_type2": "Comirnaty Original/Omicron BA.4-5", - "vaccination_route": "Left upper arm", - "batch_number": "SDYY2-12", - "batch_number_to_select": "SDYY2-12 - 19/10/2025", - "batch_expiry_date": "19/10/2025", - "dose_amount": "0.3", - "legal_mechanism": "National Protocol (NP)", - "vaccinator": "Neelima Guntupalli - GPhC (General Pharmaceutical Council), 008008", - "no_vaccination_reason": "Not appropriate to vaccinate today, patient advised to rebook", - "vaccination_comments": "Automated vaccine_data_not_eligible_not_consented Patient is National eligible and consented and vaccinated, vaccination comments", - "patient_name": "Bill GARTON", - "date_of_birth": "23/6/1946", - "address": "1 MOUNT AVENUE, BARTON-UPON-HUMBER, S HUMBERSIDE, DN18 5DW" -} diff --git a/tests/test_logout_steps.py b/tests/test_logout_steps.py index 855c6bd62..efef4a461 100644 --- a/tests/test_logout_steps.py +++ b/tests/test_logout_steps.py @@ -27,6 +27,7 @@ def click_logout(): if config["browser"] == "mobile": if check_navbar_toggle_exists(): click_navbar_toggler() + attach_screenshot("before_clicking_logged_out") click_logout_button() @then('the user should be logged out successfully') diff --git a/tests/test_reports_steps.py b/tests/test_reports_steps.py index e0be2d63d..2e6a33ce9 100644 --- a/tests/test_reports_steps.py +++ b/tests/test_reports_steps.py @@ -23,49 +23,41 @@ scenarios(f'{features_directory}/reports.feature') logger = logging.getLogger() -logger.setLevel(logging.DEBUG) # Or any other level like INFO, WARNING, etc. +logger.setLevel(logging.DEBUG) -# Create a rotating file handler to log to tox.log log_handler = RotatingFileHandler('tox.log', maxBytes=1024*1024, backupCount=3) # Log rotation (optional) log_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) -# Add the handler to the logger logger.addHandler(log_handler) def validate_report_headers(file_path, expected_headers): try: with open(file_path, mode="r", newline="", encoding="utf-8") as file: reader = csv.reader(file) - headers = next(reader) + actual_headers = next(reader) - # Check headers - if headers == expected_headers: - logger.info("Headers are valid!") - logger.info(headers) - return True, headers - else: - logger.info("Headers are invalid!") - logger.info("Expected Headers:") - logger.info(expected_headers) - logger.info("Found Headers:") - logger.info(headers) + missing_headers = [h for h in expected_headers if h not in actual_headers] + extra_headers = [h for h in actual_headers if h not in expected_headers] - # Find missing or extra headers - missing_headers = [h for h in expected_headers if h not in headers] - extra_headers = [h for h in headers if h not in expected_headers] + is_valid = not missing_headers and not extra_headers + if is_valid: + logger.info("Headers are valid!") + logger.debug(f"Headers: {actual_headers}") + else: + logger.error("Headers are invalid!") + logger.debug(f"Expected Headers: {expected_headers}") + logger.debug(f"Found Headers: {actual_headers}") if missing_headers: - logger.info("Missing Headers:") - logger.info(missing_headers) + logger.error(f"Missing Headers: {missing_headers}") if extra_headers: - logger.info("Extra Headers:") - logger.info(extra_headers) + logger.error(f"Extra Headers: {extra_headers}") - return False, headers + return is_valid, missing_headers, extra_headers except Exception as e: - logger.error(f"An error occurred while validating headers: {e}") - return False, None + logger.exception(f"An error occurred while validating headers: {e}") + return False, [], [] def validate_value_in_header(file_path, header, value): try: @@ -292,7 +284,16 @@ def the_report_is_downloaded_successfully(shared_data): "DateEntered", "UserEnteringData", "VaccinationComments", "AssessingClinician", "VaccinatingClinician", "ConsentingClinician" ] - is_valid, _ = validate_report_headers(shared_data['report_download_path'], expected_headers) + is_valid, missing_headers, extra_headers = validate_report_headers(shared_data['report_download_path'], expected_headers) + + if not is_valid: + error_message = "Report headers are invalid." + if missing_headers: + error_message += f" Missing headers: {missing_headers}." + if extra_headers: + error_message += f" Extra headers: {extra_headers}." + raise ValueError(error_message) + assert is_valid, "Report headers are invalid. See logs for details." @then(parse("the report is downloaded successfully and contains the vaccine record for {nhs_number}")) @@ -310,7 +311,15 @@ def the_report_is_downloaded_successfully(shared_data, nhs_number): "DateEntered", "UserEnteringData", "VaccinationComments", "AssessingClinician", "VaccinatingClinician", "ConsentingClinician" ] - is_valid, _ = validate_report_headers(shared_data['report_download_path'], expected_headers) + is_valid, missing_headers, extra_headers = validate_report_headers(shared_data['report_download_path'], expected_headers) + + if not is_valid: + error_message = "Report headers are invalid." + if missing_headers: + error_message += f" Missing headers: {missing_headers}." + if extra_headers: + error_message += f" Extra headers: {extra_headers}." + raise ValueError(error_message) assert is_valid, "Report headers are invalid. See logs for details." vaccination_date = shared_data.get("vaccination_date") @@ -407,6 +416,14 @@ def the_report_is_downloaded_successfully(shared_data, nhs_number): f"Mismatch in 'PatientName': expected '{shared_data['patient_name']}' but found '{last_row['PatientName']}'." ) + assert last_row["Address"].lower() in shared_data["address"].lower(), ( + f"Mismatch in 'Address': expected '{shared_data['address']}' but found '{last_row['Address']}'." + ) + + assert last_row["Gender"].lower() == shared_data["gender"].lower(), ( + f"Mismatch in 'Gender': expected '{shared_data['gender']}' but found '{last_row['Gender']}'." + ) + assert last_row["AssessmentDate"] == shared_data["eligibility_assessment_date"], ( f"Mismatch in 'AssessmentDate': expected '{shared_data['eligibility_assessment_date']}' but found '{last_row['AssessmentDate']}'." ) @@ -518,7 +535,14 @@ def the_report_is_downloaded_successfully(shared_data): "DateEntered", "UserEnteringData", "VaccinationComments", "AssessingClinician", "VaccinatingClinician", "ConsentingClinician" ] - is_valid, _ = validate_report_headers(shared_data['report_download_path'], expected_headers) + is_valid, missing_headers, extra_headers = validate_report_headers(shared_data['report_download_path'], expected_headers) + if not is_valid: + error_message = "Report headers are invalid." + if missing_headers: + error_message += f" Missing headers: {missing_headers}." + if extra_headers: + error_message += f" Extra headers: {extra_headers}." + raise ValueError(error_message) assert is_valid, "Report headers are invalid. See logs for details." @then("the choose data page should be displayed") @@ -527,3 +551,89 @@ def the_choose_data_page_should_be_displayed(): attach_screenshot("check_choose_data_pages_reports_exists") logging.info("check_choose_data_pages_reports_exists") +@when("I uncheck all filters on the data page") +def i_uncheck_all_data_filters(): + uncheck_all_data_filters() + attach_screenshot("unchecked_all_data_filters") + logging.info("unchecked_all_data_filters") + +@when(parse("I select the data {data} to filter and click continue")) +def select_data_to_filter_and_click_continue(shared_data, data): + uncheck_reports_data_check_box(data) + attach_screenshot("clicked_reports_data_check_box" + data) + logging.info("clicked_reports_data_check_box" + data) + shared_data['data_to_filter'] = data + click_continue_to_reports_check_and_confirm_button() + +@then(parse("the report is downloaded successfully and it should not contain the data that was selected for filtering")) +def the_report_is_downloaded_successfully(shared_data): + report_path = shared_data['report_download_path'] + data_to_filter = shared_data['data_to_filter'] + + # Assert that the report exists + assert os.path.exists(report_path), f"Downloaded file not found: {report_path}" + attach_screenshot("check_report_downloaded") + logger.info(f"check_report_downloaded_to_{report_path}") + + # Define expected headers based on the data to filter + headers_map = { + "Assessment and consent": [ + "NhsNumber", "PatientName", "Gender", "DateOfBirth", "Address", "Postcode", + "SiteName", "SiteODS", "OrganisationName", "OrganisationODS", "CareModel", + # "Vaccinated", "NoVaccinationReason", + "VaccinationDate", "Vaccine", "VaccineProduct", + "DoseAmount", "VaccineRoute", "PrescribingMethod", "BatchNumber", "BatchExpiryDate", + "AuditType", "DateEntered", "UserEnteringData", "VaccinationComments", + "AssessingClinician", "VaccinatingClinician", "ConsentingClinician" + ], + "Patients": [ + "SiteName", "SiteODS", "OrganisationName", "OrganisationODS", "CareModel", + "Vaccinated", "NoVaccinationReason", "AssessmentDate", "Consented", "ConsentType", + "ConsentingPersonName", "ConsentingPersonRelationship", "EligibilityType", "StaffType", + "AssessmentComments", "VaccinationDate", "Vaccine", "VaccineProduct", "DoseAmount", + "VaccineRoute", "PrescribingMethod", "BatchNumber", "BatchExpiryDate", "AuditType", + "DateEntered", "UserEnteringData", "VaccinationComments", "AssessingClinician", + "VaccinatingClinician", "ConsentingClinician" + ], + "Site or delivery team": [ + "NhsNumber", "PatientName", "Gender", "DateOfBirth", "Address", "Postcode", + "Vaccinated", "NoVaccinationReason", "AssessmentDate", "Consented", "ConsentType", + "ConsentingPersonName", "ConsentingPersonRelationship", "EligibilityType", "StaffType", + "AssessmentComments", "VaccinationDate", "Vaccine", "VaccineProduct", "DoseAmount", + "VaccineRoute", "PrescribingMethod", "BatchNumber", "BatchExpiryDate", "AuditType", + "DateEntered", "UserEnteringData", "VaccinationComments", "AssessingClinician", + "VaccinatingClinician", "ConsentingClinician" + ], + "Staff": [ + "NhsNumber", "PatientName", "Gender", "DateOfBirth", "Address", "Postcode", + "SiteName", "SiteODS", "OrganisationName", "OrganisationODS", "CareModel", + "Vaccinated", "NoVaccinationReason", "AssessmentDate", "Consented", "ConsentType", + "ConsentingPersonName", "ConsentingPersonRelationship", "EligibilityType", "StaffType", + "AssessmentComments", "VaccinationDate", "Vaccine", "VaccineProduct", "DoseAmount", + "VaccineRoute", "PrescribingMethod", "BatchNumber", "BatchExpiryDate", "AuditType", + "DateEntered", "UserEnteringData", "VaccinationComments" + ], + "Vaccination": [ + "NhsNumber", "PatientName", "Gender", "DateOfBirth", "Address", "Postcode", + "SiteName", "SiteODS", "OrganisationName", "OrganisationODS", "CareModel", + "Vaccinated", "NoVaccinationReason", "AssessmentDate", "Consented", "ConsentType", + "ConsentingPersonName", "ConsentingPersonRelationship", "EligibilityType", "StaffType", + "AssessmentComments", + #"AuditType", "DateEntered", "UserEnteringData", "VaccinationComments", + "AssessingClinician", "VaccinatingClinician", "ConsentingClinician" + ] + } + + expected_headers = headers_map.get(data_to_filter) + if not expected_headers: + raise ValueError(f"Unexpected data_to_filter value: {data_to_filter}") + + is_valid, missing_headers, extra_headers = validate_report_headers(report_path, expected_headers) + + if not is_valid: + error_message = "Report headers are invalid." + if missing_headers: + error_message += f" Missing headers: {missing_headers}." + if extra_headers: + error_message += f" Extra headers: {extra_headers}." + raise ValueError(error_message) diff --git a/tests/test_user_management_steps.py b/tests/test_user_management_steps.py new file mode 100644 index 000000000..a744b024f --- /dev/null +++ b/tests/test_user_management_steps.py @@ -0,0 +1,57 @@ +from asyncio import sleep +import csv +from logging.handlers import RotatingFileHandler +import secrets +import string +from pytest_bdd import given, when, then, scenarios, scenario +from pytest_bdd.parsers import parse +from pages.login_page import * +from pages.home_page import * +from pages.nhs_signin_page import * +from pages.manage_users_home_page import * +import logging +from init_helpers import * +from conftest import * + +features_directory = get_working_directory() + "features" + +scenarios(f'{features_directory}/user_management.feature') + +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + +log_handler = RotatingFileHandler('tox.log', maxBytes=1024*1024, backupCount=3) # Log rotation (optional) +log_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) + +# Add the handler to the logger +logger.addHandler(log_handler) + +@pytest.fixture(scope="session", autouse=True) +def setup_logging(): + # You can add logging setup here if needed + logger.info("Logging setup complete") + yield + logger.info("Test session complete") + +@pytest.fixture(scope='function') +def shared_data(): + data = {} + yield data + data.clear() + +@pytest.mark.usermanagement +@given("I am logged into the RAVS app") +def logged_into_ravs_app(navigate_and_login): + pass + +@when("I click the manage users navigation link") +def I_click_manage_users_nav_link(): + click_manage_users_nav_link() + attach_screenshot("manage_users_navigation_link_clicked") + logging.info("logged_in_and_manage_users_navigation_link_clicked") + +@then("the manage users page should be displayed") +def the_manage_users_page_should_be_displayed(): + assert check_add_user_button_exists() == True + attach_screenshot("manage_users_page_loads_and_add_user_button_is_visible") + logging.info("reports_page_loads_and_create_report_button_is_visible")