From 4fff4835f11835f1280eb9a9d4b5b9f74406756d Mon Sep 17 00:00:00 2001 From: Radislav Date: Fri, 6 Mar 2026 11:54:03 +0300 Subject: [PATCH] =?UTF-8?q?refactor:=20=D1=80=D0=B5=D0=BE=D1=80=D0=B3?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=8B=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Изменены (test_edit_rack.py, test_management_rack.py) --- tests/e2e/elements/test_edit_rack.py | 394 ++++++++++++--------- tests/e2e/elements/test_management_rack.py | 324 +++++++++-------- 2 files changed, 401 insertions(+), 317 deletions(-) diff --git a/tests/e2e/elements/test_edit_rack.py b/tests/e2e/elements/test_edit_rack.py index 8478a13..c910c9e 100644 --- a/tests/e2e/elements/test_edit_rack.py +++ b/tests/e2e/elements/test_edit_rack.py @@ -1,157 +1,45 @@ -"""Модуль тестов вкладки 'Стойка' в модуле Объекты. +"""Модуль тестов редактирования стойки в модуле Объекты. Содержит тесты для проверки функциональности -работы со стойкой оборудования. +редактирования стойки оборудования. """ import os import pytest from playwright.sync_api import Page +from tools.logger import get_logger from locators.navigation_panel_locators import NavigationPanelLocators +from frames.create_element_frame import CreateElementFrame +from forms.create_rack_form import CreateRackForm, CreateRackData +from makers.edit_rack_maker import EditRackMaker, EditRackData +from pages.location_page import LocationPage from pages.login_page import LoginPage from pages.main_page import MainPage -from pages.location_page import LocationPage from pages.rack_page import RackPage -from components_derived.accounting_objects.rack_maker import RackObjectMaker, RackData -from components_derived.frames.create_child_element_frame import CreateChildElementFrame -from components_derived.modal_edit_rack import ModalEditRack, RackEditData from components.alert_component import AlertComponent -from tools.logger import get_logger -# Константы -RACK_NAME = "Test-Rack-Functionality" -# Инициализация логгера для всего модуля logger = get_logger("RACK_EDIT_TESTS") logger.setLevel("INFO") -class TestRackTab: - """Набор тестов для вкладки 'Стойка' в модуле Объекты. - Проверяет корректность отображения, функциональность элементов интерфейса - и переключение между вкладками стойки оборудования. +class TestRackEdit: + """Набор тестов для редактирования стойки в модуле Объекты. - Тесты покрывают следующие функциональные области: - 1. test_rack_general_info_tab_fields - Заполнение полей вкладки 'Общая информация' - 2. test_rack_image_tab - Работа с вкладкой 'Изображение' - 3. test_rack_access_rules - Заполнение полей правил доступа + Проверяет функциональность редактирования различных вкладок стойки: + 1. Общая информация + 2. Изображение + 3. Правила доступа """ + # Имя тестовой стойки + RACK_NAME = "Test-Rack-Edit" + # Инициализируем атрибуты main_page: MainPage = None location_page: LocationPage = None - - def _check_rack_existance(self, browser: Page, rack_name: str) -> bool: - """Проверяет существование стойки. - - Args: - browser: Страница Playwright - rack_name: Имя стойки для проверки - - Returns: - bool: True если стойка существует, False в противном случае - """ - - # Обновляем навигационную панель - self.main_page.wait_for_timeout(500) - self.main_page.click_subpanel_item("test-zone") - - nav_panel_locator = NavigationPanelLocators.TREEVIEW - - # Проверяем видимость элемента - element = browser.locator(nav_panel_locator).get_by_text(rack_name, exact=True).first - - if element.is_visible(): - return True - return False - - def _create_rack(self, browser: Page, rack_name: str) -> None: - """Создает стойку. - - Args: - browser: Страница Playwright - rack_name: Имя стойки для создания - """ - logger.debug(f"Creating rack: {rack_name}") - - # Нажимаем кнопку "Создать" на тулбаре - self.location_page.click_create_button() - - # Создаем фрейм создания дочернего элемента - create_child_frame = CreateChildElementFrame(browser) - - # Нажимаем на плашку "Класс объекта учета" - create_child_frame.open_object_class_combobox() - - # Из выпадающего меню выбираем пункт "Стойка" - create_child_frame.select_object_class("Стойка") - - # Открывается набор плашек для задания параметров стойки - rack_maker = RackObjectMaker(browser) - - # Создаем объект данных стойки - rack_data = RackData( - name=rack_name, - height="42", - depth="1000" - ) - - # Заполняем данные стойки - rack_maker.fill_rack_data(rack_data) - - # Нажимаем кнопку создания - create_child_frame.click_add_button() - - # Проверяем уведомление об успешном создании - alert = AlertComponent(browser) - expected_alert_text = f"Элемент {rack_name} создан" - alert.check_alert_presence(expected_alert_text) - alert.close_alert_by_text(expected_alert_text) - - logger.info(f"Rack '{rack_name}' created successfully") - - def _delete_rack_from_context_menu(self, browser: Page, rack_name: str) -> None: - """Удаляет стойку через контекстное меню. - - Args: - browser: Страница Playwright - rack_name: Имя стойки для удаления - """ - - # 1. Находим элемент стойки в навигационной панели - rack_element = browser.locator( - NavigationPanelLocators.TREEVIEW - ).get_by_text(rack_name, exact=True).first - - # Прокручиваем до элемента если нужно - rack_element.scroll_into_view_if_needed() - self.main_page.wait_for_timeout(500) - - # 2. Проверяем и нажимаем кнопку "Изменить" - rack_page = RackPage(browser) - - # Проверяем видимость и тултип кнопки - rack_page.should_be_toolbar_buttons() - - # Кликаем на кнопку "Изменить" - rack_page.click_edit_button() - - self.main_page.wait_for_timeout(1000) - - # 3. Создаем экземпляр ModalRackEditRack - rack_edit = ModalEditRack(browser, rack_name) - - # Используем метод для удаления - rack_edit.click_remove_button() - self.main_page.wait_for_timeout(1000) - - # 4. Проверяем уведомление об успешном удалении - alert = AlertComponent(browser) - expected_alert_text = "Успешно удалено" - alert.check_alert_presence(expected_alert_text) - alert.close_alert_by_text(expected_alert_text) - - logger.info(f"Rack '{rack_name}' deleted successfully") + alert: AlertComponent = None + create_child_frame: CreateElementFrame = None @pytest.fixture(scope="function", autouse=True) def setup(self, browser: Page) -> None: @@ -159,11 +47,13 @@ class TestRackTab: Выполняет: 1. Авторизацию в системе - 2. Создание стойки если она не существует - 3. Переход к стойке + 2. Переход к локации test-zone + 3. Инициализацию компонентов + 4. Создание стойки если она не существует + 5. Переход к стойке Args: - browser (Page): Экземпляр страницы Playwright для взаимодействия с UI + browser: Экземпляр страницы Playwright для взаимодействия с UI """ # Авторизация в системе @@ -182,22 +72,35 @@ class TestRackTab: # Создаем экземпляр страницы локации self.location_page = LocationPage(browser) + # Инициализируем компонент алертов (вынесено в атрибуты класса) + self.alert = AlertComponent(browser) + + # Инициализируем фрейм создания дочернего элемента (вынесено в атрибуты класса) + self.create_child_frame = CreateElementFrame(browser) + # Проверяем существование стойки - if not self._check_rack_existance(browser, RACK_NAME): - self._create_rack(browser, RACK_NAME) + if not self._check_rack_existance(browser, self.RACK_NAME): + logger.info(f"Rack '{self.RACK_NAME}' does not exist. Creating...") + + rack_data = CreateRackData( + name=self.RACK_NAME, + usize="42", + depth="1000" + ) + self._create_rack(browser, rack_data) self.main_page.wait_for_timeout(3000) else: - logger.info(f"Rack '{RACK_NAME}' already exists") + logger.info(f"Rack '{self.RACK_NAME}' already exists") # Переходим к стойке для тестирования - self.main_page.click_subpanel_item(RACK_NAME, parent="test-zone") + self.main_page.click_subpanel_item(self.RACK_NAME, parent="test-zone") self.main_page.wait_for_timeout(3000) @pytest.fixture(scope="class", autouse=True) def cleanup_rack(self, browser: Page): """Фикстура для очистки созданной стойки после ВСЕХ тестов класса. - Выполняется один раз после завершения всех тестов класса TestRackTab. + Выполняется один раз после завершения всех тестов класса TestRackEdit. Удаляет созданную стойку. Args: @@ -207,6 +110,8 @@ class TestRackTab: # Тесты выполняются здесь yield + logger.debug(f"Cleaning up rack: {self.RACK_NAME}") + # Переходим на главную страницу и в нужную зону login_page = LoginPage(browser) login_page.do_login() @@ -220,37 +125,160 @@ class TestRackTab: self.main_page.click_main_navigation_panel_item("test-zone") self.main_page.wait_for_timeout(1000) + # Инициализируем компонент алертов для cleanup + self.alert = AlertComponent(browser) + # Проверяем существование стойки - if self._check_rack_existance(browser, RACK_NAME): + if self._check_rack_existance(browser, self.RACK_NAME): # Переходим на страницу стойки - self.main_page.click_subpanel_item(RACK_NAME, parent="test-zone") + self.main_page.click_subpanel_item(self.RACK_NAME, parent="test-zone") self.main_page.wait_for_timeout(2000) # Удаляем стойку - self._delete_rack_from_context_menu(browser, RACK_NAME) + self._delete_rack(browser, self.RACK_NAME) # Дополнительная проверка self.main_page.click_subpanel_item("test-zone") self.main_page.wait_for_timeout(1000) - #@pytest.mark.develop + def _check_rack_existance(self, browser: Page, rack_name: str) -> bool: + """Проверяет существование стойки. + + Args: + browser: Страница Playwright + rack_name: Имя стойки для проверки + + Returns: + bool: True если стойка существует, False в противном случае + """ + + logger.debug(f"Checking existence of rack with name '{rack_name}'") + + self.main_page.click_subpanel_item("test-zone") + + nav_panel_locator = NavigationPanelLocators.TREEVIEW + element = browser.locator(nav_panel_locator).get_by_text(rack_name, exact=True).first + + if element.is_visible(): + logger.debug(f"Rack with name '{rack_name}' found") + return True + + logger.debug(f"Rack with name '{rack_name}' not found") + return False + + def _create_rack(self, browser: Page, rack_data: CreateRackData) -> None: + """Создает стойку. + + Args: + browser: Страница Playwright + rack_data: Данные стойки для создания + """ + + logger.debug(f"Creating rack with name '{rack_data.name}'") + + # Нажимаем кнопку "Создать" на тулбаре + self.location_page.click_create_button() + + # Нажимаем на плашку "Класс объекта учета" + self.create_child_frame.open_object_class_combobox() + + # Из выпадающего меню выбираем пункт "Стойка" + self.create_child_frame.select_object_class("Стойка") + + # Создаем форму создания стойки + rack_form = CreateRackForm(browser) + + # Заполняем данные стойки + fill_results = rack_form.fill_rack_data(rack_data) + logger.debug(f"Fill results: {fill_results}") + + # Нажимаем кнопку создания + self.create_child_frame.click_add_button() + + # Ждем появления alert с текстом + expected_alert_text = f"Элемент {rack_data.name} создан" + self.alert.check_alert_presence(expected_alert_text, timeout=5000) + + self.alert.check_alert_absence(expected_alert_text, timeout=7000) + + # Закрываем alert с текстом кнопкой 'Закрыть' + try: + self.alert.close_alert_by_text(expected_alert_text) + logger.debug("Alert forcibly closed") + except AssertionError: + # Если уже закрылся - игнорируем + logger.debug("Alert already closed by the time forcible close was attempted") + + logger.info(f"Rack '{rack_data.name}' created successfully") + + def _delete_rack(self, browser: Page, rack_name: str) -> None: + """Удаляет стойку через контекстное меню. + + Args: + browser: Страница Playwright + rack_name: Имя стойки для удаления + """ + + # Находим элемент стойки в навигационной панели + rack_element = browser.locator( + NavigationPanelLocators.TREEVIEW + ).get_by_text(rack_name, exact=True).first + + # Прокручиваем до элемента если нужно + rack_element.scroll_into_view_if_needed() + self.main_page.wait_for_timeout(500) + + # Проверяем и нажимаем кнопку "Изменить" + rack_page = RackPage(browser) + + # Проверяем видимость и тултип кнопки + rack_page.should_be_toolbar_buttons() + + # Кликаем на кнопку "Изменить" + rack_page.click_edit_button() + self.main_page.wait_for_timeout(1000) + + # Создаем экземпляр EditRackMaker + rack_edit = EditRackMaker(browser, rack_name) + + # Используем метод для удаления + rack_edit.click_remove_button() + + # Проверяем уведомление об успешном удалении + expected_alert_text = "Успешно удалено" + self.alert.check_alert_presence(expected_alert_text, timeout=5000) + + self.alert.check_alert_absence(expected_alert_text, timeout=7000) + + # Закрываем alert с текстом кнопкой 'Закрыть' + try: + self.alert.close_alert_by_text(expected_alert_text) + logger.debug("Alert forcibly closed") + except AssertionError: + # Если уже закрылся - игнорируем + logger.debug("Alert already closed by the time forcible close was attempted") + + logger.info(f"Rack '{rack_name}' deleted successfully") + def test_rack_general_info_tab_fields(self, browser: Page) -> None: """Тест заполнения полей вкладки 'Общая информация' стойки.""" + logger.debug(f"Starting general info tab test for rack: {self.RACK_NAME}") + rack_page = RackPage(browser) # Переходим в режим редактирования rack_page.click_edit_button() rack_page.wait_for_timeout(1000) - # Создаем экземпляр ModalEditRack - rack_edit = ModalEditRack(browser, RACK_NAME) + # Создаем экземпляр EditRackMaker + rack_edit = EditRackMaker(browser, self.RACK_NAME) # Создаем тестовые данные для заполнения всех полей - rack_edit_data = RackEditData( + rack_edit_data = EditRackData( # Основные поля - name=RACK_NAME, + name=self.RACK_NAME, serial="SN123456789", inventory="INV987654321", comment="Тестовый комментарий для стойки (обновленный)", @@ -274,15 +302,19 @@ class TestRackTab: # Сохраняем изменения rack_edit.click_done_button() - rack_edit.wait_for_timeout(2000) # Проверяем уведомление об успешном обновлении - alert = AlertComponent(browser) expected_alert_text = "Элемент успешно обновлён" - alert.check_alert_presence(expected_alert_text) - alert.close_alert_by_text(expected_alert_text) + self.alert.check_alert_presence(expected_alert_text, timeout=5000) - browser.mouse.click(10, 10) + self.alert.check_alert_absence(expected_alert_text, timeout=7000) + + # Закрываем alert с текстом кнопкой 'Закрыть' + try: + self.alert.close_alert_by_text(expected_alert_text) + logger.debug("Alert forcibly closed") + except AssertionError: + logger.debug("Alert already closed by the time forcible close was attempted") # Вход в режим редактирования rack_page.click_edit_button() @@ -302,24 +334,27 @@ class TestRackTab: rack_edit.click_close_button() - #@pytest.mark.develop + logger.debug("General info tab test completed successfully") + def test_rack_image_tab(self, browser: Page) -> None: """Тест вкладки 'Изображение' стойки.""" + logger.debug(f"Starting image tab test for rack: {self.RACK_NAME}") + rack_page = RackPage(browser) # Переходим в режим редактирования rack_page.click_edit_button() rack_page.wait_for_timeout(1000) - # Создаем экземпляр ModalEditRack - rack_edit = ModalEditRack(browser, RACK_NAME) + # Создаем экземпляр EditRackMaker + rack_edit = EditRackMaker(browser, self.RACK_NAME) # Переключаемся на вкладку "Изображение" - rack_edit.switch_to_tab(ModalEditRack.TAB_IMAGE) + rack_edit.switch_to_tab(EditRackMaker.TAB_IMAGE) # Проверяем вкладку - assert rack_edit.is_tab_active(ModalEditRack.TAB_IMAGE), "Image tab should be active" + assert rack_edit.is_tab_active(EditRackMaker.TAB_IMAGE), "Image tab should be active" # Загружаем изображение если есть test_image_path = os.path.join(os.path.dirname(__file__), "test_edit_rack_image.jpg") @@ -339,35 +374,44 @@ class TestRackTab: # Сохраняем rack_edit.click_done_button() - rack_page.wait_for_timeout(2000) # Проверяем уведомление об успешном обновлении - alert = AlertComponent(browser) expected_alert_text = "Элемент успешно обновлён" - alert.check_alert_presence(expected_alert_text) - alert.close_alert_by_text(expected_alert_text) + self.alert.check_alert_presence(expected_alert_text, timeout=5000) + + self.alert.check_alert_absence(expected_alert_text, timeout=7000) + + # Закрываем alert с текстом кнопкой 'Закрыть' + try: + self.alert.close_alert_by_text(expected_alert_text) + logger.debug("Alert forcibly closed") + except AssertionError: + logger.debug("Alert already closed by the time forcible close was attempted") + + logger.debug("Image tab test completed successfully") - @pytest.mark.develop def test_rack_access_rules(self, browser: Page) -> None: """Тест заполнения полей правил доступа. В каждое поле добавляются ВСЕ пользователи из списка custom_users. """ + logger.debug(f"Starting access rules test for rack: {self.RACK_NAME}") + rack_page = RackPage(browser) # Переходим в режим редактирования rack_page.click_edit_button() rack_page.wait_for_timeout(1000) - # Создаем экземпляр ModalEditRack - rack_edit = ModalEditRack(browser, RACK_NAME) + # Создаем экземпляр EditRackMaker + rack_edit = EditRackMaker(browser, self.RACK_NAME) # Переключаемся на вкладку "Настройки" - rack_edit.switch_to_tab(ModalEditRack.TAB_SETTINGS) + rack_edit.switch_to_tab(EditRackMaker.TAB_SETTINGS) # Проверяем, что вкладка активна - assert rack_edit.is_tab_active(ModalEditRack.TAB_SETTINGS), \ + assert rack_edit.is_tab_active(EditRackMaker.TAB_SETTINGS), \ "Settings tab should be active after switching" # Целевые поля для заполнения @@ -420,20 +464,26 @@ class TestRackTab: # Сохраняем изменения rack_edit.click_done_button() - rack_page.wait_for_timeout(2000) # Проверяем уведомление об успешном обновлении - alert = AlertComponent(browser) expected_alert_text = "Элемент успешно обновлён" - alert.check_alert_presence(expected_alert_text) - alert.close_alert_by_text(expected_alert_text) + self.alert.check_alert_presence(expected_alert_text, timeout=5000) + + self.alert.check_alert_absence(expected_alert_text, timeout=7000) + + # Закрываем alert с текстом кнопкой 'Закрыть' + try: + self.alert.close_alert_by_text(expected_alert_text) + logger.debug("Alert forcibly closed") + except AssertionError: + logger.debug("Alert already closed by the time forcible close was attempted") # Возвращаемся в режим редактирования и проверяем снова rack_page.click_edit_button() rack_page.wait_for_timeout(1000) - rack_edit = ModalEditRack(browser, RACK_NAME) - rack_edit.switch_to_tab(ModalEditRack.TAB_SETTINGS) + rack_edit = EditRackMaker(browser, self.RACK_NAME) + rack_edit.switch_to_tab(EditRackMaker.TAB_SETTINGS) verification_results_after_save = rack_edit.verify_access_rules( expected_users=custom_users, @@ -445,3 +495,5 @@ class TestRackTab: f"After save - correctly filled {verification_results_after_save['correctly_filled']} out of {expected_total}" rack_edit.click_close_button() + + logger.debug("Access rules test completed successfully") diff --git a/tests/e2e/elements/test_management_rack.py b/tests/e2e/elements/test_management_rack.py index 20c6f66..a7685d6 100644 --- a/tests/e2e/elements/test_management_rack.py +++ b/tests/e2e/elements/test_management_rack.py @@ -6,149 +6,37 @@ import pytest from playwright.sync_api import Page +from tools.logger import get_logger from locators.navigation_panel_locators import NavigationPanelLocators -from components_derived.accounting_objects.rack_maker import RackObjectMaker, RackData -from components_derived.frames.create_child_element_frame import CreateChildElementFrame -from components_derived.modal_edit_rack import ModalEditRack +from frames.create_element_frame import CreateElementFrame +from forms.create_rack_form import CreateRackForm, CreateRackData +from makers.edit_rack_maker import EditRackMaker from pages.location_page import LocationPage from pages.login_page import LoginPage from pages.main_page import MainPage from pages.rack_page import RackPage from components.alert_component import AlertComponent -from tools.logger import get_logger -# Константы -RACK_NAME = "Test-Rack-Functionality" -# Инициализация логгера для всего модуля logger = get_logger("RACK_MANAGEMENT_TESTS") logger.setLevel("INFO") -class TestRackTab: + +class TestRackManagement: """Набор тестов для вкладки 'Стойка' в модуле Объекты. Проверяет корректность отображения, функциональность элементов интерфейса и переключение между вкладками стойки оборудования. - - Тесты покрывают следующие функциональные области: - 1. test_rack_tab_content - Базовая структура и содержимое вкладки стойки """ + # Имя тестовой стойки + RACK_NAME = "Test-Rack-Functionality" + # Инициализируем атрибуты main_page: MainPage = None location_page: LocationPage = None - - def _check_rack_existance(self, browser: Page, rack_name: str) -> bool: - """Проверяет существование стойки. - - Args: - browser: Страница Playwright - rack_name: Имя стойки для проверки - - Returns: - bool: True если стойка существует, False в противном случае - """ - - # Обновляем навигационную панель - self.main_page.wait_for_timeout(500) - self.main_page.click_subpanel_item("test-zone") - - nav_panel_locator = NavigationPanelLocators.TREEVIEW - - # Проверяем видимость элемента - element = browser.locator(nav_panel_locator).get_by_text(rack_name, exact=True).first - - if element.is_visible(): - return True - return False - - def _create_rack(self, browser: Page, rack_name: str) -> None: - """Создает стойку. - - Args: - browser: Страница Playwright - rack_name: Имя стойки для создания - """ - logger.debug(f"Creating rack: {rack_name}") - - # Нажимаем кнопку "Создать" на тулбаре - self.location_page.click_create_button() - - # Создаем фрейм создания дочернего элемента - create_child_frame = CreateChildElementFrame(browser) - - # Нажимаем на плашку "Класс объекта учета" - create_child_frame.open_object_class_combobox() - - # Из выпадающего меню выбираем пункт "Стойка" - create_child_frame.select_object_class("Стойка") - - # Открывается набор плашек для задания параметров стойки - rack_maker = RackObjectMaker(browser) - - # Создаем объект данных стойки - rack_data = RackData( - name=rack_name, - height="42", - depth="1000" - ) - - # Заполняем данные стойки - rack_maker.fill_rack_data(rack_data) - - # Нажимаем кнопку создания - create_child_frame.click_add_button() - - # Проверяем уведомление об успешном создании - alert = AlertComponent(browser) - expected_alert_text = f"Элемент {rack_name} создан" - alert.check_alert_presence(expected_alert_text) - alert.close_alert_by_text(expected_alert_text) - - logger.info(f"Rack '{rack_name}' created successfully") - - def _delete_rack_from_context_menu(self, browser: Page, rack_name: str) -> None: - """Удаляет стойку через контекстное меню. - - Args: - browser: Страница Playwright - rack_name: Имя стойки для удаления - """ - - # 1. Находим элемент стойки в навигационной панели - rack_element = browser.locator( - NavigationPanelLocators.TREEVIEW - ).get_by_text(rack_name, exact=True).first - - # Прокручиваем до элемента если нужно - rack_element.scroll_into_view_if_needed() - self.main_page.wait_for_timeout(500) - - # 2. Проверяем и нажимаем кнопку "Изменить" - rack_page = RackPage(browser) - - # Проверяем видимость и тултип кнопки - rack_page.should_be_toolbar_buttons() - - # Кликаем на кнопку "Изменить" - rack_page.click_edit_button() - - self.main_page.wait_for_timeout(1000) - - # 3. Создаем экземпляр ModalRackEditRack - rack_edit = ModalEditRack(browser, rack_name) - - # Используем метод для удаления - rack_edit.click_remove_button() - self.main_page.wait_for_timeout(1000) - - # 4. Проверяем уведомление об успешном удалении - alert = AlertComponent(browser) - expected_alert_text = "Успешно удалено" - alert.check_alert_presence(expected_alert_text) - alert.close_alert_by_text(expected_alert_text) - - logger.info(f"Rack '{rack_name}' deleted successfully") + alert: AlertComponent = None + create_child_frame: CreateElementFrame = None @pytest.fixture(scope="function", autouse=True) def setup(self, browser: Page) -> None: @@ -156,12 +44,15 @@ class TestRackTab: Выполняет: 1. Авторизацию в системе - 2. Создание стойки если она не существует - 3. Переход к стойке + 2. Переход к локации test-zone + 3. Инициализацию компонентов + 4. Создание стойки если она не существует + 5. Переход к стойке Args: - browser (Page): Экземпляр страницы Playwright для взаимодействия с UI + browser: Экземпляр страницы Playwright для взаимодействия с UI """ + # Авторизация в системе login_page = LoginPage(browser) login_page.do_login() @@ -178,15 +69,28 @@ class TestRackTab: # Создаем экземпляр страницы локации self.location_page = LocationPage(browser) + # Инициализируем компонент алертов (вынесено в атрибуты класса) + self.alert = AlertComponent(browser) + + # Инициализируем фрейм создания дочернего элемента (вынесено в атрибуты класса) + self.create_child_frame = CreateElementFrame(browser) + # Проверяем существование стойки - if not self._check_rack_existance(browser, RACK_NAME): - self._create_rack(browser, RACK_NAME) + if not self._check_rack_existance(browser, self.RACK_NAME): + logger.info(f"Rack '{self.RACK_NAME}' does not exist. Creating...") + + rack_data = CreateRackData( + name=self.RACK_NAME, + usize="42", + depth="1000" + ) + self._create_rack(browser, rack_data) self.main_page.wait_for_timeout(3000) else: - logger.info(f"Rack '{RACK_NAME}' already exists") + logger.info(f"Rack '{self.RACK_NAME}' already exists") # Переходим к стойке для тестирования - self.main_page.click_subpanel_item(RACK_NAME, parent="test-zone") + self.main_page.click_subpanel_item(self.RACK_NAME, parent="test-zone") self.main_page.wait_for_timeout(3000) @pytest.fixture(scope="class", autouse=True) @@ -199,9 +103,12 @@ class TestRackTab: Args: browser: Экземпляр страницы Playwright """ + # Тесты выполняются здесь yield + logger.debug(f"Cleaning up rack: {self.RACK_NAME}") + # Переходим на главную страницу и в нужную зону login_page = LoginPage(browser) login_page.do_login() @@ -215,21 +122,142 @@ class TestRackTab: self.main_page.click_main_navigation_panel_item("test-zone") self.main_page.wait_for_timeout(1000) + # Инициализируем компонент алертов для cleanup + self.alert = AlertComponent(browser) + # Проверяем существование стойки - if self._check_rack_existance(browser, RACK_NAME): + if self._check_rack_existance(browser, self.RACK_NAME): # Переходим на страницу стойки - self.main_page.click_subpanel_item(RACK_NAME, parent="test-zone") + self.main_page.click_subpanel_item(self.RACK_NAME, parent="test-zone") self.main_page.wait_for_timeout(2000) # Удаляем стойку - self._delete_rack_from_context_menu(browser, RACK_NAME) + self._delete_rack(browser, self.RACK_NAME) # Дополнительная проверка self.main_page.click_subpanel_item("test-zone") self.main_page.wait_for_timeout(1000) - #@pytest.mark.develop + def _check_rack_existance(self, browser: Page, rack_name: str) -> bool: + """Проверяет существование стойки. + + Args: + browser: Страница Playwright + rack_name: Имя стойки для проверки + + Returns: + bool: True если стойка существует, False в противном случае + """ + + logger.debug(f"Checking existence of rack with name '{rack_name}'") + + self.main_page.click_subpanel_item("test-zone") + + nav_panel_locator = NavigationPanelLocators.TREEVIEW + element = browser.locator(nav_panel_locator).get_by_text(rack_name, exact=True).first + + if element.is_visible(): + logger.debug(f"Rack with name '{rack_name}' found") + return True + + logger.debug(f"Rack with name '{rack_name}' not found") + return False + + def _create_rack(self, browser: Page, rack_data: CreateRackData) -> None: + """Создает стойку. + + Args: + browser: Страница Playwright + rack_data: Данные стойки для создания + """ + + logger.debug(f"Creating rack with name '{rack_data.name}'") + + # Нажимаем кнопку "Создать" на тулбаре + self.location_page.click_create_button() + + # Нажимаем на плашку "Класс объекта учета" + self.create_child_frame.open_object_class_combobox() + + # Из выпадающего меню выбираем пункт "Стойка" + self.create_child_frame.select_object_class("Стойка") + + # Создаем форму создания стойки + rack_form = CreateRackForm(browser) + + # Заполняем данные стойки + fill_results = rack_form.fill_rack_data(rack_data) + logger.debug(f"Fill results: {fill_results}") + + # Нажимаем кнопку создания + self.create_child_frame.click_add_button() + + # Ждем появления alert с текстом + expected_alert_text = f"Элемент {rack_data.name} создан" + self.alert.check_alert_presence(expected_alert_text, timeout=5000) + + self.alert.check_alert_absence(expected_alert_text, timeout=7000) + + # Закрываем alert с текстом кнопкой 'Закрыть' + try: + self.alert.close_alert_by_text(expected_alert_text) + logger.debug("Alert forcibly closed") + except AssertionError: + # Если уже закрылся - игнорируем + logger.debug("Alert already closed by the time forcible close was attempted") + + logger.info(f"Rack '{rack_data.name}' created successfully") + + def _delete_rack(self, browser: Page, rack_name: str) -> None: + """Удаляет стойку через контекстное меню. + + Args: + browser: Страница Playwright + rack_name: Имя стойки для удаления + """ + + # Находим элемент стойки в навигационной панели + rack_element = browser.locator( + NavigationPanelLocators.TREEVIEW + ).get_by_text(rack_name, exact=True).first + + # Прокручиваем до элемента если нужно + rack_element.scroll_into_view_if_needed() + self.main_page.wait_for_timeout(500) + + # Проверяем и нажимаем кнопку "Изменить" + rack_page = RackPage(browser) + + # Проверяем видимость и тултип кнопки + rack_page.should_be_toolbar_buttons() + + # Кликаем на кнопку "Изменить" + rack_page.click_edit_button() + self.main_page.wait_for_timeout(1000) + + # Создаем экземпляр EditRackMaker + rack_edit = EditRackMaker(browser, rack_name) + + # Используем метод для удаления + rack_edit.click_remove_button() + + # Проверяем уведомление об успешном удалении + expected_alert_text = "Успешно удалено" + self.alert.check_alert_presence(expected_alert_text, timeout=5000) + + self.alert.check_alert_absence(expected_alert_text, timeout=7000) + + # Закрываем alert с текстом кнопкой 'Закрыть' + try: + self.alert.close_alert_by_text(expected_alert_text) + logger.debug("Alert forcibly closed") + except AssertionError: + # Если уже закрылся - игнорируем + logger.debug("Alert already closed by the time forcible close was attempted") + + logger.info(f"Rack '{rack_name}' deleted successfully") + def test_rack_tab_content(self, browser: Page) -> None: """Тест содержимого вкладки 'Стойка'. @@ -240,30 +268,34 @@ class TestRackTab: 4. Корректность отображения юнитов и устройств на стойке Args: - browser (Page): Экземпляр страницы Playwright для взаимодействия с UI + browser: Экземпляр страницы Playwright для взаимодействия с UI """ + logger.debug(f"Starting test for rack tab content with rack: {self.RACK_NAME}") + expected_toolbar_subtitles = [ "test-zone", 'chevron_right', - RACK_NAME - ] + self.RACK_NAME + ] - rt = RackPage(browser) - rt.should_be_panel_header(expected_toolbar_subtitles) + rack_page = RackPage(browser) + rack_page.should_be_panel_header(expected_toolbar_subtitles) # Комплексная проверка отображения обеих сторон стойки с детальной информацией - rt.should_be_rack_sides_displayed() + rack_page.should_be_rack_sides_displayed() # Проверка кнопки "Скрыть стойку" - rt.should_have_hide_rack_button() + rack_page.should_have_hide_rack_button() # Проверка кнопки "Показать стойку" - rt.should_have_show_rack_button() + rack_page.should_have_show_rack_button() # Проверяем переключение между всеми вкладками стойки - rt.check_tab_switching() + rack_page.check_tab_switching() - # Переход в режим редактирования - rt.should_be_toolbar_buttons() - rt.wait_for_timeout(1000) + # Проверям наличие кнопки редактирования + rack_page.should_be_toolbar_buttons() + rack_page.wait_for_timeout(1000) + + logger.debug("Test for rack tab content completed successfully")