Source code for univention.testing.selenium.udm

#!/usr/bin/python3
#
# Selenium Tests
#
# SPDX-FileCopyrightText: 2017-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only


import time
from collections.abc import Mapping
from typing import Any

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

import univention.testing.strings as uts
import univention.testing.ucr as ucr_test
from univention.admin import localization


translator = localization.translation('ucs-test-framework')
_ = translator.translate


[docs] class UDMBase: name = None def __init__(self, selenium: Any) -> None: self.selenium = selenium def _get_search_value(self, objectname: Any) -> str: return objectname def _get_grid_value(self, objectname: Any) -> str: return objectname
[docs] def exists(self, objectname: str) -> bool: print('*** check if object exists', objectname) # This method will work with *most* UDM modules. self.search(self._get_search_value(objectname)) time.sleep(5) self.selenium.wait_until_all_standby_animations_disappeared() try: self.selenium.wait_for_text(self._get_grid_value(objectname), timeout=1) return True except TimeoutException: pass return False
[docs] def open_module(self): self.selenium.open_module(self.name)
[docs] def open_details(self, objectname: str) -> None: print('*** open detail page of object', objectname) # This method will work with *most* UDM modules. self.search(self._get_search_value(objectname)) self.selenium.click_grid_entry(self._get_grid_value(objectname)) self.selenium.wait_until_standby_animation_appears_and_disappears()
[docs] def close_details(self) -> None: print('*** close the detailpage') self.selenium.click_button(_('Back')) self.wait_for_main_grid_load()
[docs] def save_details(self) -> None: print('*** save the detailpage') self.selenium.click_button(_('Save')) self.wait_for_main_grid_load()
[docs] def delete(self, objectname: str) -> None: print('*** remove the object with name=', objectname) # This method will work with *most* UDM modules. self.search(self._get_search_value(objectname)) self.selenium.click_checkbox_of_grid_entry(self._get_grid_value(objectname)) self.selenium.click_button(_('Delete')) self.selenium.wait_for_text(_("Please confirm the removal")) self.selenium.click_element( '//div[contains(concat(" ", normalize-space(@class), " "), " dijitDialog ")]' '//*[contains(concat(" ", normalize-space(@class), " "), " dijitButtonText ")]' '[text() = "%s"]' % (_("Delete"),), )
# FIXME: this waits forever and let's the test fail when no grid entries exists. # self.wait_for_main_grid_load()
[docs] def search(self, objectname: str) -> None: print('*** searching for objects with name=', objectname) # This method will work with *most* UDM modules. xpath = '//input[@name="objectPropertyValue"]' elems = webdriver.support.ui.WebDriverWait(xpath, 60).until( self.selenium.get_all_enabled_elements, ) elems[0].clear() elems[0].send_keys(objectname) elems[0].send_keys(Keys.RETURN) self.wait_for_main_grid_load() elems[0].clear()
[docs] def wait_for_main_grid_load(self, timeout: int = 60) -> None: print('*** waiting for main grid load') self.selenium.wait_until_standby_animation_appears_and_disappears()
[docs] def open_add_dialog(self, container: str | None = None, template: str | None = None) -> None: print('*** open the add dialog') self.selenium.click_button(_('Add')) self.selenium.wait_until_all_standby_animations_disappeared() try: self.selenium.wait_for_text(_('This UCS system is part of an Active Directory domain'), timeout=1) except TimeoutException: pass else: self.selenium.click_button(_('Next')) # FIXME: clicking Next on the page with the active directory warning # cuts the dialog in half and the dom elements are not clickable/visible. # This is a workaround dialogs = self.selenium.driver.find_elements(By.CLASS_NAME, 'umcUdmNewObjectDialog') if len(dialogs): self.selenium.driver.execute_script('dijit.byId("%s")._position()' % (dialogs[0].get_attribute('widgetid'))) click_next = False try: self.selenium.wait_for_text(_('Container'), timeout=1) click_next = True except TimeoutException: pass # FIXME: select the given container try: self.selenium.wait_for_text(_("User template"), timeout=1) click_next = True except TimeoutException: pass if template is not None: self.selenium.enter_input_combobox('objectTemplate', template) if click_next: self.selenium.click_button(_('Next')) self.selenium.wait_until_all_standby_animations_disappeared()
[docs] def open_advanced_add_dialog(self, **kwargs: Any) -> None: self.open_add_dialog(**kwargs) self.selenium.click_button(_('Advanced'))
[docs] class Portals(UDMBase): name = _('Portal settings') def __init__(self, selenium: Any) -> None: super().__init__(selenium) self.ucr = ucr_test.UCSTestConfigRegistry() self.ucr.load()
[docs] def add(self, portalname: str | None = None, hostname: str | None = None) -> str: if portalname is None: portalname = uts.random_string() self.open_add_dialog() # FIXME: add this to the open_add_dialog() function self.selenium.enter_input_combobox('objectType', 'Portal: Portal') self.selenium.wait_until_standby_animation_appears_and_disappears() self.selenium.click_button('Next') self.selenium.wait_until_standby_animation_appears_and_disappears() self.selenium.enter_input("name", portalname) self.selenium.enter_input_combobox('__displayName-0-0', 'en_US', with_click=False) self.selenium.enter_input('__displayName-0-1', uts.random_string()) if hostname is not None: self.selenium.enter_input_combobox('__portalComputers-0-0', hostname) self.selenium.click_button(_("Create portal")) self.wait_for_main_grid_load() return portalname
[docs] class Computers(UDMBase): name = _('Computers')
[docs] def add(self, computername: str | None = None) -> str: if computername is None: computername = uts.random_string() self.open_add_dialog() self.selenium.enter_input("name", computername) self.selenium.click_button(_("Create computer")) self.selenium.wait_for_text(_('has been created')) self.selenium.click_button(_('Cancel')) self.selenium.wait_until_all_dialogues_closed() return computername
[docs] class Groups(UDMBase): name = _("Groups")
[docs] def add(self, groupname: str | None = None) -> str: if groupname is None: groupname = uts.random_string() self.open_add_dialog() self.selenium.wait_for_text(_("Members of this group")) self.selenium.enter_input("name", groupname) self.selenium.click_button(_("Create group")) self.wait_for_main_grid_load() return groupname
[docs] class Policies(UDMBase): name = _('Policies')
[docs] def add(self, policyname: str | None = None) -> str: if policyname is None: policyname = uts.random_string() self.open_add_dialog() self.selenium.enter_input("name", policyname) self.selenium.click_button(_("Create policy")) self.wait_for_main_grid_load() return policyname
# fails in 4.4-0, Bug #48998 # def open_details(self, objectname): # self.search(self._get_search_value(objectname)) # self.selenium.click_grid_entry(self._get_grid_value(objectname)) # self.selenium.wait_for_text(_('Advanced settings'))
[docs] class Users(UDMBase): name = _("Users") def __init__(self, selenium: Any) -> None: super().__init__(selenium) self.ucr = ucr_test.UCSTestConfigRegistry() self.ucr.load()
[docs] def get_description(self) -> str: xpath = '//input[@name="description"]' elems = webdriver.support.ui.WebDriverWait(xpath, 60).until( self.selenium.get_all_enabled_elements, ) return elems[0].get_attribute('value')
[docs] def get_primary_mail(self) -> str: xpath = '//input[@name="mailPrimaryAddress"]' elems = webdriver.support.ui.WebDriverWait(xpath, 60).until( self.selenium.get_all_enabled_elements, ) return elems[0].get_attribute('value')
[docs] def add( self, template: str | None = None, firstname: str = '', lastname: str | None = None, username: str | None = None, password: str = 'univention', ) -> dict[str, str]: if username is None: username = uts.random_string() if lastname is None: lastname = uts.random_string() self.open_add_dialog(template=template) self.selenium.wait_for_text(_("First name")) self.selenium.enter_input("firstname", firstname) self.selenium.enter_input("lastname", lastname) self.selenium.enter_input("username", username) self.selenium.click_button(_("Next")) self.selenium.wait_for_text(_("Password")) self.selenium.enter_input("password_1", password) self.selenium.enter_input("password_2", password) self.selenium.click_button(_("Create user")) self.selenium.wait_for_text(_('has been created')) self.selenium.click_button(_('Cancel')) self.selenium.wait_until_all_dialogues_closed() return {'username': username, 'lastname': lastname}
[docs] def copy(self, user, username='', lastname='', password='univention', **kwargs): username = username or uts.random_string() self.search(user) self.selenium.click_checkbox_of_grid_entry(user) self.selenium.click_text(_('more')) self.selenium.click_text(_('Copy')) try: self.selenium.wait_for_any_text_in_list(['Container', 'Template'], timeout=5) self.selenium.click_button('Next') except TimeoutException: pass finally: self.selenium.wait_until_standby_animation_appears_and_disappears() self.selenium.enter_input('username', username) self.selenium.enter_input('lastname', lastname or uts.random_string()) self.selenium.enter_input('password_1', password) self.selenium.enter_input('password_2', password) for key, value in kwargs.items(): self.selenium.enter_input(key, value) self.selenium.click_text(_('Create user')) self.selenium.wait_until_standby_animation_appears_and_disappears() # TODO: check for error return username
def _get_search_value(self, user: Mapping[str, str]) -> str: return user['username'] def _get_grid_value(self, user: Mapping[str, str]) -> str: return user['lastname'] if self.ucr.get('ad/member') else user['username']