From 5338294e9aa9887be5c0d70a8be278d9845a211d Mon Sep 17 00:00:00 2001 From: Namitha-Prabhu Date: Fri, 3 Jul 2026 09:02:16 +0100 Subject: [PATCH] fix --- helpers/ui/nhs_app_journey.py | 144 ++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 59 deletions(-) diff --git a/helpers/ui/nhs_app_journey.py b/helpers/ui/nhs_app_journey.py index eb75a2e..135dc4f 100644 --- a/helpers/ui/nhs_app_journey.py +++ b/helpers/ui/nhs_app_journey.py @@ -1,5 +1,4 @@ from pathlib import Path -from time import sleep from install_playwright import install from playwright.sync_api import expect, sync_playwright, TimeoutError as PlaywrightTimeoutError import re @@ -24,70 +23,97 @@ def nhs_app_login_and_view_message(ods_name=None, personalisation=None): page.set_default_timeout(30000) expect.set_options(timeout=30000) - page.goto("https://www-onboardingaos.nhsapp.service.nhs.uk/login") - logger.info("Accessed NHS App Onboarding AOS") - - logger.info("Navigator WebAuthn available: %s", page.evaluate("() => !!window.PublicKeyCredential")) - - expect(page.get_by_role("heading", name="Use NHS App services", exact=True)).to_be_visible() - page.get_by_role("button", name="Continue").click() - logger.info(f"Continuing on to username page - {page.url}") - - expect(page.get_by_role("heading", name="Log in ")).to_be_visible() - - page.get_by_role("textbox", name="Email address", exact=True).fill(os.environ['NHS_APP_USERNAME']) - - page.get_by_role("textbox", name="Password", exact=True).fill(os.environ['NHS_APP_PASSWORD']) - password = page.locator("#password-input") - expect(password).to_have_value(os.environ["NHS_APP_PASSWORD"]) - - page.screenshot(path=str(debug_dir / "password.png"), full_page=True) - logger.info(f"Entered username and password - {page.url}") - - continue_btn = page.locator("#continue-button button") - continue_btn.wait_for(state="visible") - continue_btn.click() - - logger.info(f"Submitted login form - {page.url}") - page.screenshot(path=str(debug_dir / "login_after_password.png"), full_page=True) - - page.get_by_text("Enter the security code", exact=True) - - logger.info(f"Current URL after OTP page check: {page.url}") - - if(page.url.endswith("/passkey-user-login-failed")): - logger.warning("Login failed, likely due to WebAuthn issue. Please check the debug screenshots for details.") - page.goto("https://access.aos.signin.nhs.uk/enter-mobile-code") - - page.get_by_text("Enter the security code", exact=True) - - page.get_by_label("Security code", exact=True).fill(os.environ['NHS_APP_OTP']) - page.get_by_role("button", name="Continue").click() - logger.info("Entered OTP") - page.screenshot(path=str(debug_dir / "before_trust_device.png"), full_page=True) - - - try: - page.wait_for_url("**/trust-device**", timeout=30000) - except PlaywrightTimeoutError: - logger.info(f"Trust-device page not shown; continuing. Current URL: {page.url}") + def run_login_attempt(attempt_index): + page.goto("https://www-onboardingaos.nhsapp.service.nhs.uk/login") + logger.info("Accessed NHS App Onboarding AOS (attempt %s)", attempt_index) + + logger.info("Navigator WebAuthn available: %s", page.evaluate("() => !!window.PublicKeyCredential")) - if "/trust-device" in page.url: - page.locator('input[name="remember"][value="yes"]').check() + expect(page.get_by_role("heading", name="Use NHS App services", exact=True)).to_be_visible() page.get_by_role("button", name="Continue").click() - logger.info("Trusted device option selected and continued") - + logger.info(f"Continuing on to username page - {page.url}") + + expect(page.get_by_role("heading", name="Log in ")).to_be_visible() + + page.get_by_role("textbox", name="Email address", exact=True).fill(os.environ['NHS_APP_USERNAME']) + + page.get_by_role("textbox", name="Password", exact=True).fill(os.environ['NHS_APP_PASSWORD']) + password = page.locator("#password-input") + expect(password).to_have_value(os.environ["NHS_APP_PASSWORD"]) + + page.screenshot(path=str(debug_dir / f"password_attempt_{attempt_index}.png"), full_page=True) + logger.info(f"Entered username and password - {page.url}") + + continue_btn = page.locator("#continue-button button") + continue_btn.wait_for(state="visible") + continue_btn.click() + + logger.info(f"Submitted login form - {page.url}") + page.screenshot(path=str(debug_dir / f"login_after_password_attempt_{attempt_index}.png"), full_page=True) + + page.get_by_text("Enter the security code", exact=True) + + logger.info(f"Current URL after OTP page check: {page.url}") + + if(page.url.endswith("/passkey-user-login-failed")): + logger.warning("Login failed, likely due to WebAuthn issue. Please check the debug screenshots for details.") + page.goto("https://access.aos.signin.nhs.uk/enter-mobile-code") - page.locator(".loading-spinner").wait_for(state="hidden") - # page.wait_for_url('**/patient/**') - page.wait_for_load_state("networkidle") + page.get_by_text("Enter the security code", exact=True) - if(page.url.endswith("/patient/whats-new")): + page.get_by_label("Security code", exact=True).fill(os.environ['NHS_APP_OTP']) page.get_by_role("button", name="Continue").click() - - page.get_by_role("link", name="Messages").click() + logger.info("Entered OTP") + page.screenshot(path=str(debug_dir / f"before_trust_device_attempt_{attempt_index}.png"), full_page=True) + + try: + page.wait_for_url("**/trust-device**", timeout=30000) + except PlaywrightTimeoutError: + logger.info(f"Trust-device page not shown; continuing. Current URL: {page.url}") + + if "/trust-device" in page.url: + page.locator('input[name="remember"][value="yes"]').check() + page.get_by_role("button", name="Continue").click() + logger.info("Trusted device option selected and continued") + + page.wait_for_load_state("networkidle") + + if page.url.endswith("/error"): + logger.warning("Reached /error after OTP on attempt %s; restarting login flow", attempt_index) + page.screenshot(path=str(debug_dir / f"after_otp_error_attempt_{attempt_index}.png"), full_page=True) + return False + + try: + page.wait_for_url(re.compile(r".*/patient(?:/.*)?$"), timeout=45000) + return True + except PlaywrightTimeoutError: + page.screenshot(path=str(debug_dir / f"post_otp_unexpected_page_attempt_{attempt_index}.png"), full_page=True) + logger.warning( + "Did not reach patient page after OTP on attempt %s. Current URL: %s", + attempt_index, + page.url, + ) + return False + + max_attempts = 2 + for attempt in range(1, max_attempts + 1): + if run_login_attempt(attempt): + break + if attempt == max_attempts: + raise AssertionError( + f"Login did not reach an NHS App patient page after {max_attempts} attempts. Current URL: {page.url}" + ) + logger.info("Retrying NHS App login flow from onboarding step") + + if page.url.endswith("/patient/whats-new"): + page.get_by_role("button", name="Continue").click() + + try: + page.get_by_role("link", name="Messages", exact=True).click(timeout=45000) + except PlaywrightTimeoutError: + # Fallback for minor NHS App UI text variations. + page.get_by_role("link", name=re.compile(r"Messages", re.IGNORECASE)).first.click(timeout=45000) - link_text = re.compile(r"You have \d+ unread messages") logger.info("Navigated to message hub") expect(page.get_by_role("heading", name="Messages")).to_be_visible()