#!/usr/bin/env python3 """ Current DOM Verification Script Visits the site with fresh credentials and checks ALL data-testid attributes in the actual rendered DOM to verify UI Dev Team's implementation. """ import sys from pathlib import Path import json import time project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) 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.mandatory_reset_page import MandatoryResetPage from pages.profile_incomplete_page import ProfileIncompletePage from pages.profile_editor_page import ProfileEditorPage from pages.dashboard_page import DashboardPage from pages.assessments_page import AssessmentsPage from utils.driver_manager import DriverManager from utils.password_tracker import password_tracker from config.config import TEST_NEW_PASSWORD, BASE_URL import re def get_all_data_testids_from_dom(driver): """Extract ALL data-testid attributes from the current DOM""" testids = {} # Get all elements with data-testid elements = driver.find_elements(By.CSS_SELECTOR, "[data-testid]") for element in elements: testid = element.get_attribute("data-testid") tag = element.tag_name element_type = element.get_attribute("type") or tag visible = element.is_displayed() text = element.text[:100] if element.text else "" value = element.get_attribute("value")[:100] if element.get_attribute("value") else "" if testid: testids[testid] = { "tag": tag, "type": element_type, "visible": visible, "text": text, "value": value, "location": f"{tag}.{element_type}" } return testids def verify_login_page(driver): """Verify login page attributes""" print("\n" + "="*80) print("VERIFYING LOGIN PAGE") print("="*80) driver.get(f"{BASE_URL}/") time.sleep(2) testids = get_all_data_testids_from_dom(driver) expected = [ "student_login__form", "student_login__identifier_input", "student_login__password_input", "student_login__remember_checkbox", "student_login__error_banner", "student_login__submit_button", "student_login__error_toast" ] found = [] missing = [] for attr in expected: if attr in testids: found.append(attr) print(f"βœ… {attr}") else: missing.append(attr) print(f"❌ MISSING: {attr}") # Check for unexpected login_testids = [tid for tid in testids if tid.startswith("student_login__")] unexpected = [tid for tid in login_testids if tid not in expected] if unexpected: print(f"\n⚠️ UNEXPECTED (but present): {len(unexpected)}") for tid in unexpected[:10]: print(f" - {tid}") print(f"\nπŸ“Š Login Page: {len(found)}/{len(expected)} found") return {"found": found, "missing": missing, "unexpected": unexpected, "all": testids} def verify_dashboard(driver): """Verify dashboard attributes""" print("\n" + "="*80) print("VERIFYING DASHBOARD PAGE") print("="*80) dashboard = DashboardPage(driver) dashboard.navigate() time.sleep(2) testids = get_all_data_testids_from_dom(driver) expected = [ "dashboard__welcome_message", "profile_incomplete__modal", "profile_incomplete__progress_value", "profile_incomplete__complete_button" ] found = [] missing = [] for attr in expected: if attr in testids: found.append(attr) print(f"βœ… {attr}") else: missing.append(attr) print(f"❌ MISSING: {attr}") print(f"\nπŸ“Š Dashboard: {len(found)}/{len(expected)} found") return {"found": found, "missing": missing, "all": testids} def verify_student_nav(driver): """Verify student navigation attributes""" print("\n" + "="*80) print("VERIFYING STUDENT NAVIGATION") print("="*80) testids = get_all_data_testids_from_dom(driver) expected = [ "student_nav__dashboard_link", "student_nav__assessments_link", "student_nav__profile_button", "student_nav__profile_dropdown", "student_nav__edit_profile_button", "student_nav__reset_password_button", "student_nav__sign_out_button" ] found = [] missing = [] for attr in expected: if attr in testids: found.append(attr) print(f"βœ… {attr}") else: missing.append(attr) print(f"❌ MISSING: {attr}") # Check for unexpected nav_testids = [tid for tid in testids if tid.startswith("student_nav__")] unexpected = [tid for tid in nav_testids if tid not in expected] if unexpected: print(f"\n⚠️ UNEXPECTED (but present): {len(unexpected)}") for tid in unexpected[:10]: print(f" - {tid}") print(f"\nπŸ“Š Student Nav: {len(found)}/{len(expected)} found") return {"found": found, "missing": missing, "unexpected": unexpected, "all": testids} def verify_profile_editor(driver): """Verify profile editor attributes""" print("\n" + "="*80) print("VERIFYING PROFILE EDITOR PAGE") print("="*80) profile_editor = ProfileEditorPage(driver) profile_editor.navigate() profile_editor.wait_for_page_load() time.sleep(3) # Wait for full render testids = get_all_data_testids_from_dom(driver) print(f"πŸ“‹ Found {len(testids)} total data-testid attributes in DOM\n") # Base attributes base_expected = [ "profile_editor__page", "profile_editor__progress_value", "profile_editor__missing_fields_toggle", "profile_editor__prev_button", "profile_editor__next_button", "profile_editor__cancel_button", "profile_editor__save_button", "profile_editor__tab_personal_information", "profile_editor__tab_contact_information", "profile_editor__tab_parent_guardian", "profile_editor__tab_education_details", "profile_editor__tab_focus_areas", "profile_editor__tab_self_assessment", "profile_editor__tab_hobbies_clubs", "profile_editor__tab_achievements", "profile_editor__tab_expectations", ] # Step 1: Personal Information step1_expected = [ "profile_editor__first_name_input", "profile_editor__last_name_input", "profile_editor__gender_select", "profile_editor__dob_input", "profile_editor__roll_number_input", "profile_editor__nationality_input", "profile_editor__language_input", "profile_editor__student_id_input", "profile_editor__student_cpid_input", "profile_editor__specially_abled_checkbox", "profile_editor__specially_abled_details_textarea" ] # Step 2: Contact Information step2_expected = [ "profile_editor__email_input", "profile_editor__phone_input", "profile_editor__address_input", "profile_editor__city_input", "profile_editor__state_input", "profile_editor__zip_code_input", "profile_editor__native_state_input" ] # Step 3: Parent/Guardian step3_expected = [ "profile_editor__father_full_name_input", "profile_editor__father_age_range_select", "profile_editor__father_occupation_input", "profile_editor__father_email_input", "profile_editor__mother_full_name_input", "profile_editor__mother_age_range_select", "profile_editor__mother_occupation_input", "profile_editor__mother_email_input", "profile_editor__guardian_different_checkbox", "profile_editor__guardian_full_name_input", "profile_editor__guardian_relationship_input", "profile_editor__guardian_phone_input", "profile_editor__guardian_email_input", "profile_editor__guardian_address_input" ] # Step 4: Education Details step4_expected = [ "profile_editor__full_name_input", "profile_editor__current_grade_input", "profile_editor__section_input", "profile_editor__board_stream_select" ] # Step 8: Achievements step8_expected = [ "profile_editor__achievement_academics_textarea", "profile_editor__achievement_sports_textarea", "profile_editor__achievement_cultural_textarea", "profile_editor__achievement_trained_textarea", "profile_editor__achievement_others_textarea" ] all_expected = base_expected + step1_expected + step2_expected + step3_expected + step4_expected + step8_expected found = [] missing = [] print("πŸ” Checking base attributes...") for attr in all_expected: if attr in testids: found.append(attr) print(f"βœ… {attr}") else: missing.append(attr) print(f"❌ MISSING: {attr}") # Check dynamic checkboxes print("\nπŸ” Checking dynamic checkboxes...") patterns = { "short_term_focus": "profile_editor__short_term_focus__", "long_term_focus": "profile_editor__long_term_focus__", "strength": "profile_editor__strength__", "improvement": "profile_editor__improvement__", "hobby": "profile_editor__hobby__", "club": "profile_editor__club_", "expectation": "profile_editor__expectation__" } dynamic_counts = {} for name, pattern in patterns.items(): matching = [tid for tid in testids if tid.startswith(pattern)] dynamic_counts[name] = len(matching) if matching: print(f"βœ… {name}: {len(matching)} checkboxes found") for tid in matching[:5]: print(f" - {tid}") if len(matching) > 5: print(f" ... and {len(matching) - 5} more") else: print(f"❌ {name}: No checkboxes found") # Check "Others" text inputs print("\nπŸ” Checking 'Others' text inputs...") others_expected = [ "profile_editor__short_term_focus_others_text", "profile_editor__long_term_focus_others_text", "profile_editor__strength_others_text", "profile_editor__improvement_others_text", "profile_editor__hobby_other_text", "profile_editor__club_other_text", "profile_editor__expectation_others_text" ] for attr in others_expected: if attr in testids: print(f"βœ… {attr}") else: print(f"❌ MISSING: {attr}") # Check tab scroll buttons print("\nπŸ” Checking tab scroll buttons...") scroll_expected = [ "profile_editor__tabs_scroll_right_button", "profile_editor__tabs_scroll_left_button" ] for attr in scroll_expected: if attr in testids: print(f"βœ… {attr}") else: print(f"❌ MISSING: {attr}") # Check toast messages print("\nπŸ” Checking toast messages...") toast_expected = [ "profile_editor__toast_message", "profile_editor__success_toast", "profile_editor__error_toast" ] toast_found = [attr for attr in toast_expected if attr in testids] if toast_found: for attr in toast_found: print(f"βœ… {attr}") else: print("❌ No toast message attributes found") # Get all profile_editor testids all_profile_testids = [tid for tid in testids if tid.startswith("profile_editor__")] unexpected = [tid for tid in all_profile_testids if tid not in all_expected and not any(tid.startswith(p) for p in patterns.values()) and tid not in others_expected and tid not in scroll_expected and tid not in toast_expected] if unexpected: print(f"\n⚠️ UNEXPECTED profile_editor attributes ({len(unexpected)}):") for tid in unexpected[:20]: print(f" - {tid}") if len(unexpected) > 20: print(f" ... and {len(unexpected) - 20} more") total_dynamic = sum(dynamic_counts.values()) total_found = len(found) + total_dynamic print(f"\nπŸ“Š Profile Editor Summary:") print(f" Base attributes: {len(found)}/{len(all_expected)}") print(f" Dynamic checkboxes: {total_dynamic}") print(f" Total found: {total_found}") print(f" Unexpected: {len(unexpected)}") return { "found": found, "missing": missing, "dynamic": dynamic_counts, "unexpected": unexpected, "all": testids, "total_found": total_found } def verify_assessments_page(driver): """Verify assessments page attributes""" print("\n" + "="*80) print("VERIFYING ASSESSMENTS PAGE") print("="*80) assessments = AssessmentsPage(driver) assessments.navigate() assessments.wait_for_page_load() time.sleep(2) testids = get_all_data_testids_from_dom(driver) # Check for assessment card pattern assessment_cards = [tid for tid in testids if tid.startswith("assessment_card__")] if assessment_cards: print(f"βœ… Found {len(assessment_cards)} assessment card attributes") for tid in assessment_cards[:5]: print(f" - {tid}") if len(assessment_cards) > 5: print(f" ... and {len(assessment_cards) - 5} more") else: print("❌ No assessment card attributes found") return {"found": assessment_cards, "all": testids} def main(): """Main verification function""" driver = None try: print("πŸš€ Starting Current DOM Verification...") print(f"🌐 Environment: {BASE_URL}\n") print(f"πŸ”‘ Using credentials: MAHMAH812B\n") # Initialize driver driver_manager = DriverManager() driver = driver_manager.get_driver(headless=False) results = {} # Step 1: Login print("\n" + "="*80) print("STEP 1: LOGIN") print("="*80) login_page = LoginPage(driver) login_page.login(identifier="MAHMAH812B", password="s&OI0m9rJAUb") print(f"βœ… Login successful - URL: {driver.current_url}\n") # Step 2: Verify Login Page (if redirected back) # Actually, we're logged in, so verify current page # Step 3: Handle Password Reset if needed reset_page = MandatoryResetPage(driver) if reset_page.is_modal_present(): print("⚠️ Password reset modal present - resetting password...") reset_page.reset_password( current_password="s&OI0m9rJAUb", new_password=TEST_NEW_PASSWORD, confirm_password=TEST_NEW_PASSWORD, student_cpid="MAHMAH812B" ) print("βœ… Password reset completed\n") time.sleep(2) # Step 4: Verify Dashboard results["dashboard"] = verify_dashboard(driver) # Step 5: Verify Student Navigation results["student_nav"] = verify_student_nav(driver) # Step 6: Navigate to Profile Editor profile_incomplete = ProfileIncompletePage(driver) if profile_incomplete.is_modal_present(): print("\n⚠️ Profile incomplete modal present - clicking Complete Profile...") profile_incomplete.click_complete() time.sleep(3) else: profile_editor = ProfileEditorPage(driver) profile_editor.navigate() time.sleep(3) # Step 7: Verify Profile Editor results["profile_editor"] = verify_profile_editor(driver) # Step 8: Navigate to Assessments dashboard = DashboardPage(driver) dashboard.navigate() time.sleep(2) dashboard.click_assessments() time.sleep(3) # Step 9: Verify Assessments Page results["assessments"] = verify_assessments_page(driver) # Step 10: Verify Login Page (logout and check) print("\n" + "="*80) print("STEP 10: VERIFYING LOGIN PAGE (After Logout)") print("="*80) from pages.student_nav_page import StudentNavPage nav = StudentNavPage(driver) try: nav.logout() time.sleep(2) results["login"] = verify_login_page(driver) except Exception as e: print(f"⚠️ Could not logout: {e}") # Navigate directly to login driver.get(f"{BASE_URL}/") time.sleep(2) results["login"] = verify_login_page(driver) # Final Summary print("\n" + "="*80) print("FINAL VERIFICATION SUMMARY") print("="*80) total_found = 0 total_expected = 0 if "login" in results: found_count = len(results["login"]["found"]) total_found += found_count total_expected += 7 print(f"Login Page: {found_count}/7") if "dashboard" in results: found_count = len(results["dashboard"]["found"]) total_found += found_count total_expected += 4 print(f"Dashboard: {found_count}/4") if "student_nav" in results: found_count = len(results["student_nav"]["found"]) total_found += found_count total_expected += 7 print(f"Student Nav: {found_count}/7") if "profile_editor" in results: base_found = len(results["profile_editor"]["found"]) dynamic_found = sum(results["profile_editor"]["dynamic"].values()) total_profile = base_found + dynamic_found total_found += total_profile print(f"Profile Editor: {total_profile} (Base: {base_found}, Dynamic: {dynamic_found})") if "assessments" in results: found_count = len(results["assessments"]["found"]) total_found += found_count print(f"Assessments: {found_count} cards found") print(f"\nπŸ“Š TOTAL: {total_found} attributes found") # Save results results_file = project_root / "analysis" / "current_dom_verification_results.json" with open(results_file, 'w') as f: json.dump(results, f, indent=2, default=str) print(f"\nπŸ“„ Results saved to: {results_file}") # Keep browser open for inspection print("\n⏸️ Browser will remain open for 120 seconds for manual inspection...") print(" Press Ctrl+C to close early\n") time.sleep(120) except KeyboardInterrupt: print("\n\n⚠️ Verification interrupted by user") except Exception as e: print(f"\n\n❌ Error during verification: {e}") import traceback traceback.print_exc() finally: if driver: driver.quit() print("\nβœ… Browser closed") if __name__ == "__main__": main()