#!/usr/bin/python3
#
# Selenium Tests
#
# SPDX-FileCopyrightText: 2017-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only
import logging
from collections.abc import Callable, Iterable
from typing import Any
import selenium.common.exceptions as selenium_exceptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
from univention.testing.selenium.utils import expand_path
logger = logging.getLogger(__name__)
[docs]
class ChecksAndWaits:
[docs]
def wait_for_text(self, text: str, timeout: int = 60) -> None:
logger.info("Waiting for text: %r", text)
xpath = f'//*[contains(text(), "{text}")]'
WebDriverWait([xpath], timeout).until(
self.get_all_visible_elements, f'waited {timeout} seconds for text {text!r}',
)
[docs]
def wait_for_any_text_in_list(self, texts: Iterable[str], timeout: int = 60) -> None:
logger.info("Waiting until any of those texts is visible: %r", texts)
xpaths = [f'//*[contains(text(), "{text}")]' for text in texts]
WebDriverWait(xpaths, timeout).until(
self.get_all_visible_elements, f'waited {timeout} seconds for texts {texts!r}',
)
[docs]
def wait_for_text_to_disappear(self, text: Any, timeout: int = 60) -> None:
xpath = f'//*[contains(text(), "{text}")]'
WebDriverWait(xpath, timeout).until(
self.elements_invisible, f'waited {timeout} seconds for text {text!r} to disappear',
)
[docs]
def wait_until_all_dialogues_closed(self) -> None:
logger.info("Waiting for all dialogues to close.")
xpath = '//*[contains(concat(" ", normalize-space(@class), " "), " dijitDialogUnderlay ")]'
WebDriverWait(xpath, timeout=60).until(
self.elements_invisible, 'wait_until_all_dialogues_closed() timeout=60',
)
[docs]
def wait_until_all_standby_animations_disappeared(self, timeout: int = 60) -> None:
logger.info("Waiting for all standby animations to disappear.")
xpath = expand_path('//*[contains(@id, "_Standby_")]//*[@containsClass="umcStandbySvgWrapper"]')
WebDriverWait(xpath, timeout).until(
self.elements_invisible, f'wait_until_all_standby_animations_disappeared(timeout={timeout!r})',
)
[docs]
def wait_until_standby_animation_appears(self, timeout: int = 5) -> None:
logger.info("Waiting for standby animation to appear.")
xpath = expand_path('//*[contains(@id, "_Standby_")]//*[@containsClass="umcStandbySvgWrapper"]')
try:
WebDriverWait(xpath, timeout).until(
self.elements_visible, f'wait_until_standby_animation_appears(timeout={timeout!r})',
)
except selenium_exceptions.TimeoutException:
logger.info("No standby animation appeared during timeout. Ignoring")
else:
logger.info("Found standby animation")
[docs]
def wait_until_standby_animation_appears_and_disappears(self, appear_timeout: int = 5, disappear_timeout: int = 60) -> None:
self.wait_until_standby_animation_appears(timeout=appear_timeout)
self.wait_until_all_standby_animations_disappeared(timeout=disappear_timeout)
[docs]
def wait_until_progress_bar_finishes(self, timeout: int = 300) -> None:
logger.info("Waiting for all progress bars to disappear.")
xpath = '//*[contains(concat(" ", normalize-space(@class), " "), " umcProgressBar ")]'
WebDriverWait(xpath, timeout=timeout).until(
self.elements_invisible, f'waited {timeout} seconds for progress bar',
)
[docs]
def wait_until_element_visible(self, xpath: str, timeout: int = 60) -> None:
logger.info("Waiting for the element with the xpath %r to be visible.", xpath)
self.wait_until(
expected_conditions.visibility_of_element_located(
(By.XPATH, xpath),
),
timeout=timeout,
)
[docs]
def wait_until(self, check_function: Callable[..., Any], timeout: int = 60) -> None:
WebDriverWait(self.driver, timeout).until(
check_function, f'wait_until({check_function!r}, timeout={timeout!r})',
)
[docs]
def get_gallery_items(self) -> list[str]:
items = self.get_all_visible_elements(['//div[contains(concat(" ", normalize-space(@class), " "), " umcGalleryName ")]'])
return [item.text for item in items]
[docs]
def get_all_visible_elements(self, xpaths: Iterable[str]) -> list[Any]:
try:
return [
elem
for xpath in xpaths
for elem in self.driver.find_elements(By.XPATH, xpath)
if elem.is_displayed()
]
except selenium_exceptions.StaleElementReferenceException:
pass
return []
[docs]
def elements_invisible(self, xpath: Iterable[str]) -> bool:
elems = self.driver.find_elements(By.XPATH, xpath)
try:
return all(not elem.is_displayed() for elem in elems)
except selenium_exceptions.StaleElementReferenceException:
pass
return False
[docs]
def elements_visible(self, xpath: Iterable[str]) -> bool:
elems = self.driver.find_elements(By.XPATH, xpath)
try:
return any(elem.is_displayed() for elem in elems)
except selenium_exceptions.StaleElementReferenceException:
pass
return False
[docs]
def wait_for_element_by_css_selector(self, css_selector: str, message: str = '', timeout: int = 60) -> Any:
return WebDriverWait(self.driver, timeout).until(
expected_conditions.presence_of_element_located((By.CSS_SELECTOR, css_selector)),
message,
)