CP_AUTOMATION/pages/domains_page.py
2025-12-12 19:54:54 +05:30

243 lines
10 KiB
Python

"""
Domains Page Object Model
Handles domain listing screen for an assessment.
Scope: domains_page, domain_card, domains_final_feedback
"""
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class DomainsPage(BasePage):
"""Page Object for Domains Page"""
# Locators using data-testid (scope: domains_page)
PAGE_CONTAINER = (By.CSS_SELECTOR, "[data-testid='domains_page__container']")
BACK_BUTTON = (By.CSS_SELECTOR, "[data-testid='domains_page__back_button']")
PAGE_TITLE = (By.CSS_SELECTOR, "[data-testid='domains_page__title']")
PROGRESS_VALUE = (By.CSS_SELECTOR, "[data-testid='domains_page__progress_value']")
# Final feedback modal (scope: domains_final_feedback)
FINAL_FEEDBACK_MODAL = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__modal']")
FINAL_FEEDBACK_MODAL_CONTENT = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__modal__content']")
# Rating (1-5)
FINAL_FEEDBACK_RATING = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__rating']")
FINAL_FEEDBACK_RATING_1 = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__rating_1']")
FINAL_FEEDBACK_RATING_2 = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__rating_2']")
FINAL_FEEDBACK_RATING_3 = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__rating_3']")
FINAL_FEEDBACK_RATING_4 = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__rating_4']")
FINAL_FEEDBACK_RATING_5 = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__rating_5']")
# Clarity question
FINAL_FEEDBACK_CLARITY = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__clarity']")
FINAL_FEEDBACK_CLARITY_YES = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__clarity_yes']")
FINAL_FEEDBACK_CLARITY_NO = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__clarity_no']")
FINAL_FEEDBACK_CLARITY_JUSTIFICATION = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__clarity_justification']")
# Confidence question
FINAL_FEEDBACK_CONFIDENCE = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__confidence']")
FINAL_FEEDBACK_CONFIDENCE_YES = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__confidence_yes']")
FINAL_FEEDBACK_CONFIDENCE_NO = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__confidence_no']")
FINAL_FEEDBACK_CONFIDENCE_JUSTIFICATION = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__confidence_justification']")
# Comments
FINAL_FEEDBACK_COMMENTS = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__comments']")
FINAL_FEEDBACK_COMMENTS_TEXTAREA = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__comments_textarea']")
# Submit button
FINAL_FEEDBACK_SUBMIT_BUTTON = (By.CSS_SELECTOR, "[data-testid='domains_final_feedback__submit_button']")
def __init__(self, driver):
"""Initialize Domains Page"""
super().__init__(driver)
def wait_for_page_load(self):
"""Wait for domains page to load"""
super().wait_for_page_load() # Call parent method
# Wait for back button to be visible
self.wait.wait_for_element_visible(self.BACK_BUTTON)
def click_back(self):
"""Click back button - returns to assessments page"""
self.click_element(self.BACK_BUTTON)
self.wait.wait_for_url_contains("/assessments")
def get_overall_progress(self):
"""
Get overall progress value
Returns:
str: Progress value
"""
try:
return self.get_text(self.PROGRESS_VALUE)
except:
return "0%"
def get_domain_card(self, domain_id):
"""
Get domain card element by domain ID
Args:
domain_id: Domain ID
Returns:
WebElement: Domain card element
"""
card_locator = (By.CSS_SELECTOR, f"[data-testid='domain_card__{domain_id}']")
return self.find_element(card_locator)
def click_domain_action(self, domain_id):
"""
Click Start/Continue button for a domain
Args:
domain_id: Domain ID
"""
action_locator = (By.CSS_SELECTOR, f"[data-testid='domain_card__{domain_id}__action']")
self.click_element(action_locator)
# Wait for navigation to domain assessment
# URL pattern: /assessment/{assignmentId}/domain/{domainId}
# Wait for either pattern
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from config.config import EXPLICIT_WAIT
try:
# Wait for /domain/ in URL (up to 15 seconds)
WebDriverWait(self.driver, 15).until(
lambda d: "/domain/" in d.current_url
)
except:
# Fallback: check if we're on assessment page (instructions modal might be showing)
try:
WebDriverWait(self.driver, 5).until(
lambda d: "/assessment/" in d.current_url
)
# If we're on assessment page, that's also valid (instructions modal state)
current_url = self.driver.current_url
if "/assessment/" in current_url:
return # Navigation successful, even if domain ID not in URL yet
except:
pass
# If still not navigated, check current URL one more time
current_url = self.driver.current_url
if "/assessment/" in current_url or "/domain/" in current_url:
return # Navigation successful
raise Exception(f"Navigation failed. Current URL: {current_url}")
def click_start_domain(self, domain_id):
"""Alias for click_domain_action"""
self.click_domain_action(domain_id)
def is_domain_locked(self, domain_id):
"""
Check if domain is locked
Args:
domain_id: Domain ID
Returns:
bool: True if domain is locked
"""
try:
card = self.get_domain_card(domain_id)
action = self.driver.find_element(By.CSS_SELECTOR, f"[data-testid='domain_card__{domain_id}__action']")
# Check if action button is disabled or has "locked" text
return action.get_attribute("disabled") is not None or "locked" in action.text.lower()
except:
return True
def is_domain_unlocked(self, domain_id):
"""
Check if domain is unlocked (opposite of is_domain_locked)
Args:
domain_id: Domain ID
Returns:
bool: True if domain is unlocked
"""
return not self.is_domain_locked(domain_id)
def get_all_domain_ids(self):
"""
Get all domain IDs from cards on the page
Returns:
list: List of domain IDs
"""
import re
cards = self.driver.find_elements(By.CSS_SELECTOR, "[data-testid^='domain_card__']")
ids = []
for card in cards:
test_id = card.get_attribute("data-testid")
if test_id:
match = re.search(r'domain_card__(\d+)', test_id)
if match:
ids.append(match.group(1))
return list(set(ids))
def is_final_feedback_modal_present(self):
"""
Check if final feedback modal is present (after all domains completed)
Returns:
bool: True if modal is visible
"""
try:
return self.is_element_visible(self.FINAL_FEEDBACK_MODAL, timeout=5)
except:
return False
def fill_final_feedback(self, rating=5, clarity=True, clarity_justification="",
confidence=True, confidence_justification="", comments=""):
"""
Fill and submit final feedback form
Args:
rating: Overall rating (1-5)
clarity: Answer to clarity question (True/False)
clarity_justification: Justification for clarity (required if clarity=False)
confidence: Answer to confidence question (True/False)
confidence_justification: Justification for confidence (required if confidence=False)
comments: Additional comments text
"""
if not self.is_final_feedback_modal_present():
raise Exception("Final feedback modal is not present")
# Select overall rating
rating_locator = getattr(self, f"FINAL_FEEDBACK_RATING_{rating}")
self.click_element(rating_locator)
# Answer clarity question
if clarity:
self.click_element(self.FINAL_FEEDBACK_CLARITY_YES)
else:
self.click_element(self.FINAL_FEEDBACK_CLARITY_NO)
if clarity_justification:
# Wait for justification textarea to appear
self.wait.wait_for_element_visible(self.FINAL_FEEDBACK_CLARITY_JUSTIFICATION, timeout=3)
self.send_keys(self.FINAL_FEEDBACK_CLARITY_JUSTIFICATION, clarity_justification)
# Answer confidence question
if confidence:
self.click_element(self.FINAL_FEEDBACK_CONFIDENCE_YES)
else:
self.click_element(self.FINAL_FEEDBACK_CONFIDENCE_NO)
if confidence_justification:
# Wait for justification textarea to appear
self.wait.wait_for_element_visible(self.FINAL_FEEDBACK_CONFIDENCE_JUSTIFICATION, timeout=3)
self.send_keys(self.FINAL_FEEDBACK_CONFIDENCE_JUSTIFICATION, confidence_justification)
# Fill comments
if comments:
self.send_keys(self.FINAL_FEEDBACK_COMMENTS_TEXTAREA, comments)
# Submit
self.click_element(self.FINAL_FEEDBACK_SUBMIT_BUTTON)
# Wait for modal to close
self.wait.wait_for_element_invisible(self.FINAL_FEEDBACK_MODAL, timeout=10)