"""Модуль вкладки 'Шаблоны'. Содержит класс TemplatesTab для работы с таблицей шаблонов. Позволяет проверять состояние и взаимодействовать с элементами вкладки. """ from playwright.sync_api import Page from tools.logger import get_logger from locators.table_locators import TableLocators from locators.modal_window_locators import ModalWindowLocators from locators.json_container_locators import JsonContainerLocators from components_derived.modal_view_template import ViewTemplateModalWindow from components.modal_window_component import ModalWindowComponent from components.toolbar_component import ToolbarComponent from components.table_component import TableComponent from components.json_container_component import JsonContainerComponent from pages.base_page import BasePage logger = get_logger("TEMPLATES_TAB") class TemplatesTab(BasePage): """Класс для работы с вкладкой 'Шаблоны'. Предоставляет методы для взаимодействия с таблицей шаблонов и проверки её состояния. Args: page: Экземпляр страницы Playwright. """ def __init__(self, page: Page) -> None: """Инициализирует компоненты вкладки 'Шаблоны'.""" super().__init__(page) self.toolbar = ToolbarComponent(page, "Шаблоны") self.templates_table = TableComponent(page) self.modal_windows = {} self.json_container = JsonContainerComponent(page) def add_modal_window(self, title: str) -> None: """Добавляет модальное окно в коллекцию. Args: title: Заголовок окна. """ self.modal_windows[title] = ViewTemplateModalWindow(self.page, title) def get_modal_window(self, title: str) -> ViewTemplateModalWindow: """Возвращает модальное окно по заголовку. Args: title: Заголовок окна. Returns: ViewTemplateModalWindow: Экземпляр модального окна. 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 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 open_template_modal_by_index(self, row_index: int = 0) -> str: """Открывает модальное окно шаблона по клику на строку таблицы. Args: row_index: Индекс строки для клика (по умолчанию 0 - первая строка). Returns: str: Имя шаблона. """ row_locator = self.templates_table.get_row_locator( TableLocators.TABLE_WORK_AREA, row_index ) row_locator.click() # Получаем имя шаблона из выбранной строки table_content = self.templates_table.read(TableLocators.TABLE_WORK_AREA) # +1 потому что первая строка - заголовки title = table_content[row_index + 1][0] # Добавляем модальное окно в коллекцию после открытия self.add_modal_window(title) return 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 get_rows_count(self) -> int: """Возвращает количество строк в таблице (без заголовка). Returns: int: Количество строк с данными. Raises: AssertionError: Если таблица пуста. """ return self.templates_table.get_rows_count(TableLocators.TABLE_WORK_AREA) def scroll_templates_table_up(self) -> None: """Прокручивает таблицу шаблонов вверх.""" self.templates_table.scroll_up(TableLocators.TABLE_SCROLL_CONTAINER) def scroll_templates_table_down(self) -> None: """Прокручивает таблицу шаблонов вниз.""" self.templates_table.scroll_down(TableLocators.TABLE_SCROLL_CONTAINER) def scroll_modal_up(self) -> None: """Прокручивает содержимое модального окна вверх.""" temp_modal = ModalWindowComponent(self.page) temp_modal.scroll_window_up() def scroll_modal_down(self) -> None: """Прокручивает содержимое модального окна вниз.""" temp_modal = ModalWindowComponent(self.page) temp_modal.scroll_window_down() def extract_specific_template(self, title: str, response_data: dict) -> dict: """Извлекает структуру конкретного шаблона по title из данных API. Args: title: Имя шаблона для извлечения. response_data: Данные ответа от API. Returns: dict: Структура конкретного шаблона. Raises: AssertionError: Если шаблон с указанным именем не найден или структура ответа некорректна. """ # Проверяем, что ответ является списком шаблонов assert isinstance(response_data, list), "API response is not a list of templates" # Ищем шаблон с указанным именем for template in response_data: if template.get('id') == title: logger.info("Found template: %s", title) return template # Если шаблон не найден available_templates = [t.get('id', 'Unknown') for t in response_data] # Генерируем понятное сообщение об ошибке error_msg = ( f"Template '{title}' not found. " f"Available templates: {available_templates}" ) logger.error(error_msg) assert False, error_msg def check_templates_modal_content(self, title: str) -> None: """Проверяет наличие и корректность элементов модального окна шаблона. Args: title: Имя шаблона для проверки заголовка окна. Raises: AssertionError: Если элементы окна некорректны. """ modal_window = self.get_modal_window(title) modal_window.check_content() def check_templates_table_content(self) -> None: """Проверяет содержимое таблицы шаблонов. Проверяет заголовки и наличие данных в таблице. Raises: AssertionError: Если таблица пуста или заголовки неверны. """ expected_headers = [ 'Имя', 'Описание', 'Тип устройства', 'Производитель' ] self.templates_table.check_content(TableLocators.TABLE_WORK_AREA, expected_headers) def check_templates_table_vertical_scrolling(self) -> bool: """Проверяет возможность вертикальной прокрутки таблицы. Returns: bool: True если прокрутка возможна, иначе False. """ return self.templates_table.is_scrollable_vertically( TableLocators.TABLE_SCROLL_CONTAINER ) def check_templates_table_first_row_visibility(self) -> None: """Проверяет видимость первой строки таблицы. Raises: AssertionError: Если строка не видна. """ self.templates_table.check_first_row_visibility(TableLocators.TABLE_WORK_AREA) def check_templates_table_last_row_visibility(self) -> None: """Проверяет видимость последней строки таблицы. Raises: AssertionError: Если строка не видна. """ self.templates_table.check_last_row_visibility(TableLocators.TABLE_WORK_AREA) def check_templates_table_row_highlighting(self, row_index: int) -> None: """Проверяет выделение указанной строки таблицы. Args: row_index: Индекс проверяемой строки. Raises: AssertionError: Если строка не выделена. """ self.templates_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") def should_be_templates_table(self) -> None: """Проверяет наличие таблицы шаблонов. Raises: AssertionError: Если таблица отсутствует. """ self.templates_table.check_visibility( TableLocators.TABLE_WORK_AREA, "Templates table is missing" ) def should_be_modal_window(self) -> None: """Проверяет наличие модального окна. Raises: AssertionError: Если модальное окно отсутствует. """ self.templates_table.check_visibility( ModalWindowLocators.MODAL_WINDOW, "Modal window is not visible" ) def should_not_be_modal_window(self) -> None: """Проверяет, что модальное окно отсутствует. Raises: AssertionError: Если модальное окно все еще видно. """ is_visible = self.page.locator( ModalWindowLocators.MODAL_WINDOW ).is_visible(timeout=1000) if is_visible: assert False, "Modal window should not be visible" def check_modal_vertical_scrolling(self) -> bool: """Проверяет возможность вертикального скроллинга в модальном окне. Returns: bool: True если скроллинг возможен, иначе False. """ temp_modal = ModalWindowComponent(self.page) return temp_modal.check_window_vertical_scrolling() def verify_json_container_content(self, title: str) -> None: """Проверяет соответствие данных контейнера данным из API. Args: title: Имя шаблона для проверки. """ # Читаем данные из контейнера actual_data = self.json_container.read_data(JsonContainerLocators.CONTAINER) # Отправляем запрос к backend для получения информации о шаблоне response = self.send_get_api_request("e-cmdb/api/device/template") response_body = self.get_response_body(response) # Извлекаем конкретный шаблон по имени из ответа API template_data = self.extract_specific_template(title, response_body) # Сравниваем actual_data с данными конкретного шаблона self.json_container.check_json_equals( actual_data, template_data, "Expected json content is not equal actual:" )