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

331 lines
14 KiB
Python

"""
DOM Inspector - World-Class Debug Tool
Purpose: Inspect actual DOM structure at runtime to identify correct locators
Usage: Run this script to quickly identify element structures without running full tests
This saves time by:
1. Inspecting DOM directly without full test execution
2. Testing multiple locator strategies quickly
3. Identifying correct selectors before updating code
4. Verifying element presence and visibility
"""
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
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.mandatory_reset_page import MandatoryResetPage
from config.config import TEST_USERNAME, TEST_PASSWORD, BASE_URL
import time
import json
class DOMInspector:
"""World-Class DOM Inspector for Quick Debugging"""
def __init__(self, driver):
self.driver = driver
def find_elements_by_strategies(self, element_name, strategies):
"""
Try multiple locator strategies and report results
Args:
element_name: Name of element for logging
strategies: List of (strategy_name, locator) tuples
"""
print(f"\n{'='*80}")
print(f"🔍 INSPECTING: {element_name}")
print(f"{'='*80}")
results = []
for strategy_name, locator in strategies:
try:
if isinstance(locator, tuple):
by_type, selector = locator
else:
by_type, selector = locator[0], locator[1]
print(f"\n📋 Strategy: {strategy_name}")
print(f" Locator: {by_type} = '{selector}'")
# Try to find element
elements = self.driver.find_elements(by_type, selector)
if elements:
print(f" ✅ Found {len(elements)} element(s)")
for idx, elem in enumerate(elements):
try:
is_displayed = elem.is_displayed()
is_enabled = elem.is_enabled() if hasattr(elem, 'is_enabled') else 'N/A'
tag_name = elem.tag_name
text = elem.text[:100] if elem.text else 'No text'
# Get attributes
attrs = {}
try:
attrs['id'] = elem.get_attribute('id')
attrs['class'] = elem.get_attribute('class')
attrs['data-testid'] = elem.get_attribute('data-testid')
attrs['name'] = elem.get_attribute('name')
attrs['type'] = elem.get_attribute('type')
except:
pass
print(f" Element {idx + 1}:")
print(f" - Tag: {tag_name}")
print(f" - Displayed: {is_displayed}")
print(f" - Enabled: {is_enabled}")
print(f" - Text: {text}")
print(f" - Attributes: {json.dumps({k: v for k, v in attrs.items() if v}, indent=8)}")
# Get outer HTML snippet
try:
outer_html = elem.get_attribute('outerHTML')
if outer_html:
snippet = outer_html[:200] + '...' if len(outer_html) > 200 else outer_html
print(f" - HTML: {snippet}")
except:
pass
results.append({
'strategy': strategy_name,
'locator': selector,
'found': True,
'displayed': is_displayed,
'element': elem,
'attributes': attrs
})
except Exception as e:
print(f" ⚠️ Error inspecting element {idx + 1}: {e}")
else:
print(f" ❌ No elements found")
results.append({
'strategy': strategy_name,
'locator': selector,
'found': False
})
except Exception as e:
print(f" ❌ Error with strategy: {e}")
results.append({
'strategy': strategy_name,
'locator': selector,
'found': False,
'error': str(e)
})
return results
def inspect_modal_structure(self):
"""Inspect password reset modal structure"""
print(f"\n{'='*80}")
print("🔍 INSPECTING: Password Reset Modal Structure")
print(f"{'='*80}")
# Check for modal overlay
print("\n📋 Checking for modal overlay...")
overlay_selectors = [
("CSS - Exact", (By.CSS_SELECTOR, "div.fixed.inset-0.bg-black\\/60.z-\\[99999\\]")),
("CSS - Partial", (By.CSS_SELECTOR, "div[class*='fixed'][class*='inset-0'][class*='bg-black'][class*='z-[99999]']")),
("CSS - Generic", (By.CSS_SELECTOR, "div.fixed.inset-0.bg-black")),
("XPath - Fixed inset", (By.XPATH, "//div[contains(@class, 'fixed') and contains(@class, 'inset-0')]")),
]
overlay_results = self.find_elements_by_strategies("Modal Overlay", overlay_selectors)
# Check for modal content
print("\n📋 Checking for modal content...")
content_selectors = [
("Text - Welcome", (By.XPATH, "//*[contains(text(), 'Welcome to Cognitive Prism')]")),
("Text - Reset Password", (By.XPATH, "//*[contains(text(), 'Password Reset Required')]")),
("Text - Secure Account", (By.XPATH, "//*[contains(text(), 'Secure Your Account')]")),
]
content_results = self.find_elements_by_strategies("Modal Content", content_selectors)
return overlay_results, content_results
def inspect_continue_button(self):
"""Inspect Continue button structure"""
print(f"\n{'='*80}")
print("🔍 INSPECTING: Continue Button")
print(f"{'='*80}")
strategies = [
("data-testid", (By.CSS_SELECTOR, "[data-testid='mandatory_reset__continue_button']")),
("XPath - Span text", (By.XPATH, "//span[contains(text(), 'Continue to Reset Password')]")),
("XPath - Button with span", (By.XPATH, "//button[.//span[contains(text(), 'Continue')]]")),
("XPath - Button contains Continue", (By.XPATH, "//button[contains(., 'Continue')]")),
("XPath - Button with Reset", (By.XPATH, "//button[contains(., 'Reset Password')]")),
("XPath - Any button in modal", (By.XPATH, "//div[contains(@class, 'fixed')]//button")),
("XPath - Button with arrow icon", (By.XPATH, "//button[.//*[local-name()='svg']]")),
]
return self.find_elements_by_strategies("Continue Button", strategies)
def inspect_form_fields(self):
"""Inspect password reset form fields"""
print(f"\n{'='*80}")
print("🔍 INSPECTING: Password Reset Form Fields")
print(f"{'='*80}")
strategies = [
("Form container", (By.CSS_SELECTOR, "[data-testid='mandatory_reset__form']")),
("Current password input", (By.CSS_SELECTOR, "[data-testid='mandatory_reset__current_password_input']")),
("New password input", (By.CSS_SELECTOR, "[data-testid='mandatory_reset__new_password_input']")),
("Confirm password input", (By.CSS_SELECTOR, "[data-testid='mandatory_reset__confirm_password_input']")),
("Submit button", (By.CSS_SELECTOR, "[data-testid='mandatory_reset__submit_button']")),
("XPath - Input by name", (By.XPATH, "//input[@name='currentPassword' or @name='newPassword' or @name='confirmPassword']")),
("XPath - Input type password", (By.XPATH, "//input[@type='password']")),
]
return self.find_elements_by_strategies("Form Fields", strategies)
def get_page_source_snippet(self, search_text, context_lines=5):
"""Get snippet of page source around specific text"""
try:
page_source = self.driver.page_source
if search_text.lower() in page_source.lower():
index = page_source.lower().index(search_text.lower())
start = max(0, index - 500)
end = min(len(page_source), index + 500)
snippet = page_source[start:end]
return snippet
return None
except:
return None
def inspect_page_source(self):
"""Inspect page source for key indicators"""
print(f"\n{'='*80}")
print("🔍 INSPECTING: Page Source Indicators")
print(f"{'='*80}")
indicators = [
"Welcome to Cognitive Prism",
"Password Reset Required",
"Continue to Reset Password",
"mandatory_reset",
"data-testid",
]
page_source = self.driver.page_source.lower()
for indicator in indicators:
found = indicator.lower() in page_source
status = "" if found else ""
print(f"{status} '{indicator}': {'Found' if found else 'Not found'}")
if found:
snippet = self.get_page_source_snippet(indicator)
if snippet:
print(f" Context: {snippet[:300]}...")
def debug_password_reset_modal():
"""Main debug function for password reset modal"""
print("=" * 80)
print("🔍 DOM INSPECTOR - Password Reset Modal Debug")
print("=" * 80)
print("\n🎯 Purpose: Inspect actual DOM structure to identify correct locators")
print("💡 This saves time by avoiding full test execution\n")
# Setup Chrome driver
chrome_options = Options()
chrome_options.add_argument("--start-maximized")
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=chrome_options)
inspector = DOMInspector(driver)
try:
# Step 1: Login
print(f"\n{'='*80}")
print("STEP 1: LOGIN")
print(f"{'='*80}")
login_page = LoginPage(driver)
login_page.login(identifier=TEST_USERNAME, password=TEST_PASSWORD)
print(f"✅ Login completed")
print(f" Current URL: {driver.current_url}")
time.sleep(2)
# Step 2: Inspect modal structure
print(f"\n{'='*80}")
print("STEP 2: INSPECT MODAL STRUCTURE")
print(f"{'='*80}")
overlay_results, content_results = inspector.inspect_modal_structure()
# Step 3: Inspect Continue button
print(f"\n{'='*80}")
print("STEP 3: INSPECT CONTINUE BUTTON")
print(f"{'='*80}")
continue_results = inspector.inspect_continue_button()
# Step 4: Inspect form fields (if form is visible)
print(f"\n{'='*80}")
print("STEP 4: INSPECT FORM FIELDS")
print(f"{'='*80}")
form_results = inspector.inspect_form_fields()
# Step 5: Inspect page source
inspector.inspect_page_source()
# Step 6: Summary and recommendations
print(f"\n{'='*80}")
print("📊 SUMMARY & RECOMMENDATIONS")
print(f"{'='*80}")
# Find working strategies
working_overlay = [r for r in overlay_results if r.get('found') and r.get('displayed')]
working_continue = [r for r in continue_results if r.get('found') and r.get('displayed')]
working_form = [r for r in form_results if r.get('found') and r.get('displayed')]
print(f"\n✅ Working Strategies Found:")
if working_overlay:
print(f" Modal Overlay: {working_overlay[0]['strategy']} - {working_overlay[0]['locator']}")
if working_continue:
print(f" Continue Button: {working_continue[0]['strategy']} - {working_continue[0]['locator']}")
if working_form:
print(f" Form Fields: {working_form[0]['strategy']} - {working_form[0]['locator']}")
if not working_continue:
print(f"\n⚠️ Continue Button Not Found!")
print(f" Recommendations:")
print(f" 1. Check if button is inside a shadow DOM")
print(f" 2. Check if button has animation delays")
print(f" 3. Try JavaScript-based element finding")
print(f" 4. Check if button is inside a specific container")
print(f"\n⏸️ Browser will stay open for 30 seconds for manual inspection...")
print(f" You can inspect the DOM manually in browser DevTools")
time.sleep(30)
except Exception as e:
print(f"\n❌ ERROR: {e}")
import traceback
traceback.print_exc()
print(f"\n⏸️ Browser will stay open for 30 seconds for manual inspection...")
time.sleep(30)
finally:
print(f"\n{'='*80}")
print("CLEANUP")
print(f"{'='*80}")
driver.quit()
print("✅ Driver closed")
if __name__ == "__main__":
debug_password_reset_modal()