diff --git a/components/dropdown_list_component.py b/components/dropdown_list_component.py index 92a84cf..160aa47 100644 --- a/components/dropdown_list_component.py +++ b/components/dropdown_list_component.py @@ -3,8 +3,8 @@ Класс DropdownList наследует базовый функционал BaseComponent и добавляет методы для взаимодействия с выпадающими списками на странице. """ - -from playwright.sync_api import Page +import re +from playwright.sync_api import Page, Locator from tools.logger import get_logger from components.base_component import BaseComponent @@ -19,7 +19,7 @@ class DropdownList(BaseComponent): def __init__(self, page: Page): """Инициализирует компонент выпадающего списка. - + Args: page: Экземпляр страницы Playwright. """ @@ -34,7 +34,59 @@ class DropdownList(BaseComponent): text (str): Текст элемента для выбора. """ - self.page.get_by_role("listitem").filter(has_text=text).click() + element = self.page.get_by_role("listitem").filter(has_text=text) + if element.count() > 1: + rtext = f"^{text}$" + element = self.page.get_by_role("listitem").filter(has_text=re.compile(rtext)) + element.click() + + def get_item_names(self, locator: str | Locator) -> list[str]: + """Возвращает тексты всех элементов по указанному локатору. + + Args: + locator: Локатор элементов или строка с CSS/XPath. + + Returns: + Список текстов элементов. + """ + + loc = self.get_locator(locator) + texts = loc.all_inner_texts() + return texts[0].splitlines() + + def scroll_until_end(self, locator: str | Locator) -> None: + """ + Скроллит список до тех пор, пока не перестанут подгружаться новые элементы. + + Args: + locator: Локатор элементов или строка с CSS/XPath. + """ + + loc = self.get_locator(locator) + + items_count = 0 + attempts = 0 + max_attempts = 3 + last_item_name = "" + + while attempts < max_attempts: + self.page.wait_for_timeout(300) + + item_names = self.get_item_names(loc) + current_count = len(item_names) + + if current_count == items_count: + attempts += 1 + else: + items_count = current_count + attempts = 0 + + last_item_name = item_names[current_count-1] + element = self.page.get_by_role("listitem").filter(has_text=last_item_name) + element.scroll_into_view_if_needed() + + self.page.wait_for_timeout(300) + self.check_item_with_text(last_item_name) # Проверки: def check_item_with_text(self, text: str) -> None: @@ -46,7 +98,37 @@ class DropdownList(BaseComponent): Raises: AssertionError: Если элемент отсутствует или недоступен. """ - - enabled = self.page.get_by_role("listitem").filter(has_text=text).is_enabled() + + element = self.page.get_by_role("listitem").filter(has_text=text) + if element.count() > 1: + rtext = f"^{text}$" + element = self.page.get_by_role("listitem").filter(has_text=re.compile(rtext)) + enabled = element.is_enabled() if not enabled: assert False, f"Dropdown list item '{text}' is missing or disabled" + + def check_vertical_scrolling(self, locator: str | Locator) -> bool: + """ + Проверяет функцию вертикального скроллинга списка. + + Args: + locator: Локатор элементов или строка с CSS/XPath. + + Returns: + True или False значение в зависимости от скроллируемый список или нет. + """ + + loc = self.get_locator(locator) + + is_scrollable_vertically = self.is_scrollable_vertically(loc) + if is_scrollable_vertically: + self.scroll_until_end(loc) + + item_names = self.get_item_names(loc) + first_item_name = item_names[0] + + self.scroll_up(loc) + self.page.wait_for_timeout(300) + self.check_item_with_text(first_item_name) + + return is_scrollable_vertically diff --git a/elements/base_element.py b/elements/base_element.py index 72f1659..c71fa1f 100644 --- a/elements/base_element.py +++ b/elements/base_element.py @@ -55,6 +55,12 @@ class BaseElement: logger.info(f"Get text for {self.type_of} '{self.name}'") return self.locator.nth(index).text_content() + def update_locator(self, new_locator: Locator) -> None: + """Меняет значение локатора для элемента""" + + logger.info(f"Update locator for {self.type_of} '{self.name}'") + self.locator = new_locator + def wait_for_element(self, timeout: int = 12000) -> None: """Ожидает появление элемента в течение заданного времени.""" diff --git a/elements/checkbox_element.py b/elements/checkbox_element.py index 8811d1d..7ec6064 100644 --- a/elements/checkbox_element.py +++ b/elements/checkbox_element.py @@ -28,17 +28,23 @@ class Checkbox(BaseElement): return "checkbox" # Действия: - def check(self) -> None: + def check(self, force=False) -> None: """Отмечает чекбокс (устанавливает галочку).""" logger.info(f"Checking checkbox '{self.name}'") - self.locator.check() + if force: + self.locator.check(force=True) + else: + self.locator.check() - def uncheck(self) -> None: + def uncheck(self, force=False) -> None: """Снимает отметку с чекбокса (убирает галочку).""" logger.info(f"Unchecking checkbox '{self.name}'") - self.locator.uncheck() + if force: + self.locator.uncheck(force=True) + else: + self.locator.uncheck() # Проверки: def is_checked(self) -> bool: diff --git a/locators/modal_window_locators.py b/locators/modal_window_locators.py index ddba607..7fade33 100644 --- a/locators/modal_window_locators.py +++ b/locators/modal_window_locators.py @@ -11,10 +11,7 @@ class ModalWindowLocators: MODAL_WINDOW (str): активного модального окна INPUT_FORM_USER_DATA (str): формы ввода пользовательских данных TEXT_FIELD_INPUT_FORM_USER_DATA (str): текстового поля ввода - - ROLES_FIELD_INPUT_FORM_USER_DATA (str): поля выбора ролей - - ROLES_MENU_INPUT_FORM_USER_DATA (str): меню выбора ролей + MENU_INPUT_FORM_USER_DATA (str): меню выбора ролей LABEL_INPUT_FORM_USER_DATA (str): метки поля ввода """ @@ -22,6 +19,5 @@ class ModalWindowLocators: INPUT_FORM_USER_DATA = "//form[@class='v-form']" TEXT_FIELD_INPUT_FORM_USER_DATA = "xpath=div[2]/div/div/div/div/input" - ROLES_FIELD_INPUT_FORM_USER_DATA = "xpath=div[2]/div/div/div/div/div[1]" - ROLES_MENU_INPUT_FORM_USER_DATA = "//div[contains(@class, 'menuable__content__active')]" + MENU_INPUT_FORM_USER_DATA = "//div[contains(@class, 'menuable__content__active')]" LABEL_INPUT_FORM_USER_DATA = "//label[contains(@class,'v-label')]/span" diff --git a/modal_windows/modal_add_AD_user.py b/modal_windows/modal_add_AD_user.py new file mode 100644 index 0000000..b1343f5 --- /dev/null +++ b/modal_windows/modal_add_AD_user.py @@ -0,0 +1,364 @@ +"""Модуль modal_add_user содержит класс для работы с модальным окном добавления пользователя. + +Класс AddUserModalWindow наследует базовый функционал ModalWindowComponent +и реализует специфичные методы для работы с формами добавления пользователей. +""" + +import re +from playwright.sync_api import Page +from tools.logger import get_logger +from locators.modal_window_locators import ModalWindowLocators +from elements.text_input_element import TextInput +from elements.text_element import Text +from elements.checkbox_element import Checkbox +from data.roles_dict import roles_dict +from components.modal_window_component import ModalWindowComponent +from components.dropdown_list_component import DropdownList +from components.confirm_component import ConfirmComponent + + +logger = get_logger("ADD_USER_FROM_ACTIVE_DIRECTORY_MODAL_WINDOW") + + +class AddADUserModalWindow(ModalWindowComponent): + """Модальное окно добавления нового пользователя. + + Наследует ModalWindowComponent и добавляет элементы формы: + - Поля ввода (имя, пароль, email и др.) + - Чекбоксы (Active Directory, Push-уведомления) + - Выпадающие списки групп, пользователей AD, ролей + - Кнопки действий + """ + + def __init__(self, page: Page): + """Инициализирует элементы формы добавления пользователя.""" + + super().__init__(page) + + # Локаторы элементов формы + input_form_locator = page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA) + text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA + label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA + + # Настройка заголовка и кнопки закрытия тулбара + self.window_title = "Добавить нового пользователя" + locator_button_toolbar_close = self.page.get_by_role("navigation").filter( + has_text=re.compile(self.window_title) + ).get_by_role("button") + + self.add_toolbar_title(self.window_title) + self.add_toolbar_button(locator_button_toolbar_close, "close") + + # Добавление элементов формы + checkbox_1 = Checkbox( + page, + self.page.get_by_role("checkbox").nth(0), + "active_directory" + ) + self.add_content_item("active_directory_checkbox", checkbox_1) + + label_1 = Text( + page, + self.page.locator(label_locator).nth(0), + "active_directory_checkbox_label" + ) + self.add_content_item("active_directory_checkbox_label", label_1) + + # Начальный набор полей формы + group_loc = input_form_locator.get_by_role("combobox").nth(0) + group_input = TextInput(page, group_loc, "group_input") + self.add_content_item("group_input", group_input) + self.add_content_item( + "group_list", + DropdownList(page) + ) + + locator_button_search = self.page.get_by_role("button", name="Поиск") + self.add_button(locator_button_search, "search") + + loc = input_form_locator.locator("xpath=div[3]").locator(text_field_locator) + name_input = TextInput(page, loc, "name_input") + self.add_content_item("name_input", name_input) + + role_loc = input_form_locator.get_by_role("combobox").nth(1) + role_input = TextInput(page, role_loc, "role_input") + self.add_content_item("role_input", role_input) + self.add_content_item( + "roles_list", + DropdownList(page) + ) + + loc = input_form_locator.locator("xpath=div[6]").locator(text_field_locator) + commentary_input = TextInput(page, loc, "commentary_input") + self.add_content_item("commentary_input", commentary_input) + + loc = input_form_locator.locator("xpath=div[7]").locator(text_field_locator) + email_input = TextInput(page, loc, "email_input") + self.add_content_item("email_input", email_input) + + loc = input_form_locator.locator("xpath=div[8]").locator(text_field_locator) + phone_input = TextInput(page, loc, "phone_input") + self.add_content_item("phone_input", phone_input) + + checkbox_2 = Checkbox( + page, + page.get_by_role("checkbox").nth(1), + "push_notification" + ) + self.add_content_item("push_notification_checkbox", checkbox_2) + + label_2 = Text( + page, + self.page.locator(label_locator).nth(1), + "push_notification_checkbox_label" + ) + self.add_content_item("push_notification_checkbox_label", label_2) + + # Добавление кнопок действий + locator_button_add = self.page.get_by_role("button", name="Добавить") + self.add_button(locator_button_add, "add") + + locator_button_close = self.page.get_by_role("button", name="Закрыть") + self.add_button(locator_button_close, "close") + + self.new_user_confirm = ConfirmComponent(page, " Отмена ", " Добавить ") + + # Действия: + def check_active_directory_checkbox(self): + """Включает чек-бокс Active Directory. """ + + self.get_content_item("active_directory_checkbox").check(force=True) + + def uncheck_active_directory_checkbox(self): + """Выключает чек-бокс Active Directory. """ + + self.get_content_item("active_directory_checkbox").uncheck(force=True) + + def update_input_form_fields(self, expand): + """Персчитывает локаторы полей формы ввода при добавлении/удалении дополнительного поля. """ + + input_form_locator = self.page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA) + text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA + + if expand: + new_loc = input_form_locator.locator("xpath=div[4]").locator(text_field_locator) + self.get_content_item("name_input").update_locator(new_loc) + + new_loc = input_form_locator.locator("xpath=div[7]").locator(text_field_locator) + self.get_content_item("commentary_input").update_locator(new_loc) + + new_loc = input_form_locator.locator("xpath=div[8]").locator(text_field_locator) + self.get_content_item("email_input").update_locator(new_loc) + + new_loc = input_form_locator.locator("xpath=div[9]").locator(text_field_locator) + self.get_content_item("phone_input").update_locator(new_loc) + + role_loc = input_form_locator.get_by_role("combobox").nth(2) + self.get_content_item("role_input").update_locator(role_loc) + else: + new_loc = input_form_locator.locator("xpath=div[3]").locator(text_field_locator) + self.get_content_item("name_input").update_locator(new_loc) + + new_loc = input_form_locator.locator("xpath=div[6]").locator(text_field_locator) + self.get_content_item("commentary_input").update_locator(new_loc) + + new_loc = input_form_locator.locator("xpath=div[7]").locator(text_field_locator) + self.get_content_item("email_input").update_locator(new_loc) + + new_loc = input_form_locator.locator("xpath=div[8]").locator(text_field_locator) + self.get_content_item("phone_input").update_locator(new_loc) + + role_loc = input_form_locator.get_by_role("combobox").nth(1) + self.get_content_item("role_input").update_locator(role_loc) + + def new_user(self, user_data): + """Заполняет форму и добавляет нового пользователя. + + Args: + user_data (dict): Данные пользователя (имя, роль, пароль и др.) + """ + + menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA) + input_form_locator = self.page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA) + + group_name = user_data.get("group") + if group_name is None: + assert False, "Value of 'group' is missing" + + name = user_data.get("name") + if name is None: + assert False, "Value of 'name' is missing" + + role = user_data.get("role") + if role is None: + assert False, "Value of 'role' is missing" + + group_field = self.get_content_item("group_input") + group_field.click() + + group_list = self.get_content_item("group_list") + group_list.scroll_until_end(menu_locator) + group_names = group_list.get_item_names(menu_locator) + if group_name not in group_names: + assert False, f"Required group name {group_name} is missing" + + group_list.check_item_with_text(group_name) + group_list.click_item_with_text(group_name) + + search_button = self.get_button_by_name("search") + search_button.click() + + count = input_form_locator.get_by_role("combobox").count() + if count == 2: + assert False, f"Selected group {group_name} is empty. Use another group." + + user_AD_loc = input_form_locator.get_by_role("combobox").nth(1) + user_AD_input = TextInput(self.page, user_AD_loc, "user_AD_input") + self.add_content_item("user_AD_input", user_AD_input) + self.add_content_item( + "user_AD_list", + DropdownList(self.page) + ) + + user_AD_input.click() + user_AD_list = self.get_content_item("user_AD_list") + user_AD_list.scroll_until_end(menu_locator) + user_AD_names = group_list.get_item_names(menu_locator) + if name not in user_AD_names: + assert False, f"Required user name {name} is missing" + + user_AD_list.check_item_with_text(name) + user_AD_list.click_item_with_text(name) + + role_field = self.get_content_item("role_input") + role_field.click() + + roles_list = self.get_content_item("roles_list") + roles_list.check_item_with_text(user_data["role"]) + roles_list.click_item_with_text(user_data["role"]) + + # Отправка формы + add_button = self.get_button_by_name("add") + add_button.click() + + # Подтверждение действия + title = "Добавить нового пользователя" + self.new_user_confirm.check_title( + title, + f"Confirmation dialog window with title '{title}' is missing" + ) + + # На первом этапе реального пользователя не создаем + self.new_user_confirm.click_cancel_button() + self.close_window() + + def close_window(self): + """Закрывает модальное окно через кнопку 'Закрыть'.""" + + close_button = self.get_button_by_name("close") + close_button.click() + + def close_window_by_toolbar_button(self): + """Закрывает модальное окно через кнопку в тулбаре.""" + + self.click_toolbar_close_button() + + # Проверки: + def check_content(self): + """Проверяет наличие и корректность всех элементов формы.""" + + input_form_locator = self.page.locator(ModalWindowLocators.INPUT_FORM_USER_DATA) + menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA) + + self.check_by_window_title() + + is_checked = self.get_content_item("active_directory_checkbox").is_checked() + if not is_checked: + assert False, \ + "The checkbox 'Active Directory'should be checked for the add user from Active Directory window" + + self.check_toolbar_button_presence("close") + self.check_toolbar_button_tooltip("close", "Закрыть") + + no_op_names = ["roles_list", "group_list"] + + for name in self.content_items.keys(): + item = self.get_content_item(name) + + if name == "active_directory_checkbox_label": + item.check_have_text( + "Active Directory", + "Label 'Active Directory' is missing" + ) + elif name == "push_notification_checkbox_label": + item.check_have_text( + "Подписка на Push-уведомления", + "Label 'Подписка на Push-уведомления' is missing" + ) + elif name == "group_input": + item.click() + group_list = self.get_content_item("group_list") + group_list.check_presence(menu_locator, + "Groups list is missing") + + is_scrollable_vertically = group_list.check_vertical_scrolling(menu_locator) + assert is_scrollable_vertically, "Groups list should be scrollable_vertically" + self.page.keyboard.press("Escape") + elif name == "role_input": + item.click() + roles_list = self.get_content_item("roles_list") + roles_list.check_presence(menu_locator, + "Roles list is missing") + + is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator) + assert not is_scrollable_vertically, \ + "Roles list should not be scrollable_vertically" + + for role in roles_dict.values(): + # временно, пока есть несоответствие со списком ролей в вкладке Сессии + if role == "Пользователь": + continue + roles_list.check_item_with_text(role) + self.page.keyboard.press("Escape") + elif name in no_op_names: + continue + else: + item.check_presence( + f"Modal window content item with name '{name}' is missing" + ) + + self.check_button_presence("search") + self.check_button_presence("add") + self.check_button_presence("close") + + search_button = self.get_button_by_name("search") + search_button.click() + + user_AD_loc = input_form_locator.get_by_role("combobox").nth(1) + user_AD_input = TextInput(self.page, user_AD_loc, "user_AD_input") + self.add_content_item("user_AD_input", user_AD_input) + self.add_content_item( + "user_AD_list", + DropdownList(self.page) + ) + + user_AD_input.click() + user_AD_list = self.get_content_item("user_AD_list") + user_AD_list.check_presence(menu_locator, + "Users AD list is missing") + is_scrollable_vertically = user_AD_list.check_vertical_scrolling(menu_locator) + assert is_scrollable_vertically, "Users AD list should be scrollable_vertically" + self.page.keyboard.press("Escape") + + self.update_input_form_fields(expand=True) + + self.get_content_item("name_input").check_presence( + "Modal window content item with name 'name_input' is missing") + self.get_content_item("role_input").check_presence( + "Modal window content item with name 'role_input' is missing") + self.get_content_item("commentary_input").check_presence( + "Modal window content item with name 'commentary_input' is missing") + self.get_content_item("email_input").check_presence( + "Modal window content item with name 'email_input' is missing") + self.get_content_item("phone_input").check_presence( + "Modal window content item with name 'phone_input' is missing") diff --git a/modal_windows/modal_add_user.py b/modal_windows/modal_add_local_user.py similarity index 84% rename from modal_windows/modal_add_user.py rename to modal_windows/modal_add_local_user.py index 817d497..5355c80 100644 --- a/modal_windows/modal_add_user.py +++ b/modal_windows/modal_add_local_user.py @@ -1,6 +1,6 @@ -"""Модуль modal_add_user содержит класс для работы с модальным окном добавления пользователя. +"""Модуль modal_add_local_user содержит класс для работы с модальным окном добавления локального пользователя. -Класс AddUserModalWindow наследует базовый функционал ModalWindowComponent +Класс AddLocalUserModalWindow наследует базовый функционал ModalWindowComponent и реализует специфичные методы для работы с формами добавления пользователей. """ @@ -17,10 +17,10 @@ from components.dropdown_list_component import DropdownList from components.confirm_component import ConfirmComponent -logger = get_logger("ADD_USER_MODAL_WINDOW") +logger = get_logger("ADD_LOCAL_USER_MODAL_WINDOW") -class AddUserModalWindow(ModalWindowComponent): +class AddLocalUserModalWindow(ModalWindowComponent): """Модальное окно добавления нового пользователя. Наследует ModalWindowComponent и добавляет элементы формы: @@ -37,7 +37,6 @@ class AddUserModalWindow(ModalWindowComponent): # Локаторы элементов формы text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA - roles_field_locator = ModalWindowLocators.ROLES_FIELD_INPUT_FORM_USER_DATA input_form_locator = ModalWindowLocators.INPUT_FORM_USER_DATA label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA @@ -53,9 +52,10 @@ class AddUserModalWindow(ModalWindowComponent): # Добавление элементов формы checkbox_1 = Checkbox( page, - self.page.get_by_role("checkbox").nth(0), + self.page.locator(input_form_locator).get_by_role("checkbox").nth(0), "active_directory" ) + self.add_content_item("active_directory_checkbox", checkbox_1) label_1 = Text( @@ -69,7 +69,7 @@ class AddUserModalWindow(ModalWindowComponent): name_input = TextInput(page, loc, "name_input") self.add_content_item("name_input", name_input) - role_loc = self.page.locator(input_form_locator).locator("xpath=div[3]").locator(roles_field_locator) + role_loc = self.page.locator(input_form_locator).get_by_role("combobox").nth(0) role_input = TextInput(page, role_loc, "role_input") self.add_content_item("role_input", role_input) self.add_content_item( @@ -95,7 +95,7 @@ class AddUserModalWindow(ModalWindowComponent): checkbox_2 = Checkbox( page, - page.get_by_role("checkbox").nth(1), + self.page.locator(input_form_locator).get_by_role("checkbox").nth(1), "push_notification" ) self.add_content_item("push_notification_checkbox", checkbox_2) @@ -116,6 +116,17 @@ class AddUserModalWindow(ModalWindowComponent): self.new_user_confirm = ConfirmComponent(page, " Отмена ", " Добавить ") + # Действия: + def check_active_directory_checkbox(self): + """Включает чек-бокс Active Directory. """ + + self.get_content_item("active_directory_checkbox").check(force=True) + + def uncheck_active_directory_checkbox(self): + """Выключает чек-бокс Active Directory. """ + + self.get_content_item("active_directory_checkbox").uncheck(force=True) + def new_user(self, user_data): """Заполняет форму и добавляет нового пользователя. @@ -125,13 +136,6 @@ class AddUserModalWindow(ModalWindowComponent): fields = user_data.keys() - if "active_directory_checked" in fields: - checkbox = self.get_content_item("active_directory_checkbox") - if user_data["active_directory_checked"]: - checkbox.check() - else: - checkbox.uncheck() - if "name" in fields: input_field = self.get_content_item("name_input") input_field.input_value(user_data["name"]) @@ -190,11 +194,19 @@ class AddUserModalWindow(ModalWindowComponent): self.click_toolbar_close_button() + # Проверки: def check_content(self): """Проверяет наличие и корректность всех элементов формы.""" + menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA) + self.check_by_window_title() + is_checked = self.get_content_item("active_directory_checkbox").is_checked() + if is_checked: + assert False, \ + "The checkbox 'Active Directory'should not be checked for the add local user window" + self.check_toolbar_button_presence("close") self.check_toolbar_button_tooltip("close", "Закрыть") @@ -214,9 +226,13 @@ class AddUserModalWindow(ModalWindowComponent): elif name == "role_input": item.click() roles_list = self.get_content_item("roles_list") - roles_list.check_presence(self.page.locator(ModalWindowLocators.ROLES_MENU_INPUT_FORM_USER_DATA), + roles_list.check_presence(menu_locator, "Roles list is missing") + is_scrollable_vertically = roles_list.check_vertical_scrolling(menu_locator) + assert not is_scrollable_vertically, \ + "Roles list should not be scrollable_vertically" + for role in roles_dict.values(): # временно, пока есть несоответствие со списком ролей в вкладке Сессии if role == "Пользователь": diff --git a/modal_windows/modal_edit_user.py b/modal_windows/modal_edit_user.py index 54882a8..287e963 100644 --- a/modal_windows/modal_edit_user.py +++ b/modal_windows/modal_edit_user.py @@ -35,7 +35,6 @@ class EditUserModalWindow(ModalWindowComponent): # Локаторы элементов формы text_field_locator = ModalWindowLocators.TEXT_FIELD_INPUT_FORM_USER_DATA - roles_field_locator = ModalWindowLocators.ROLES_FIELD_INPUT_FORM_USER_DATA input_form_locator = ModalWindowLocators.INPUT_FORM_USER_DATA label_locator = ModalWindowLocators.LABEL_INPUT_FORM_USER_DATA @@ -53,7 +52,7 @@ class EditUserModalWindow(ModalWindowComponent): name_input = TextInput(page, loc, "name_input") self.add_content_item("name_input", name_input) - role_loc = self.page.locator(input_form_locator).locator("xpath=div[2]").locator(roles_field_locator) + role_loc = self.page.locator(input_form_locator).get_by_role("combobox").nth(0) role_input = TextInput(page, role_loc, "role_input") self.add_content_item("role_input", role_input) self.add_content_item( @@ -193,6 +192,8 @@ class EditUserModalWindow(ModalWindowComponent): role (str): Ожидаемая роль пользователя """ + menu_locator = self.page.locator(ModalWindowLocators.MENU_INPUT_FORM_USER_DATA) + self.check_by_window_title() self.check_toolbar_button_presence("close") self.check_toolbar_button_tooltip("close", "Закрыть") @@ -214,7 +215,7 @@ class EditUserModalWindow(ModalWindowComponent): elif name == "role_input": item.click() roles_list = self.get_content_item("roles_list") - roles_list.check_presence(self.page.locator(ModalWindowLocators.ROLES_MENU_INPUT_FORM_USER_DATA), + roles_list.check_presence(menu_locator, "Roles list is missing") roles_list.check_item_with_text(role) elif name == "roles_list": diff --git a/pages/users_tab.py b/pages/users_tab.py index e77746d..679c0c0 100644 --- a/pages/users_tab.py +++ b/pages/users_tab.py @@ -7,7 +7,8 @@ import re from playwright.sync_api import Page from modal_windows.modal_edit_user import EditUserModalWindow -from modal_windows.modal_add_user import AddUserModalWindow +from modal_windows.modal_add_local_user import AddLocalUserModalWindow +from modal_windows.modal_add_AD_user import AddADUserModalWindow from locators.table_locators import TableLocators from data.roles_dict import roles_dict from components.toolbar_component import ToolbarComponent @@ -58,14 +59,16 @@ class UsersTab(BasePage): AssertionError: Если тип окна не поддерживается. """ - if window_type == "add_user": - self.modal_windows["add_user"] = AddUserModalWindow(self.page) + if window_type == "add_local_user": + self.modal_windows["add_local_user"] = AddLocalUserModalWindow(self.page) + elif window_type == "add_AD_user": + self.modal_windows["add_AD_user"] = AddADUserModalWindow(self.page) elif window_type == "edit_user": self.modal_windows[title] = EditUserModalWindow(self.page, title) else: assert False, "Unsupported modal window type" - def get_modal_window(self, title: str) -> None: + def get_modal_window(self, title: str): """Возвращает модальное окно по заголовку. Args: @@ -119,15 +122,25 @@ class UsersTab(BasePage): modal_window.close_window() self.delete_modal_window(title) + def close_add_AD_user_window_by_toolbar_button(self) -> None: + """Закрывает окно добавления пользователя через тулбар.""" + + self.close_modal_window_by_toolbar_button("add_AD_user") + + def close_add_AD_user_window(self) -> None: + """Закрывает окно добавления пользователя.""" + + self.close_modal_window("add_AD_user") + def close_add_user_window_by_toolbar_button(self) -> None: """Закрывает окно добавления пользователя через тулбар.""" - self.close_modal_window_by_toolbar_button("add_user") + self.close_modal_window_by_toolbar_button("add_local_user") def close_add_user_window(self) -> None: """Закрывает окно добавления пользователя.""" - self.close_modal_window("add_user") + self.close_modal_window("add_local_user") def close_edit_user_window_by_toolbar_button(self, title: str) -> None: """Закрывает окно редактирования через кнопку в тулбаре. @@ -147,6 +160,7 @@ class UsersTab(BasePage): self.close_modal_window(title) + def add_new_user(self, user_data: dict) -> bool: """Добавляет нового пользователя или обрабатывает ошибку при дубликате. @@ -161,7 +175,17 @@ class UsersTab(BasePage): или если текст alert не соответствует ожидаемому. """ - self.get_modal_window("add_user").new_user(user_data) + add_user_window = self.get_modal_window("add_local_user") + + auth_type = user_data.get("auth_type") + if auth_type == "active_directory": + add_user_window.check_active_directory_checkbox() + self.add_modal_window("add_AD_user", "") + add_user_window = self.get_modal_window("add_AD_user") + add_user_window.new_user(user_data) + return True + + add_user_window.new_user(user_data) is_added = False alert_type = self.alert.get_alert_type() @@ -274,8 +298,8 @@ class UsersTab(BasePage): self.toolbar.check_button_presence("add_user") self.toolbar.click_button("add_user") - self.add_modal_window("add_user", "") - self.get_modal_window("add_user").check_by_window_title() + self.add_modal_window("add_local_user", "") + self.get_modal_window("add_local_user").check_by_window_title() def open_edit_user_page_by_index(self, row_index: int) -> tuple: """Открывает окно редактирования по индексу строки. @@ -335,6 +359,28 @@ class UsersTab(BasePage): self.add_modal_window("edit_user", user_name) self.get_modal_window(user_name).check_by_window_title() + def transform_to_add_AD_user_window(self): + """Трансформирует модальное окно добавления локального пользователя + в окно добавления пользователя Active Directory с помощью нажатия + чек-бокса Active Directory. + """ + + self.get_modal_window("add_local_user").check_active_directory_checkbox() + modal_window = self.modal_windows.get("add_AD_user") + if modal_window is None: + self.add_modal_window("add_AD_user", "") + + def transform_to_add_user_window(self): + """Трансформирует модальное окно добавления пользователя Active Directory + в окно добавления локального пользователя с помощью снятия отметки с + чек-бокса Active Directory. + """ + + self.get_modal_window("add_AD_user").uncheck_active_directory_checkbox() + modal_window = self.modal_windows.get("add_local_user") + if modal_window is None: + self.add_modal_window("add_local_user", "") + # Проверки: def check_users_table_content(self, verify: bool = False) -> None: """Проверяет содержимое таблицы пользователей. @@ -367,9 +413,14 @@ class UsersTab(BasePage): self.verify_users_table_content(table_content) def check_add_user_window_content(self) -> None: - """Проверяет содержимое окна добавления пользователя.""" + """Проверяет содержимое окна добавления локального пользователя.""" - self.get_modal_window("add_user").check_content() + self.get_modal_window("add_local_user").check_content() + + def check_add_AD_user_window_content(self) -> None: + """Проверяет содержимое окна добавления пользователя через Active Directory.""" + + self.get_modal_window("add_AD_user").check_content() def check_edit_user_window_content(self, user_name: str, role: str) -> None: """Проверяет содержимое окна редактирования. diff --git a/tests/components/test_user_modal_window.py b/tests/components/test_user_modal_window.py index 570725d..0c63e92 100644 --- a/tests/components/test_user_modal_window.py +++ b/tests/components/test_user_modal_window.py @@ -78,7 +78,7 @@ class TestUsersModalWindow: ut = UsersTab(browser) ut.open_add_user_window() - modal_window = ut.get_modal_window("add_user") + modal_window = ut.get_modal_window("add_local_user") is_scrollable_vertically = modal_window.check_window_vertical_scrolling() assert is_scrollable_vertically, "Should be vertical scrolling" diff --git a/tests/e2e/test_users_tab.py b/tests/e2e/test_users_tab.py index 6edbe9f..e423357 100644 --- a/tests/e2e/test_users_tab.py +++ b/tests/e2e/test_users_tab.py @@ -85,6 +85,7 @@ class TestUsersTab: ut = UsersTab(browser) ut.should_be_toolbar_buttons() + # pytest.mark.develop def test_add_user_window_content(self, browser: Page) -> None: """Проверяет содержимое окна добавления пользователя. @@ -95,6 +96,8 @@ class TestUsersTab: ut = UsersTab(browser) ut.open_add_user_window() ut.check_add_user_window_content() + ut.transform_to_add_AD_user_window() + ut.check_add_AD_user_window_content() def test_add_user_window_close_buttons(self, browser: Page) -> None: """Проверяет кнопки закрытия окна добавления. @@ -110,6 +113,14 @@ class TestUsersTab: ut.open_add_user_window() ut.close_add_user_window() + ut.open_add_user_window() + ut.transform_to_add_AD_user_window() + ut.close_add_AD_user_window_by_toolbar_button() + + ut.open_add_user_window() + ut.transform_to_add_AD_user_window() + ut.close_add_AD_user_window() + def test_edit_user_window_content(self, browser: Page) -> None: """Проверяет содержимое окна редактирования. @@ -134,6 +145,7 @@ class TestUsersTab: user_name, _ = ut.open_edit_user_page_by_index(0) ut.close_edit_user_window(user_name) + # @pytest.mark.develop def test_add_and_delete_user(self, browser: Page, cleanup_user: None) -> None: """Проверяет добавление и удаление пользователя. @@ -181,6 +193,25 @@ class TestUsersTab: mp.click_subpanel_item("Пользователи") ut.should_not_be_user_in_table(user_data["name"], user_data["role"]) + # @pytest.mark.develop + def test_add_AD_user(self, browser: Page, cleanup_user: None) -> None: + """Проверяет добавление пользователя Active Directory. + + Args: + browser: Экземпляр страницы Playwright. + cleanup_user: Фикстура для очистки пользователя. + """ + + user_data: Dict[str, str] = {"auth_type":"active_directory", + "group": "Администраторы", + "name": "Администратор", + "role": "Администратор"} + + ut = UsersTab(browser) + + ut.open_add_user_window() + ut.add_new_user(user_data) + def test_reset_password(self, browser: Page, cleanup_autoadmin: None) -> None: """Проверяет сброс пароля пользователя.