""" Verify UI Team's Implementation of Missing Attributes This script verifies that all 5 missing attributes are actually present in the DOM after the UI team's implementation. """ import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.parent)) from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from pages.login_page import LoginPage from pages.profile_editor_page import ProfileEditorPage from pages.domain_assessment_page import DomainAssessmentPage from pages.assessments_page import AssessmentsPage from pages.domains_page import DomainsPage from utils.password_tracker import password_tracker from config.config import TEST_USERNAME, TEST_NEW_PASSWORD, BASE_URL import time def verify_toast_attribute(driver, test_id, description): """Verify toast attribute is present in DOM""" print(f"\nšŸ” Verifying: {description}") print(f" Looking for: [data-testid='{test_id}']") try: # Wait for toast to appear and data-testid to be added (UI team's helper takes max 1 second) # Check multiple times as toast helpers add attribute programmatically max_attempts = 10 for attempt in range(max_attempts): time.sleep(0.3) # Wait a bit for attribute to be added # Check if attribute exists in DOM elements = driver.find_elements(By.CSS_SELECTOR, f"[data-testid='{test_id}']") if elements: visible_elements = [e for e in elements if e.is_displayed()] if visible_elements: print(f" āœ… FOUND: {len(visible_elements)} visible element(s) (attempt {attempt + 1})") # Also check if it has role="status" (should have both) for elem in visible_elements: role = elem.get_attribute("role") if role == "status": print(f" āœ… Also has role='status' (correct)") return True else: if attempt < max_attempts - 1: continue # Retry print(f" āš ļø Found but not visible: {len(elements)} element(s)") return False # Also check page source as fallback if attempt == max_attempts - 1: page_source = driver.page_source if test_id in page_source: print(f" āš ļø Found in page source but not as DOM element") return False print(f" āŒ NOT FOUND in DOM after {max_attempts} attempts") return False except Exception as e: print(f" āŒ ERROR: {e}") return False def verify_static_attribute(driver, test_id, description): """Verify static attribute is present in DOM""" print(f"\nšŸ” Verifying: {description}") print(f" Looking for: [data-testid='{test_id}']") try: element = WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.CSS_SELECTOR, f"[data-testid='{test_id}']")) ) if element.is_displayed(): print(f" āœ… FOUND and VISIBLE") return True else: print(f" āš ļø Found but not visible") return False except Exception as e: print(f" āŒ NOT FOUND: {e}") return False def main(): print("=" * 70) print("UI TEAM IMPLEMENTATION VERIFICATION") print("=" * 70) options = Options() options.add_argument('--headless=new') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') driver = webdriver.Chrome(options=options) driver.implicitly_wait(5) results = {} try: # 1. Verify Login Error (Banner and Toast) print("\n" + "=" * 70) print("1. LOGIN ERROR (BANNER AND TOAST)") print("=" * 70) login_page = LoginPage(driver) login_page.navigate() # Try invalid login to trigger error login_page.send_keys(login_page.IDENTIFIER_INPUT, "INVALID_USER_12345") login_page.send_keys(login_page.PASSWORD_INPUT, "INVALID_PASS_12345") time.sleep(3) # Allow UI to stabilize # Use JavaScript click to avoid interception try: submit_button = WebDriverWait(driver, 5).until( EC.element_to_be_clickable(login_page.SUBMIT_BUTTON) ) driver.execute_script("arguments[0].click();", submit_button) except Exception as e: print(f" āš ļø Error clicking submit button: {e}") # Try alternative: find and click via JavaScript submit_button = driver.find_element(*login_page.SUBMIT_BUTTON) driver.execute_script("arguments[0].click();", submit_button) time.sleep(5) # Wait for error to appear # Check for error banner (inline error - this is what actually appears) print("\n Checking for Error Banner (inline error):") results['login_error_banner'] = verify_static_attribute( driver, 'student_login__error_banner', 'Login Error Banner (Inline)' ) # Check for error toast (toast notification - may not appear) print("\n Checking for Error Toast (toast notification):") results['login_error_toast'] = verify_toast_attribute( driver, 'student_login__error_toast', 'Login Error Toast' ) # Document finding if results['login_error_banner'] and not results['login_error_toast']: print("\n šŸ“ NOTE: Login error is displayed as inline banner, not toast.") print(" āœ… Automation uses error banner (student_login__error_banner) - WORKING") print(" āš ļø Toast (student_login__error_toast) not appearing - may be UI team issue") # 2. Verify Profile Editor Toasts (requires login and navigation) print("\n" + "=" * 70) print("2. PROFILE EDITOR TOASTS") print("=" * 70) # Login with valid credentials driver.get(BASE_URL) time.sleep(2) # Use JavaScript click for login to avoid interception try: login_page.send_keys(login_page.IDENTIFIER_INPUT, TEST_USERNAME) login_page.send_keys(login_page.PASSWORD_INPUT, TEST_NEW_PASSWORD) time.sleep(2) submit_button = WebDriverWait(driver, 5).until( EC.element_to_be_clickable(login_page.SUBMIT_BUTTON) ) driver.execute_script("arguments[0].click();", submit_button) time.sleep(5) # Wait for login to complete except Exception as e: print(f" āš ļø Error during login: {e}") # Fallback: try regular login method login_page.login(TEST_USERNAME, TEST_NEW_PASSWORD) time.sleep(3) # Navigate to profile editor profile_editor = ProfileEditorPage(driver) profile_editor.navigate() profile_editor.wait_for_page_load() time.sleep(2) # Check if profile editor page is loaded if profile_editor.is_element_visible(profile_editor.PAGE, timeout=5): print(" āœ… Profile editor page loaded") print(" Note: Profile editor toasts require actual save operation") print(" Checking if toast locators are defined correctly...") # Verify locators are defined (code-level check) if hasattr(profile_editor, 'SUCCESS_TOAST') and hasattr(profile_editor, 'ERROR_TOAST'): print(f" āœ… SUCCESS_TOAST locator defined: {profile_editor.SUCCESS_TOAST}") print(f" āœ… ERROR_TOAST locator defined: {profile_editor.ERROR_TOAST}") results['profile_editor_success_toast'] = "LOCATOR_DEFINED" results['profile_editor_error_toast'] = "LOCATOR_DEFINED" else: print(" āŒ Toast locators not defined in page object") results['profile_editor_success_toast'] = False results['profile_editor_error_toast'] = False else: print(" āŒ Profile editor page not loaded") results['profile_editor_success_toast'] = False results['profile_editor_error_toast'] = False # 3. Verify Assessment Header Product Name print("\n" + "=" * 70) print("3. ASSESSMENT HEADER - PRODUCT NAME") print("=" * 70) # Navigate to assessments assessments_page = AssessmentsPage(driver) assessments_page.navigate() assessments_page.wait_for_page_load() time.sleep(2) # Get first assessment and start it assessment_ids = assessments_page.get_assessment_ids() if assessment_ids: # Use JavaScript click to avoid interception try: assessment_card = driver.find_element( By.CSS_SELECTOR, f"[data-testid='assessment_card__{assessment_ids[0]}_action']" ) driver.execute_script("arguments[0].click();", assessment_card) except Exception as e: print(f" āš ļø Error clicking assessment: {e}") assessments_page.click_begin_assessment(assessment_ids[0]) time.sleep(3) # Navigate to first domain domains_page = DomainsPage(driver) domains_page.wait_for_page_load() time.sleep(2) domain_ids = domains_page.get_all_domain_ids() unlocked_domain_id = None for domain_id in domain_ids: if domains_page.is_domain_unlocked(domain_id): unlocked_domain_id = domain_id break if unlocked_domain_id: # Use JavaScript click to avoid interception try: domain_card = driver.find_element( By.CSS_SELECTOR, f"[data-testid='domain_card__{unlocked_domain_id}_action']" ) driver.execute_script("arguments[0].click();", domain_card) except Exception as e: print(f" āš ļø Error clicking domain: {e}") domains_page.click_start_domain(unlocked_domain_id) time.sleep(5) # Dismiss instructions modal if present domain_assessment = DomainAssessmentPage(driver) if domain_assessment.is_instructions_modal_present(): domain_assessment.dismiss_instructions_modal() time.sleep(2) results['assessment_header_product_name'] = verify_static_attribute( driver, 'domain_assessment__header__product_name', 'Assessment Header Product Name' ) # 4. Verify Question Counter print("\n" + "=" * 70) print("4. ACTION BAR - QUESTION COUNTER") print("=" * 70) results['question_counter'] = verify_static_attribute( driver, 'domain_assessment__action_bar__question_counter', 'Question Counter in Action Bar' ) else: print(" āš ļø No unlocked domain found") results['assessment_header_product_name'] = False results['question_counter'] = False else: print(" āš ļø No assessments found") results['assessment_header_product_name'] = False results['question_counter'] = False except Exception as e: print(f"\nāŒ ERROR during verification: {e}") import traceback traceback.print_exc() finally: driver.quit() # Print Summary print("\n" + "=" * 70) print("VERIFICATION SUMMARY") print("=" * 70) summary = { 'High Priority': { 'student_login__error_banner': results.get('login_error_banner', False), 'student_login__error_toast': results.get('login_error_toast', False), 'profile_editor__success_toast': results.get('profile_editor_success_toast', False), 'profile_editor__error_toast': results.get('profile_editor_error_toast', False), }, 'Medium Priority': { 'domain_assessment__header__product_name': results.get('assessment_header_product_name', False), 'domain_assessment__action_bar__question_counter': results.get('question_counter', False), } } for priority, attrs in summary.items(): print(f"\n{priority}:") for attr, result in attrs.items(): if result == True: print(f" āœ… {attr}") elif result == "LOCATOR_DEFINED": print(f" āš ļø {attr} - Locator defined (needs actual toast to verify)") elif result == "NEEDS_MANUAL_TEST": print(f" āš ļø {attr} - Needs manual test (requires user action)") else: print(f" āŒ {attr}") # Calculate completion # Note: student_login__error_banner is the actual working locator (inline error) # student_login__error_toast is the toast (may not appear for this error type) high_priority_verified = sum(1 for v in summary['High Priority'].values() if v == True) high_priority_defined = sum(1 for v in summary['High Priority'].values() if v == "LOCATOR_DEFINED") medium_priority_verified = sum(1 for v in summary['Medium Priority'].values() if v == True) # Critical attributes (what automation actually uses) critical_verified = sum(1 for k, v in summary['High Priority'].items() if k in ['student_login__error_banner', 'profile_editor__success_toast', 'profile_editor__error_toast'] and v == True) print(f"\nšŸ“Š Completion:") print(f" Critical (for automation): {critical_verified}/3 verified") print(f" High Priority: {high_priority_verified}/4 verified, {high_priority_defined}/4 locators defined") print(f" Medium Priority: {medium_priority_verified}/2 verified") print(f" Total Verified: {high_priority_verified + medium_priority_verified}/6") print(f" Total (with locators): {high_priority_verified + high_priority_defined + medium_priority_verified}/6") print(f"\nšŸ“ Notes:") print(f" - student_login__error_banner: Inline error (actually used by automation) āœ…") print(f" - student_login__error_toast: Toast notification (may not appear for 'User not found' error)") print(f" - Profile editor toasts: Need actual save/error operation to verify") if critical_verified == 3 and medium_priority_verified == 2: print("\nāœ… ALL CRITICAL ATTRIBUTES VERIFIED - 100% READY FOR AUTOMATION!") elif high_priority_verified >= 3 and medium_priority_verified == 2: print("\nāœ… ALL REQUIRED ATTRIBUTES IMPLEMENTED - 100% COMPLETE!") print("āš ļø Some toast attributes need actual operations to verify") else: print("\nāš ļø Some attributes need verification") if __name__ == "__main__": main()