"""Модуль тестов редактирования стойки в модуле Объекты. Содержит тесты для проверки функциональности редактирования стойки оборудования. """ 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.rack_page import RackPage from components.alert_component import AlertComponent logger = get_logger("RACK_EDIT_TESTS") logger.setLevel("INFO") class TestRackEdit: """Набор тестов для редактирования стойки в модуле Объекты. Проверяет функциональность редактирования различных вкладок стойки: 1. Общая информация 2. Изображение 3. Правила доступа """ # Имя тестовой стойки RACK_NAME = "Test-Rack-Edit" # Инициализируем атрибуты main_page: MainPage = None location_page: LocationPage = None alert: AlertComponent = None create_child_frame: CreateElementFrame = None @pytest.fixture(scope="function", autouse=True) def setup(self, browser: Page) -> None: """Фикстура для подготовки тестового окружения. Выполняет: 1. Авторизацию в системе 2. Переход к локации test-zone 3. Инициализацию компонентов 4. Создание стойки если она не существует 5. Переход к стойке Args: browser: Экземпляр страницы Playwright для взаимодействия с UI """ # Авторизация в системе login_page = LoginPage(browser) login_page.do_login() # Мы на главной странице self.main_page = MainPage(browser) self.main_page.should_be_navigation_panel() # Переходим к Объектам self.main_page.click_main_navigation_panel_item("Объекты") self.main_page.wait_for_timeout(1000) self.main_page.click_main_navigation_panel_item("test-zone") # Создаем экземпляр страницы локации self.location_page = LocationPage(browser) # Инициализируем компонент алертов (вынесено в атрибуты класса) self.alert = AlertComponent(browser) # Инициализируем фрейм создания дочернего элемента (вынесено в атрибуты класса) self.create_child_frame = CreateElementFrame(browser) # Проверяем существование стойки 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 '{self.RACK_NAME}' already exists") # Переходим к стойке для тестирования 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): """Фикстура для очистки созданной стойки после ВСЕХ тестов класса. Выполняется один раз после завершения всех тестов класса TestRackEdit. Удаляет созданную стойку. Args: browser: Экземпляр страницы Playwright """ # Тесты выполняются здесь yield logger.debug(f"Cleaning up rack: {self.RACK_NAME}") # Переходим на главную страницу и в нужную зону login_page = LoginPage(browser) login_page.do_login() self.main_page = MainPage(browser) self.main_page.should_be_navigation_panel() # Переходим к Объектам self.main_page.click_main_navigation_panel_item("Объекты") self.main_page.wait_for_timeout(1000) 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, self.RACK_NAME): # Переходим на страницу стойки self.main_page.click_subpanel_item(self.RACK_NAME, parent="test-zone") self.main_page.wait_for_timeout(2000) # Удаляем стойку self._delete_rack(browser, self.RACK_NAME) # Дополнительная проверка self.main_page.click_subpanel_item("test-zone") self.main_page.wait_for_timeout(1000) 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"Успешно создано" self.alert.check_alert_presence(expected_alert_text, timeout=7000) 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=7000) 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) # Создаем экземпляр EditRackMaker rack_edit = EditRackMaker(browser, self.RACK_NAME) # Создаем тестовые данные для заполнения всех полей rack_edit_data = EditRackData( # Основные поля name=self.RACK_NAME, serial="SN123456789", inventory="INV987654321", comment="Тестовый комментарий для стойки (обновленный)", allocated_power="5500", # Combobox поля cable_entry="сверху", state="Введен в эксплуатацию", owner="", service_org="", project="", # Checkbox поля ventilation_panel=True, ) # Заполняем все поля формы results = rack_edit.fill_rack_data(rack_edit_data) logger.debug(f"Fill results: {results}") # Сохраняем изменения rack_edit.click_done_button() # Проверяем уведомление об успешном обновлении expected_alert_text = "Успешно обновлено" self.alert.check_alert_presence(expected_alert_text, timeout=7000) 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() # Проверяем поля, пропуская недоступные verification_results = rack_edit.verify_all_filled_fields( rack_edit_data, skip_fields=["Владелец", "Обслуживающая организация", "Проект/Титул"] ) logger.debug(f"Verification results: {verification_results}") # Проверяем результаты assert verification_results["incorrectly_filled"] == 0, \ f"Available fields incorrectly filled: {verification_results['field_errors']}" assert verification_results["not_filled"] == 0, \ f"Available fields not filled: {verification_results['field_errors']}" rack_edit.click_close_button() logger.debug("General info tab test completed successfully") def test_required_field_name_validation(self, browser: Page) -> None: """Тест проверки обязательного поля ИМЯ при создании стойки.""" logger.debug(f"Starting required field name validation test for rack: {self.RACK_NAME}") rack_page = RackPage(browser) # Переходим в режим редактирования rack_page.click_edit_button() # Создаем экземпляр EditRackMaker rack_edit = EditRackMaker(browser, self.RACK_NAME) # ========== Тест 1: Обязательное поле имя пустое ========== # Очищаем поле имя rack_edit.clear_field("Имя") # Создаем тестовые данные для заполнения поля test_data_1 = EditRackData( name="" ) rack_edit.fill_rack_data(test_data_1) rack_edit.click_done_button() # Проверяем уведомление об ошибочном обновлении expected_alert_text = "поле ИМЯ должно быть заполнено, и не должно превышать 35 знаков" self.alert.check_alert_presence(expected_alert_text, timeout=7000) self.alert.check_alert_absence(expected_alert_text, timeout=7000) # ========== Тест 2: Обязательное поле имя не должно превышать 35 знаков ========== # Создаем тестовые данные для заполнения поля test_data_2 = EditRackData( name="_123456789_123456789_123456789_12345" ) rack_edit.fill_rack_data(test_data_2) rack_edit.click_done_button() # Проверяем уведомление об ошибочном обновлении expected_alert_text = "поле ИМЯ должно быть заполнено, и не должно превышать 35 знаков" self.alert.check_alert_presence(expected_alert_text, timeout=7000) self.alert.check_alert_absence(expected_alert_text, timeout=7000) rack_edit.click_close_button() logger.debug("Required field name validation 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) # Создаем экземпляр EditRackMaker rack_edit = EditRackMaker(browser, self.RACK_NAME) # Переключаемся на вкладку "Изображение" rack_edit.switch_to_tab(EditRackMaker.TAB_IMAGE) # Проверяем вкладку 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") if os.path.exists(test_image_path): logger.debug(f"Found test image: {test_image_path}") # Находим input и загружаем файл file_input = browser.locator("input[type='file']") if file_input.count() == 0: file_input = browser.locator(".button-file-upload__input") if file_input.count() > 0: file_input.set_input_files(test_image_path) rack_page.wait_for_timeout(2000) logger.debug("Test image uploaded") else: logger.warning(f"Test image not found at: {test_image_path}") # Сохраняем rack_edit.click_done_button() # Проверяем уведомление об успешном обновлении expected_alert_text = "Успешно обновлено" self.alert.check_alert_presence(expected_alert_text, timeout=7000) 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") 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) # Создаем экземпляр EditRackMaker rack_edit = EditRackMaker(browser, self.RACK_NAME) # Переключаемся на вкладку "Настройки" rack_edit.switch_to_tab(EditRackMaker.TAB_SETTINGS) # Проверяем, что вкладка активна assert rack_edit.is_tab_active(EditRackMaker.TAB_SETTINGS), \ "Settings tab should be active after switching" # Целевые поля для заполнения target_fields = [ "read_access_rules", "write_access_rules", "sms_access_rules", "email_access_rules", "push_access_rules" ] # Пользователи для добавления в каждое поле custom_users = [ "admin", "manager", "operator", "sec", "collector" ] # Заполняем поля fill_results = rack_edit.fill_access_rules( users_to_add=custom_users, target_fields=target_fields ) # Проверяем, что все пользователи были добавлены expected_total = len(target_fields) * len(custom_users) assert fill_results["access_rules_filled"] == expected_total, \ f"Added {fill_results['access_rules_filled']} users, expected {expected_total}" assert len(fill_results["errors"]) == 0, \ f"Errors during filling: {fill_results['errors']}" # Проверяем заполнение verification_results = rack_edit.verify_access_rules( expected_users=custom_users, target_fields=target_fields ) logger.debug(f"Verification results: {verification_results}") # Проверяем результаты assert verification_results["correctly_filled"] == expected_total, \ f"Correctly filled {verification_results['correctly_filled']} out of {expected_total}" assert verification_results["incorrectly_filled"] == 0, \ f"Verification errors: {verification_results['field_errors']}" # Дополнительная проверка assert len(verification_results["fields_verified"]) == len(target_fields), \ f"Fields verified: {len(verification_results['fields_verified'])}, expected: {len(target_fields)}" # Сохраняем изменения rack_edit.click_done_button() # Проверяем уведомление об успешном обновлении expected_alert_text = "Успешно обновлено" self.alert.check_alert_presence(expected_alert_text, timeout=7000) 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 = 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, target_fields=target_fields ) logger.debug(f"Verification results after save: {verification_results_after_save}") assert verification_results_after_save["correctly_filled"] == expected_total, \ 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")