# pages/base_page.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import TimeoutException import time import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class BasePage: """Basis-Klasse für alle Page Objects""" def __init__(self, driver, wait): self.driver = driver self.wait = wait def wait_for_spa_navigation(self, expected_route_part, timeout=2): """Wartet bis SPA zur erwarteten Route navigiert hat""" WebDriverWait(self.driver, timeout).until( lambda d: expected_route_part in d.current_url ) # Zusätzlich auf Vue-Rendering warten time.sleep(0.5) def wait_for_element(self, by, value, timeout=2): """Wartet auf ein Element""" start_time = time.time() logger.info(f"Waiting for element: {by}={value}") result = WebDriverWait(self.driver, timeout).until( EC.presence_of_element_located((by, value)) ) elapsed = time.time() - start_time logger.info(f"Found element after {elapsed:.2f}s") return result def wait_for_clickable(self, by, value, timeout=2): """Wartet bis Element klickbar ist""" return WebDriverWait(self.driver, timeout).until( EC.element_to_be_clickable((by, value)) ) def fill_input(self, by, value, text, check_existence=False, timeout=2): if check_existence: # Prüfe ob Element existiert try: element = WebDriverWait(self.driver, timeout).until( EC.presence_of_element_located((by, value)) ) logger.info(f"Element exists, filling...") except TimeoutException: logger.warning(f"Element does not exist, skipping (check_existence=True)") return False else: # Normaler Modus - erwarte dass Element existiert element = self.wait_for_element(by, value, timeout) # Element existiert - jetzt füllen element.clear() element.send_keys(text) logger.info(f"Filled input with: {text}") return True def click_button(self, by, value): """Klickt einen Button""" start_time = time.time() logger.info(f"Clicking button: {by}={value}") button = self.wait_for_clickable(by, value) button.click() elapsed = time.time() - start_time logger.info(f"Clicked after {elapsed:.2f}s") def set_checkbox(self, by, value, checked, timeout=2): label = self.wait_for_clickable(by, value, timeout) checkbox_input = label.find_element(By.CSS_SELECTOR, "input[type='checkbox']") is_checked = checkbox_input.is_selected() if is_checked != checked: label.click() time.sleep(0.3) def select_dropdown_option(self, by, value, option_text, timeout=10): dropdown_button = self.wait_for_element(by, value, timeout=timeout) try: current_value = dropdown_button.find_element( By.CSS_SELECTOR, "span.dropdown-trigger-text" ).text if current_value == option_text: logger.info(f"Dropdown already has value: {option_text}") return except: pass # Falls kein Text gefunden wurde, öffne das Dropdown dropdown_button.click() logger.info("Opened dropdown") menu = WebDriverWait(self.driver, timeout).until( EC.visibility_of_element_located((By.CSS_SELECTOR, "ul.dropdown-menu")) ) logger.info("Dropdown menu visible") option_xpath = f"//li[contains(@class, 'dropdown-option')][normalize-space(text())='{option_text}']" option = WebDriverWait(self.driver, timeout).until( EC.element_to_be_clickable((By.XPATH, option_xpath)) ) logger.info(f"Clicking option: {option_text}") option.click() time.sleep(0.2) def search_and_select_autosuggest(self, by_or_selector, value_or_search_text, search_text=None, suggestion_selector=".suggestion-item", timeout=2): if search_text is not None: # Fall: (By.CSS_SELECTOR, ".selector", "search_text") search_input = self.wait_for_element(by_or_selector, value_or_search_text, timeout) text_to_search = search_text else: # Fall: (".selector", "search_text") search_input = self.wait_for_element(By.CSS_SELECTOR, by_or_selector, timeout) text_to_search = value_or_search_text search_input.clear() search_input.send_keys(text_to_search) time.sleep(1) suggestion = WebDriverWait(self.driver, timeout).until( EC.element_to_be_clickable((By.CSS_SELECTOR, suggestion_selector)) ) suggestion.click() time.sleep(0.5)