"""Модуль вкладки 'Пользователи'. Содержит класс UsersTab для работы с таблицей пользователей. Позволяет управлять пользователями через модальные окна и проверять их состояние. """ import re from playwright.sync_api import Page from locators.table_locators import TableLocators from components_derived.modal_edit_user import EditUserModalWindow from components_derived.modal_add_user import AddUserModalWindow from data.roles_dict import roles_dict from components.toolbar_component import ToolbarComponent from components.table_component import TableComponent from components.modal_window_component import ModalWindowComponent from components.alert_component import AlertComponent from pages.base_page import BasePage class UsersTab(BasePage): """Класс для работы с вкладкой 'Пользователи'. Предоставляет методы для взаимодействия с таблицей пользователей, модальными окнами и проверки состояния элементов. Args: page: Экземпляр страницы Playwright. """ def __init__(self, page: Page) -> None: """Инициализирует компоненты вкладки 'Пользователи'.""" super().__init__(page) self.toolbar = ToolbarComponent(page, "Пользователи") toolbar_button_edit = self.page.get_by_role("navigation").filter(has_text=re.compile("Пользователи")). \ locator("//button[@data-testid='USERS__btn__edit']") self.toolbar.add_tooltip_button(toolbar_button_edit, "edit") toolbar_button_add_user = self.page.get_by_role("navigation").filter(has_text=re.compile("Пользователи")). \ locator("//button[@data-testid='USERS__btn__onAdd']") self.toolbar.add_tooltip_button(toolbar_button_add_user, "add_user") toolbar_button_close = self.page.get_by_role("navigation").filter(has_text=re.compile("Пользователи")). \ locator("//button[@data-testid='USERS__btn__close']") self.toolbar.add_tooltip_button(toolbar_button_close, "close") self.users_table = TableComponent(page) self.modal_windows = {} self.alert = AlertComponent(page) # Действия: def add_modal_window(self, window_type: str, title: str) -> None: """Добавляет модальное окно в коллекцию. Args: window_type: Тип окна ('add_user' или 'edit_user'). title: Заголовок окна. Raises: AssertionError: Если тип окна не поддерживается. """ if window_type == "add_user": self.modal_windows["add_user"] = AddUserModalWindow(self.page) elif window_type == "edit_user": self.modal_windows[title] = EditUserModalWindow(self.page, title) else: assert False, "Unsupported modal window type" def add_new_user(self, user_data: dict) -> bool: """Добавляет нового пользователя или обрабатывает ошибку при дубликате. Args: user_data: Данные пользователя (name, role, password). Returns: bool: True если пользователь успешно добавлен, False если пользователь уже существует. Raises: AssertionError: Если открылось alert окно отличное от success или error, или если текст alert не соответствует ожидаемому. """ add_user_window = self.get_modal_window("add_user") add_user_window.new_user(user_data) is_added = False alert_type = self.alert.get_alert_type() if alert_type == "success": self.alert.check_alert_presence(' Новый пользователь \n успешно добавлен! ') self.alert.check_alert_absence(' Новый пользователь \n успешно добавлен! ') is_added = True elif alert_type == "error": self.alert.check_alert_presence(f' Имя {user_data["name"]} уже \n используется ') self.alert.check_alert_absence(f' Имя {user_data["name"]} уже \n используется ') else: assert False, f"Got unexpected alert type {alert_type}" return is_added def close_add_user_window(self) -> None: """Закрывает окно добавления пользователя.""" self.close_modal_window("add_user") def close_add_user_window_by_toolbar_button(self) -> None: """Закрывает окно добавления пользователя через тулбар.""" self.close_modal_window_by_toolbar_button("add_user") def close_edit_user_window(self, title: str) -> None: """Закрывает окно редактирования пользователя. Args: title: Имя пользователя (заголовок окна). """ self.close_modal_window(title) def close_edit_user_window_by_toolbar_button(self, title: str) -> None: """Закрывает окно редактирования через кнопку в тулбаре. Args: title: Имя пользователя (заголовок окна). """ self.close_modal_window_by_toolbar_button(title) def close_modal_window(self, title: str) -> None: """Закрывает модальное окно через кнопку закрытия. Args: title: Заголовок окна. """ modal_window = self.get_modal_window(title) modal_window.close_window() self.delete_modal_window(title) def close_modal_window_by_toolbar_button(self, title: str) -> None: """Закрывает модальное окно через кнопку в тулбаре. Args: title: Заголовок окна. """ modal_window = self.get_modal_window(title) modal_window.close_window_by_toolbar_button() self.delete_modal_window(title) def delete_modal_window(self, title: str) -> None: """Удаляет модальное окно из коллекции. Args: title: Заголовок окна. Raises: AssertionError: Если окно не найдено. """ if self.modal_windows.get(title) is None: assert False, f"Modal window with title '{title}' not found" self.modal_windows[title] = None def delete_user(self, user_name: str) -> None: """Удаляет пользователя. Args: user_name: Имя пользователя. Raises: AssertionError: Если нет сообщения об успешном удалении. """ self.get_modal_window(user_name).delete_user() alert_type = self.alert.get_alert_type() assert alert_type == "success", f"Expected success alert, but got {alert_type} alert" self.alert.check_alert_presence('\nПользователь удалён\n') self.alert.check_alert_absence('\nПользователь удалён\n') def edit_user(self, user_name: str, user_data: dict) -> None: """Редактирует данные пользователя. Args: user_name: Имя пользователя. user_data: Новые данные пользователя. Raises: AssertionError: Если нет сообщения об успешном обновлении. """ self.get_modal_window(user_name).edit_user(user_data) alert_type = self.alert.get_alert_type() assert alert_type == "success", f"Expected success alert, but got {alert_type} alert" self.alert.check_alert_presence('\nОбновление успешно\n') self.alert.check_alert_absence('\nОбновление успешно\n') def find_user_in_table(self, name: str, role: str) -> int: """Ищет пользователя в таблице. Args: name: Имя пользователя. role: Роль пользователя. Returns: int: Индекс строки или -1 если не найден. Raises: AssertionError: Если таблица пуста. """ self.page.wait_for_timeout(1000) table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA) if len(table_content) == 0: assert False, "The contents of the table are missing" # Удаляем заголовок del table_content[0] for row_index, user_info in enumerate(table_content): if name in user_info and role in user_info: return row_index return -1 def get_modal_window(self, title: str) -> ModalWindowComponent: """Возвращает модальное окно по заголовку. Args: title: Заголовок окна. Returns: ModalWindowComponent: Экземпляр модального окна. Raises: AssertionError: Если окно не найдено. """ modal_window = self.modal_windows.get(title) if modal_window is None: assert False, f"Modal window with title '{title}' not found" return modal_window def get_rows_count(self) -> int: """Возвращает количество строк в таблице пользователей (без заголовка). Returns: int: Количество строк с данными. Raises: AssertionError: Если таблица пуста. """ return self.users_table.get_rows_count(TableLocators.TABLE_WORK_AREA) def open_add_user_window(self) -> None: """Открывает окно добавления пользователя. Raises: AssertionError: Если кнопки недоступны или окно не открылось. """ if self.toolbar.is_button_not_present("close"): self.toolbar.check_button_visibility("edit") self.toolbar.click_button("edit") self.toolbar.check_button_visibility("add_user") self.toolbar.click_button("add_user") self.page.wait_for_timeout(700) self.add_modal_window("add_user", "") self.get_modal_window("add_user").check_by_window_title() def open_edit_user_page_by_index(self, row_index: int) -> tuple: """Открывает окно редактирования по индексу строки. Args: row_index: Индекс строки в таблице. Returns: tuple: (имя пользователя, роль). Raises: AssertionError: Если таблица пуста или индекс вне диапазона. """ self.page.wait_for_timeout(2000) tmp_dict = {"admin": "Администратор", "manager": "Контактное лицо", "operator": "Оператор"} table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA) if len(table_content) == 0: assert False, "The contents of the table are missing" # Удаляем заголовок del table_content[0] if row_index >= len(table_content): assert False, "Row_index is out of range" user_name = table_content[row_index][0] for key, val in tmp_dict.items(): if user_name == val: user_name = key role = table_content[row_index][3] self.page.locator(TableLocators.TABLE_WORK_AREA).locator( "//tbody/tr").nth(row_index).click() self.add_modal_window("edit_user", user_name) self.get_modal_window(user_name).check_by_window_title() return user_name, role def open_edit_user_page_by_user(self, user_name: str, role: str) -> None: """Открывает окно редактирования по имени и роли. Args: user_name: Имя пользователя. role: Роль пользователя. Raises: AssertionError: Если пользователь не найден. """ row_index = self.find_user_in_table(user_name, role) if row_index == -1: assert False, f"User with name {user_name} and role {role} has not been found" self.page.locator(TableLocators.TABLE_WORK_AREA).locator("//tbody/tr").nth(row_index).click() self.add_modal_window("edit_user", user_name) self.get_modal_window(user_name).check_by_window_title() def reset_password(self, user_name: str) -> str: """Сбрасывает пароль пользователя. Args: user_name: Имя пользователя. Returns: str: Новый пароль (если получен). """ new_password = "" self.get_modal_window(user_name).reset_password() self.alert.check_alert_presence("") alert_message = self.alert.get_text() if len(alert_message) > 0: new_password = re.findall(r'[\d]+', alert_message)[0] return new_password # Проверки: def check_add_user_window_content(self) -> None: """Проверяет содержимое окна добавления локального пользователя.""" self.get_modal_window("add_user").check_content() def check_edit_user_window_content(self, user_name: str, role: str) -> None: """Проверяет содержимое окна редактирования. Args: user_name: Имя пользователя. role: Роль пользователя. """ edit_user_window = self.get_modal_window(user_name) edit_user_window.check_content(user_name, role) def check_users_table_content(self, verify: bool = False) -> None: """Проверяет содержимое таблицы пользователей. Args: verify: Проверять соответствие данных из БД. По умолчанию False. Raises: AssertionError: Если таблица пуста или заголовки неверны. """ self.page.wait_for_timeout(2000) expected_headers = ['Имя пользователя', 'Идентификатор', 'Тип авторизации', 'Роль', 'E-mail', 'Номер для СМС'] table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA) if len(table_content) == 0: assert False, "The contents of the table are missing" actual_headers = table_content[0] self.check_equals( actual_headers, expected_headers, f"Expected table headers {expected_headers} are not equal {actual_headers}" ) if len(table_content) == 1: assert False, "Table body is missing" if verify: self.verify_users_table_content(table_content) def check_users_table_row_highlighting(self, row_index: int) -> None: """Проверяет выделение указанной строки таблицы. Args: row_index: Индекс проверяемой строки. Raises: AssertionError: Если строка не выделена. """ self.users_table.check_row_highlighting( TableLocators.TABLE_WORK_AREA, row_index ) def should_be_toolbar(self) -> None: """Проверяет наличие тулбара. Raises: AssertionError: Если тулбар или кнопка редактирования отсутствуют. """ self.toolbar.check_toolbar_presence("Toolbar is missing") self.toolbar.check_button_visibility("edit") def should_be_toolbar_buttons(self) -> None: """Проверяет наличие и функциональность кнопок тулбара. Raises: AssertionError: Если кнопки недоступны или подсказки неверны. """ self.toolbar.check_button_visibility("edit") self.toolbar.check_button_tooltip("edit", "Редактировать") self.toolbar.get_button_by_name("edit").click() self.toolbar.check_button_visibility("add_user") self.toolbar.check_button_visibility("close") self.toolbar.check_button_tooltip("add_user", "Добавить") self.toolbar.check_button_tooltip("close", "Закрыть") self.toolbar.get_button_by_name("close").click() self.toolbar.check_button_visibility("edit") def should_be_user_in_table(self, name: str, role: str) -> None: """Проверяет наличие пользователя в таблице. Args: name: Имя пользователя. role: Роль пользователя. Raises: AssertionError: Если пользователь не найден. """ found = self.find_user_in_table(name, role) if found == -1: assert False, f"User with name {name} and role {role} has not been found" def should_be_users_table(self) -> None: """Проверяет наличие таблицы пользователей. Raises: AssertionError: Если таблица отсутствует. """ self.users_table.check_visibility(TableLocators.TABLE_WORK_AREA,"Users table is missing") def should_not_be_user_in_table(self, name: str, role: str) -> None: """Проверяет отсутствие пользователя в таблице. Args: name: Имя пользователя. role: Роль пользователя. Raises: AssertionError: Если пользователь найден. """ found = self.find_user_in_table(name, role) if found != -1: assert False, f"User with name {name} and role {role} has been found" def verify_users_table_content(self, users_table: list) -> None: """Сверяет данные таблицы с данными из БД. Args: users_table: Данные из таблицы на странице. Raises: AssertionError: Если данные не соответствуют. """ expected_users_list = [] query = { "id": ["/catalogs/user"], "data": { "namePath": True, "children": {"flatten": True} } } response = self.send_post_api_request("e-cmdb/api/query", query) response_body = self.get_response_body(response) for item in response_body[0]["children"]: user_info = [] user_name = item["name"] # НЕ преобразуем имя пользователя - оставляем как есть из БД user_info.append(user_name) if item["id"] is not None: user_info.append(str(item["id"])) else: user_info.append("") if item["type_auth"] is not None: user_info.append(item["type_auth"]) else: user_info.append("") if item["role"] is not None: role = item["role"] # Убрали вызов .keys() if role in roles_dict: item["role"] = roles_dict[role] user_info.append(item["role"]) else: user_info.append("") if item["email"] is not None: user_info.append(item["email"]) else: user_info.append("") if item["sms_phone"] is not None: user_info.append(item["sms_phone"]) else: user_info.append("") expected_users_list.append(user_info) # Удаляем заголовок del users_table[0] self.check_lists_equals( users_table, expected_users_list, "Actual users list is not equal expected users list on base db" )