CP_AUTOMATION/pages/domain_assessment_page.py
2025-12-15 17:30:28 +05:30

451 lines
18 KiB
Python

"""
Domain Assessment Page Object Model
Handles in-progress domain test experience.
Scope: domain_assessment, domain_question
"""
import time
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class DomainAssessmentPage(BasePage):
"""Page Object for Domain Assessment Page"""
# Locators using data-testid (scope: domain_assessment)
PAGE = (By.CSS_SELECTOR, "[data-testid='domain_assessment__page']")
BACK_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__back_button']")
PROGRESS_VALUE = (By.CSS_SELECTOR, "[data-testid='domain_assessment__progress_value']")
TIMER_VALUE = (By.CSS_SELECTOR, "[data-testid='domain_assessment__timer_value']")
# Navigation buttons
PREV_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__prev_button']")
NEXT_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__next_button']")
SUBMIT_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__submit_button']")
# Modals
INSTRUCTIONS_MODAL = (By.CSS_SELECTOR, "[data-testid='domain_assessment__instructions_modal']")
INSTRUCTIONS_MODAL_CONTENT = (By.CSS_SELECTOR, "[data-testid='domain_assessment__instructions_modal__content']")
INSTRUCTIONS_CONTINUE_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__instructions_modal__continue_button']")
SUBMIT_MODAL = (By.CSS_SELECTOR, "[data-testid='domain_assessment__submit_modal']")
SUBMIT_MODAL_CONTENT = (By.CSS_SELECTOR, "[data-testid='domain_assessment__submit_modal__content']")
SUBMIT_MODAL_REVIEW_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__submit_modal__review_button']")
SUBMIT_MODAL_CONFIRM_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__submit_modal__confirm_button']")
SUBMIT_MODAL_CANCEL_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__submit_modal__cancel_button']")
GUIDANCE_MODAL = (By.CSS_SELECTOR, "[data-testid='domain_assessment__guidance_modal']")
GUIDANCE_MODAL_CONTENT = (By.CSS_SELECTOR, "[data-testid='domain_assessment__guidance_modal__content']")
GUIDANCE_DISMISS_BUTTON = (By.CSS_SELECTOR, "[data-testid='domain_assessment__guidance_modal__dismiss_button']")
SUCCESS_MODAL = (By.CSS_SELECTOR, "[data-testid='domain_assessment__success_modal']")
SUCCESS_MODAL_CONTENT = (By.CSS_SELECTOR, "[data-testid='domain_assessment__success_modal__content']")
SUCCESS_MODAL_MESSAGE = (By.CSS_SELECTOR, "[data-testid='domain_assessment__success_modal__message']")
# Action bar
ACTION_BAR = (By.CSS_SELECTOR, "[data-testid='domain_assessment__action_bar']")
def __init__(self, driver):
"""Initialize Domain Assessment Page"""
super().__init__(driver)
def wait_for_page_load(self):
"""Wait for domain assessment page to load"""
super().wait_for_page_load() # Call parent method
# Wait for either the page container OR instructions modal (both indicate page loaded)
try:
# First check if instructions modal is present (that's also a valid state)
if self.is_instructions_modal_present():
return # Page loaded, instructions modal showing
# Otherwise wait for the actual page
self.wait.wait_for_element_visible(self.PAGE, timeout=15)
return # Page element found
except:
# If page not found, check if instructions modal is there
try:
if self.is_instructions_modal_present():
return # Instructions modal is present, page is loaded
except:
pass
# If neither found, try waiting for action bar or header as fallback
try:
self.wait.wait_for_element_visible(self.ACTION_BAR, timeout=5)
return # Action bar found, page is loaded
except:
pass
# Try to find a question element (if questions are visible, page is loaded)
try:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(self.driver, 5).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "[data-testid^='domain_question__']"))
)
return # Questions found, page is loaded
except:
pass
# Last resort: try back button (but don't fail if not found)
try:
self.wait.wait_for_element_visible(self.BACK_BUTTON, timeout=3)
return # Back button found, page is loaded
except:
pass
# Final check: if URL is correct, consider page loaded (even if elements not found yet)
current_url = self.driver.current_url
if "/assessment/" in current_url and "/domain/" in current_url:
# URL indicates we're on the right page - give it a moment and return
import time
time.sleep(1) # Brief wait for elements to appear
return # URL indicates we're on the right page
# If we get here, page might still be loading - don't raise exception
# Let the caller handle it or wait longer
pass
def click_back(self):
"""Click back button - returns to domains page"""
self.click_element(self.BACK_BUTTON)
self.wait.wait_for_url_contains("/domains")
def get_progress(self):
"""Get current progress value"""
try:
return self.get_text(self.PROGRESS_VALUE)
except:
return "0"
def get_timer_value(self):
"""Get timer value"""
try:
return self.get_text(self.TIMER_VALUE)
except:
return ""
def get_current_question_id(self):
"""
Get current question ID from URL or page
Returns:
str: Question ID or None
"""
import re
current_url = self.driver.current_url
match = re.search(r'/question/(\d+)', current_url)
if match:
return match.group(1)
return None
def get_question_element(self, question_id):
"""
Get question shell element
Args:
question_id: Question ID
Returns:
WebElement: Question element
"""
question_locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}']")
return self.find_element(question_locator)
def get_question_text(self, question_id):
"""Get question text"""
text_locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__text']")
return self.get_text(text_locator)
def answer_multiple_choice(self, question_id, option_label):
"""
Answer multiple choice question
Args:
question_id: Question ID
option_label: Option label (a, b, c, etc.)
"""
option_locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__option_{option_label}']")
self.click_element(option_locator)
def answer_true_false(self, question_id, value):
"""
Answer true/false question
Args:
question_id: Question ID
value: True or False (boolean or string "True"/"False")
"""
# Convert boolean to string if needed
if isinstance(value, bool):
value_str = "True" if value else "False"
else:
value_str = str(value)
if value_str.lower() in ['true', 'yes']:
value_str = "True"
elif value_str.lower() in ['false', 'no']:
value_str = "False"
tf_locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__truefalse_{value_str}']")
self.click_element(tf_locator)
def answer_rating_scale(self, question_id, score):
"""
Answer rating scale question
Args:
question_id: Question ID
score: Rating score (1-5, etc.)
"""
rating_locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__rating_{score}']")
self.click_element(rating_locator)
def answer_rating(self, question_id, score):
"""Alias for answer_rating_scale"""
self.answer_rating_scale(question_id, score)
def answer_open_ended(self, question_id, text):
"""
Answer open-ended question
Args:
question_id: Question ID
text: Answer text
"""
textarea_locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__textarea']")
self.send_keys(textarea_locator, text)
def answer_matrix(self, question_id, row_index, column_index):
"""
Answer matrix question
Args:
question_id: Question ID
row_index: Row index
column_index: Column index
"""
matrix_locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__matrix_{row_index}_{column_index}']")
self.click_element(matrix_locator)
def click_previous(self):
"""Click Previous button"""
self.click_element(self.PREV_BUTTON)
# Wait for previous question to load
self.wait_for_page_load()
def click_next(self):
"""Click Next button"""
self.click_element(self.NEXT_BUTTON)
# Wait for next question to load
self.wait_for_page_load()
def click_submit(self):
"""Click Submit button - opens submit confirmation modal"""
self.click_element(self.SUBMIT_BUTTON)
# Wait for submit modal
self.wait.wait_for_element_visible(self.SUBMIT_MODAL)
def confirm_submit(self):
"""Confirm submission - clicks confirm in submit modal"""
self.click_element(self.SUBMIT_MODAL_CONFIRM_BUTTON)
# Wait for success modal
self.wait.wait_for_element_visible(self.SUCCESS_MODAL)
def review_before_submit(self):
"""Click review button in submit modal"""
self.click_element(self.SUBMIT_MODAL_REVIEW_BUTTON)
# Modal closes, back to questions
def dismiss_guidance(self):
"""Dismiss guidance modal if present"""
try:
if self.is_element_visible(self.GUIDANCE_MODAL, timeout=2):
self.click_element(self.GUIDANCE_DISMISS_BUTTON)
# Wait for modal to close
self.wait.wait_for_element_invisible(self.GUIDANCE_MODAL, timeout=5)
except:
pass
def is_instructions_modal_present(self):
"""Check if instructions modal is present"""
try:
return self.is_element_visible(self.INSTRUCTIONS_MODAL, timeout=3)
except:
return False
def dismiss_instructions_modal(self):
"""Dismiss instructions modal by clicking continue button"""
try:
if self.is_instructions_modal_present():
self.click_element(self.INSTRUCTIONS_CONTINUE_BUTTON)
# Wait for modal to close
self.wait.wait_for_element_invisible(self.INSTRUCTIONS_MODAL, timeout=5)
except:
pass
def wait_for_success_modal(self):
"""Wait for success modal after submission"""
self.wait.wait_for_element_visible(self.SUCCESS_MODAL)
def is_submit_modal_present(self):
"""Check if submit confirmation modal is present"""
try:
return self.is_element_visible(self.SUBMIT_MODAL, timeout=3)
except:
return False
def is_success_modal_present(self):
"""Check if success modal is present"""
try:
return self.is_element_visible(self.SUCCESS_MODAL, timeout=5)
except:
return False
def close_success_modal(self):
"""Close success modal if present"""
try:
# Success modal usually auto-closes or redirects
# Wait for it to disappear (no fixed sleep needed)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from config.config import SHORT_WAIT
WebDriverWait(self.driver, SHORT_WAIT).until(
EC.invisibility_of_element_located(self.SUCCESS_MODAL)
)
except:
# Modal might have already closed or redirected
pass
def is_next_button_visible(self):
"""Check if next button is visible and enabled"""
try:
next_btn = self.find_element(self.NEXT_BUTTON)
return next_btn.is_displayed() and next_btn.is_enabled()
except:
return False
def is_submit_button_visible(self):
"""Check if submit button is visible and enabled"""
try:
submit_btn = self.find_element(self.SUBMIT_BUTTON)
return submit_btn.is_displayed() and submit_btn.is_enabled()
except:
return False
def get_all_questions(self):
"""
Get all question IDs on current page
Returns:
list: List of question IDs
"""
import re
questions = self.driver.find_elements(By.CSS_SELECTOR, "[data-testid^='domain_question__']")
question_ids = []
for question in questions:
test_id = question.get_attribute("data-testid")
if test_id:
match = re.search(r'domain_question__(\d+)', test_id)
if match:
q_id = match.group(1)
if q_id not in question_ids:
question_ids.append(q_id)
return question_ids
def get_question_type(self, question_id):
"""
Determine question type by checking available answer options
Args:
question_id: Question ID
Returns:
str: Question type (multiple_choice, true_false, rating_scale, open_ended, matrix)
"""
try:
# Check for multiple choice options (A, B, C, D, E)
if self.is_element_present((By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__option_A']"), timeout=1):
return "multiple_choice"
# Check for true/false
if self.is_element_present((By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__truefalse_True']"), timeout=1):
return "true_false"
# Check for rating scale
if self.is_element_present((By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__rating_1']"), timeout=1):
return "rating_scale"
# Check for open ended
if self.is_element_present((By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__textarea']"), timeout=1):
return "open_ended"
# Check for matrix
if self.is_element_present((By.CSS_SELECTOR, f"[data-testid^='domain_question__{question_id}__matrix_']"), timeout=1):
return "matrix"
return "unknown"
except:
return "unknown"
def get_question_options(self, question_id):
"""
Get available options for multiple choice question
Args:
question_id: Question ID
Returns:
list: List of option labels (a, b, c, etc.)
"""
import re
options = self.driver.find_elements(By.CSS_SELECTOR, f"[data-testid^='domain_question__{question_id}__option_']")
option_labels = []
for option in options:
test_id = option.get_attribute("data-testid")
if test_id:
match = re.search(r'option_([a-z0-9]+)', test_id)
if match:
option_labels.append(match.group(1))
return option_labels
def select_option(self, question_id, option_label):
"""Select an option for multiple choice question"""
self.answer_multiple_choice(question_id, option_label)
def select_true_false(self, question_id, value):
"""Select true/false value"""
self.answer_true_false(question_id, value)
def select_rating(self, question_id, score):
"""Select rating score"""
self.answer_rating(question_id, score)
def enter_open_ended(self, question_id, text):
"""Enter text for open-ended question"""
self.answer_open_ended(question_id, text)
def select_matrix_cell(self, question_id, row_index, column_index, value=True):
"""Select matrix cell"""
self.answer_matrix(question_id, row_index, column_index)
def get_matrix_dimensions(self, question_id):
"""
Get matrix dimensions
Returns:
tuple: (rows, cols)
"""
import re
matrix_cells = self.driver.find_elements(By.CSS_SELECTOR, f"[data-testid^='domain_question__{question_id}__matrix_']")
rows = set()
cols = set()
for cell in matrix_cells:
test_id = cell.get_attribute("data-testid")
if test_id:
match = re.search(r'matrix_(\d+)_(\d+)', test_id)
if match:
rows.add(int(match.group(1)))
cols.add(int(match.group(2)))
return (len(rows) if rows else 0, len(cols) if cols else 0)