CP_AUTOMATION/scripts/comprehensive_dom_verification.py
2025-12-12 19:54:54 +05:30

662 lines
25 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Comprehensive DOM Verification Script
Systematically verifies ALL data-testid attributes by:
1. Logging in
2. Navigating through each tab of profile editor
3. Waiting for elements to load
4. Scrolling to make elements visible
5. Checking all attributes in each step
6. Reporting detailed findings
"""
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 selenium.webdriver.common.action_chains import ActionChains
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 utils.driver_manager import DriverManager
from config.config import TEST_NEW_PASSWORD, BASE_URL
def get_all_data_testids(driver, scroll_into_view=True):
"""Get all data-testid attributes from DOM, optionally scrolling elements into view"""
elements = driver.find_elements(By.CSS_SELECTOR, "[data-testid]")
testids = {}
for elem in elements:
try:
testid = elem.get_attribute("data-testid")
if testid:
# Scroll into view if requested
if scroll_into_view:
try:
driver.execute_script("arguments[0].scrollIntoView({block: 'center', behavior: 'smooth'});", elem)
time.sleep(0.1) # Brief wait for scroll
except:
pass
testids[testid] = {
"tag": elem.tag_name,
"type": elem.get_attribute("type") or elem.tag_name,
"visible": elem.is_displayed(),
"enabled": elem.is_enabled() if hasattr(elem, 'is_enabled') else True,
"text": elem.text[:50] if elem.text else "",
"value": elem.get_attribute("value")[:50] if elem.get_attribute("value") else ""
}
except Exception as e:
# Element might have been removed from DOM
continue
return testids
def wait_for_tab_to_load(driver, tab_name, timeout=10):
"""Wait for a specific tab to be fully loaded"""
try:
# Wait for tab to be active/visible
tab_locator = (By.CSS_SELECTOR, f"[data-testid='profile_editor__tab_{tab_name}']")
WebDriverWait(driver, timeout).until(
EC.presence_of_element_located(tab_locator)
)
# Wait a bit more for content to render
time.sleep(1)
# Scroll to top of form
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(0.5)
return True
except Exception as e:
print(f"⚠️ Warning: Could not verify tab {tab_name} loaded: {e}")
return False
def navigate_to_tab_and_check(driver, tab_index, tab_name, expected_attributes):
"""Navigate to a specific tab and check for expected attributes"""
print(f"\n{'='*80}")
print(f"TAB {tab_index + 1}: {tab_name.upper().replace('_', ' ')}")
print(f"{'='*80}")
try:
# Navigate to tab
profile_editor = ProfileEditorPage(driver)
profile_editor.navigate_to_tab(tab_index)
time.sleep(2) # Wait for tab content to load
# Scroll through the tab to trigger lazy loading
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(0.5)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(0.5)
# Get all testids in this tab
all_testids = get_all_data_testids(driver, scroll_into_view=True)
# Filter for profile_editor testids
profile_testids = {tid: info for tid, info in all_testids.items() if tid.startswith("profile_editor__")}
print(f"📋 Found {len(profile_testids)} profile_editor attributes in this tab")
# Check expected attributes
found = []
missing = []
for attr in expected_attributes:
if attr in profile_testids:
info = profile_testids[attr]
status = "" if info["visible"] else "⚠️ (hidden)"
print(f"{status} {attr}")
found.append(attr)
else:
print(f"❌ MISSING: {attr}")
missing.append(attr)
# Check for unexpected attributes
unexpected = [tid for tid in profile_testids if tid not in expected_attributes]
if unexpected:
print(f"\n⚠️ UNEXPECTED attributes found ({len(unexpected)}):")
for tid in sorted(unexpected)[:10]:
print(f" - {tid}")
if len(unexpected) > 10:
print(f" ... and {len(unexpected) - 10} more")
return {
"tab_name": tab_name,
"found": found,
"missing": missing,
"unexpected": unexpected,
"all_testids": list(profile_testids.keys())
}
except Exception as e:
print(f"❌ Error checking tab {tab_name}: {e}")
import traceback
traceback.print_exc()
return {
"tab_name": tab_name,
"found": [],
"missing": expected_attributes,
"unexpected": [],
"all_testids": [],
"error": str(e)
}
def check_dynamic_checkboxes(driver, pattern_prefix, expected_count=None):
"""Check for dynamic checkboxes matching a pattern"""
try:
# Scroll through page to load all checkboxes
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(0.3)
# Find all checkboxes with matching pattern
checkboxes = driver.find_elements(
By.CSS_SELECTOR,
f"input[type='checkbox'][data-testid^='{pattern_prefix}']"
)
found_testids = []
for cb in checkboxes:
try:
# Scroll checkbox into view
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", cb)
time.sleep(0.1)
testid = cb.get_attribute("data-testid")
if testid and testid.startswith(pattern_prefix):
found_testids.append(testid)
except:
continue
# Also try finding by CSS selector with wildcard
all_elements = driver.find_elements(By.CSS_SELECTOR, "[data-testid]")
for elem in all_elements:
testid = elem.get_attribute("data-testid")
if testid and testid.startswith(pattern_prefix) and testid not in found_testids:
found_testids.append(testid)
found_count = len(found_testids)
status = "" if found_count > 0 else ""
if expected_count:
status = "" if found_count >= expected_count else "⚠️"
print(f"{status} {pattern_prefix}: {found_count}/{expected_count} found")
else:
print(f"{status} {pattern_prefix}: {found_count} found")
if found_testids:
for tid in sorted(found_testids)[:5]:
print(f" - {tid}")
if len(found_testids) > 5:
print(f" ... and {len(found_testids) - 5} more")
return found_testids
except Exception as e:
print(f"❌ Error checking {pattern_prefix}: {e}")
return []
def main():
driver = None
try:
print("🚀 COMPREHENSIVE DOM VERIFICATION")
print("="*80)
print(f"🌐 Environment: {BASE_URL}")
print(f"🔑 Credentials: BATBAT311A")
print("="*80)
# Initialize driver
driver_manager = DriverManager()
driver = driver_manager.get_driver(headless=False)
driver.maximize_window()
results = {
"login": {},
"dashboard": {},
"student_nav": {},
"password_reset": {},
"profile_editor": {
"tabs": {},
"dynamic_checkboxes": {},
"summary": {}
}
}
# ============================================================
# STEP 1: LOGIN
# ============================================================
print("\n" + "="*80)
print("STEP 1: LOGIN")
print("="*80)
login_page = LoginPage(driver)
login_page.login(identifier="BATBAT311A", password="17k*o@yReCUA")
time.sleep(3)
# Check login page attributes (if still on login)
if "/login" in driver.current_url or driver.current_url.rstrip("/") == BASE_URL.rstrip("/"):
login_testids = get_all_data_testids(driver)
login_expected = [
"student_login__form",
"student_login__identifier_input",
"student_login__password_input",
"student_login__remember_checkbox",
"student_login__error_banner",
"student_login__submit_button"
]
found = [tid for tid in login_expected if tid in login_testids]
print(f"📊 Login Page: {len(found)}/{len(login_expected)} found")
results["login"] = {"found": found, "missing": [tid for tid in login_expected if tid not in found]}
else:
print("✅ Login successful - redirected to dashboard")
results["login"] = {"status": "success"}
# ============================================================
# STEP 2: PASSWORD RESET (if needed)
# ============================================================
print("\n" + "="*80)
print("STEP 2: PASSWORD RESET CHECK")
print("="*80)
reset_page = MandatoryResetPage(driver)
if reset_page.is_modal_present():
print("🔄 Password reset modal present - resetting...")
reset_page.reset_password("17k*o@yReCUA", TEST_NEW_PASSWORD, TEST_NEW_PASSWORD, "BATBAT311A")
time.sleep(3)
results["password_reset"] = {"status": "completed"}
else:
print("✅ No password reset required")
results["password_reset"] = {"status": "not_required"}
# ============================================================
# STEP 3: NAVIGATE TO PROFILE EDITOR
# ============================================================
print("\n" + "="*80)
print("STEP 3: NAVIGATING TO PROFILE EDITOR")
print("="*80)
# Handle profile incomplete modal
profile_incomplete = ProfileIncompletePage(driver)
if profile_incomplete.is_modal_present():
print("⚠️ 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)
# Wait for profile editor to fully load
profile_editor = ProfileEditorPage(driver)
profile_editor.wait_for_page_load()
time.sleep(2)
# ============================================================
# STEP 4: CHECK PAGE-LEVEL ATTRIBUTES
# ============================================================
print("\n" + "="*80)
print("STEP 4: PAGE-LEVEL ATTRIBUTES")
print("="*80)
all_testids = get_all_data_testids(driver)
page_level_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"
]
page_level_found = []
for attr in page_level_expected:
if attr in all_testids:
print(f"{attr}")
page_level_found.append(attr)
else:
print(f"❌ MISSING: {attr}")
print(f"\n📊 Page-Level: {len(page_level_found)}/{len(page_level_expected)} found")
# ============================================================
# STEP 5: CHECK TAB NAVIGATION
# ============================================================
print("\n" + "="*80)
print("STEP 5: TAB NAVIGATION")
print("="*80)
tab_expected = [
"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",
"profile_editor__tabs_scroll_left_button",
"profile_editor__tabs_scroll_right_button"
]
tab_found = []
for attr in tab_expected:
if attr in all_testids:
print(f"{attr}")
tab_found.append(attr)
else:
print(f"❌ MISSING: {attr}")
print(f"\n📊 Tab Navigation: {len(tab_found)}/{len(tab_expected)} found")
# ============================================================
# STEP 6: SYSTEMATICALLY CHECK EACH TAB
# ============================================================
# Tab 0: Personal Information
tab0_result = navigate_to_tab_and_check(driver, 0, "personal_information", [
"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"
])
results["profile_editor"]["tabs"]["personal_information"] = tab0_result
# Tab 1: Contact Information
tab1_result = navigate_to_tab_and_check(driver, 1, "contact_information", [
"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"
])
results["profile_editor"]["tabs"]["contact_information"] = tab1_result
# Tab 2: Parent/Guardian
tab2_result = navigate_to_tab_and_check(driver, 2, "parent_guardian", [
"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"
])
results["profile_editor"]["tabs"]["parent_guardian"] = tab2_result
# Tab 3: Education Details
tab3_result = navigate_to_tab_and_check(driver, 3, "education_details", [
"profile_editor__full_name_input",
"profile_editor__current_grade_input",
"profile_editor__section_input",
"profile_editor__board_stream_select"
])
results["profile_editor"]["tabs"]["education_details"] = tab3_result
# Tab 4: Focus Areas (with dynamic checkboxes)
print("\n" + "="*80)
print("TAB 5: FOCUS AREAS")
print("="*80)
profile_editor.navigate_to_tab(4)
time.sleep(2)
# Scroll to load all checkboxes
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(1)
# Check dynamic checkboxes
print("\n🔍 Checking Short-term Focus Areas...")
short_term = check_dynamic_checkboxes(driver, "profile_editor__short_term_focus__", expected_count=11)
print("\n🔍 Checking Long-term Focus Areas...")
long_term = check_dynamic_checkboxes(driver, "profile_editor__long_term_focus__", expected_count=11)
# Check "Others" text inputs
others_expected = [
"profile_editor__short_term_focus_others_text",
"profile_editor__long_term_focus_others_text"
]
all_testids_tab4 = get_all_data_testids(driver)
for attr in others_expected:
if attr in all_testids_tab4:
print(f"{attr}")
else:
print(f"❌ MISSING: {attr}")
results["profile_editor"]["tabs"]["focus_areas"] = {
"short_term_focus": short_term,
"long_term_focus": long_term,
"others_text": [tid for tid in others_expected if tid in all_testids_tab4]
}
# Tab 5: Self-Assessment (with dynamic checkboxes)
print("\n" + "="*80)
print("TAB 6: SELF-ASSESSMENT")
print("="*80)
profile_editor.navigate_to_tab(5)
time.sleep(2)
# Scroll to load all checkboxes
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(1)
print("\n🔍 Checking Strengths...")
strengths = check_dynamic_checkboxes(driver, "profile_editor__strength__", expected_count=19)
print("\n🔍 Checking Areas of Improvement...")
improvements = check_dynamic_checkboxes(driver, "profile_editor__improvement__", expected_count=19)
# Check "Others" text inputs
others_expected = [
"profile_editor__strength_others_text",
"profile_editor__improvement_others_text"
]
all_testids_tab5 = get_all_data_testids(driver)
for attr in others_expected:
if attr in all_testids_tab5:
print(f"{attr}")
else:
print(f"❌ MISSING: {attr}")
results["profile_editor"]["tabs"]["self_assessment"] = {
"strengths": strengths,
"improvements": improvements,
"others_text": [tid for tid in others_expected if tid in all_testids_tab5]
}
# Tab 6: Hobbies & Clubs (with dynamic checkboxes)
print("\n" + "="*80)
print("TAB 7: HOBBIES & CLUBS")
print("="*80)
profile_editor.navigate_to_tab(6)
time.sleep(2)
# Scroll to load all checkboxes
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(1)
print("\n🔍 Checking Hobbies...")
hobbies = check_dynamic_checkboxes(driver, "profile_editor__hobby__", expected_count=12)
print("\n🔍 Checking Clubs...")
clubs = check_dynamic_checkboxes(driver, "profile_editor__club_", expected_count=12) # Single underscore
# Check "Others" text inputs
others_expected = [
"profile_editor__hobby_other_text",
"profile_editor__club_other_text"
]
all_testids_tab6 = get_all_data_testids(driver)
for attr in others_expected:
if attr in all_testids_tab6:
print(f"{attr}")
else:
print(f"❌ MISSING: {attr}")
results["profile_editor"]["tabs"]["hobbies_clubs"] = {
"hobbies": hobbies,
"clubs": clubs,
"others_text": [tid for tid in others_expected if tid in all_testids_tab6]
}
# Tab 7: Achievements
tab7_result = navigate_to_tab_and_check(driver, 7, "achievements", [
"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"
])
results["profile_editor"]["tabs"]["achievements"] = tab7_result
# Tab 8: Expectations (with dynamic checkboxes)
print("\n" + "="*80)
print("TAB 9: EXPECTATIONS")
print("="*80)
profile_editor.navigate_to_tab(8)
time.sleep(2)
# Scroll to load all checkboxes
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)
driver.execute_script("window.scrollTo(0, 0);")
time.sleep(1)
print("\n🔍 Checking Expectations...")
expectations = check_dynamic_checkboxes(driver, "profile_editor__expectation__", expected_count=10)
# Check "Others" text input
others_expected = ["profile_editor__expectation_others_text"]
all_testids_tab8 = get_all_data_testids(driver)
for attr in others_expected:
if attr in all_testids_tab8:
print(f"{attr}")
else:
print(f"❌ MISSING: {attr}")
results["profile_editor"]["tabs"]["expectations"] = {
"expectations": expectations,
"others_text": [tid for tid in others_expected if tid in all_testids_tab8]
}
# ============================================================
# FINAL SUMMARY
# ============================================================
print("\n" + "="*80)
print("FINAL VERIFICATION SUMMARY")
print("="*80)
# Count all found attributes
total_found = 0
total_expected = 0
# Page-level
total_found += len(page_level_found)
total_expected += len(page_level_expected)
# Tab navigation
total_found += len(tab_found)
total_expected += len(tab_expected)
# Tab-specific attributes
for tab_name, tab_result in results["profile_editor"]["tabs"].items():
if "found" in tab_result:
total_found += len(tab_result["found"])
total_expected += len(tab_result.get("missing", [])) + len(tab_result["found"])
if "short_term_focus" in tab_result:
total_found += len(tab_result["short_term_focus"])
if "long_term_focus" in tab_result:
total_found += len(tab_result["long_term_focus"])
if "strengths" in tab_result:
total_found += len(tab_result["strengths"])
if "improvements" in tab_result:
total_found += len(tab_result["improvements"])
if "hobbies" in tab_result:
total_found += len(tab_result["hobbies"])
if "clubs" in tab_result:
total_found += len(tab_result["clubs"])
if "expectations" in tab_result:
total_found += len(tab_result["expectations"])
print(f"\n📊 TOTAL ATTRIBUTES FOUND: {total_found}")
print(f"📊 TOTAL ATTRIBUTES EXPECTED: ~250+")
print(f"📊 COVERAGE: {(total_found/250)*100:.1f}%")
# Save results
results["profile_editor"]["summary"] = {
"total_found": total_found,
"total_expected": total_expected,
"page_level_found": len(page_level_found),
"tab_navigation_found": len(tab_found)
}
results_file = project_root / "analysis" / "comprehensive_dom_verification_results.json"
with open(results_file, 'w') as f:
json.dump(results, f, indent=2, default=str)
print(f"\n📄 Detailed results saved to: {results_file}")
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()