475 lines
21 KiB
Python
475 lines
21 KiB
Python
"""Тест создания дочернего элемента 'Стойка'."""
|
||
|
||
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 pages.location_page import LocationPage
|
||
from makers.edit_rack_maker import EditRackMaker
|
||
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("CREATE_RACK_TEST")
|
||
logger.setLevel("INFO")
|
||
|
||
|
||
class TestCreateRack:
|
||
"""Тест создания дочернего элемента типа 'Стойка'."""
|
||
|
||
# Единое имя для тестовой стойки
|
||
TEST_RACK_NAME = "Test-Rack-Create"
|
||
|
||
# Для теста с дубликатом используем отдельное имя
|
||
DUPLICATE_RACK_NAME = "Test-Rack-Duplicate"
|
||
|
||
# Инициализируем атрибуты
|
||
main_page: MainPage = None
|
||
location_page: LocationPage = None
|
||
alert: AlertComponent = None
|
||
create_child_frame: CreateElementFrame = None
|
||
rack_form: CreateRackForm = None
|
||
|
||
@pytest.fixture(scope="function", autouse=True)
|
||
def setup(self, browser: Page) -> None:
|
||
"""Фикстура для подготовки тестового окружения.
|
||
|
||
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(2000)
|
||
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)
|
||
|
||
# Инициализируем форму создания Стойки
|
||
self.rack_form = CreateRackForm(browser)
|
||
|
||
@pytest.fixture
|
||
def cleanup_racks(self, browser: Page):
|
||
"""Фикстура для очистки созданных стоек."""
|
||
|
||
created_racks = []
|
||
yield created_racks
|
||
|
||
# После завершения теста удаляем созданные стойки
|
||
if created_racks:
|
||
logger.debug(f"Cleaning up racks: {created_racks}")
|
||
|
||
self.main_page.wait_for_timeout(500)
|
||
self.main_page.click_subpanel_item("test-zone")
|
||
self.main_page.wait_for_timeout(1000)
|
||
|
||
for rack_name in created_racks:
|
||
if self._check_rack_existance(browser, rack_name):
|
||
logger.debug(f"Deleting rack '{rack_name}'...")
|
||
self.main_page.click_subpanel_item(rack_name, parent="test-zone")
|
||
self.main_page.wait_for_timeout(1000)
|
||
self._delete_rack(browser, rack_name)
|
||
self.main_page.click_subpanel_item("test-zone")
|
||
self.main_page.wait_for_timeout(500)
|
||
|
||
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=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 _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 test_create_rack_content(self, browser: Page) -> None:
|
||
"""Тест проверки содержимого формы создания стойки."""
|
||
|
||
# Проверяем что кнопка "Создать" доступна
|
||
self.location_page.should_be_toolbar_buttons()
|
||
|
||
# Нажимаем кнопку "Создать" на тулбаре
|
||
self.location_page.click_create_button()
|
||
|
||
# Проверяем заголовок формы создания
|
||
self.create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||
|
||
# Нажимаем на плашку "Класс объекта учета"
|
||
self.create_child_frame.open_object_class_combobox()
|
||
|
||
# Из выпадающего меню выбираем пункт "Стойка"
|
||
self.create_child_frame.select_object_class("Стойка")
|
||
|
||
# Создаем форму создания стойки и проверяем наличие полей
|
||
rack_form = CreateRackForm(browser)
|
||
|
||
# Проверяем, что основные поля присутствуют
|
||
assert rack_form.get_content_item("name_input") is not None, "Name field not initialized"
|
||
assert rack_form.get_content_item("usize_input") is not None, "Height field not initialized"
|
||
assert rack_form.get_content_item("depth_input") is not None, "Depth field not initialized"
|
||
|
||
logger.debug("Rack-specific fields are displayed correctly")
|
||
self.create_child_frame.should_be_toolbar_buttons()
|
||
|
||
def test_create_rack(self, browser: Page, cleanup_racks) -> None:
|
||
"""Тест создания дочернего элемента типа 'Стойка'."""
|
||
|
||
logger.debug(f"Starting test with rack name: {self.TEST_RACK_NAME}")
|
||
|
||
# Создаем данные стойки с расширенным набором полей
|
||
rack_data = CreateRackData(
|
||
name=self.TEST_RACK_NAME,
|
||
usize="42",
|
||
depth="1000",
|
||
serial="TEST123456",
|
||
inventory="INV-001",
|
||
comment="Тестовая стойка для автоматизации",
|
||
cable_entry="сверху",
|
||
state="Введен в эксплуатацию",
|
||
# owner="Владелец",
|
||
# service_org="Обслуживающая организация",
|
||
# project="Проект/Титул"
|
||
)
|
||
|
||
# Сохраняем имя стойки для очистки
|
||
cleanup_racks.append(rack_data.name)
|
||
|
||
# Проверяем, существует ли уже стойка с таким именем
|
||
if self._check_rack_existance(browser, rack_data.name):
|
||
logger.warning(f"Rack '{rack_data.name}' already exists. Deleting it before creating new one...")
|
||
|
||
# Переходим к стойке для удаления
|
||
self.main_page.click_subpanel_item(rack_data.name, parent="test-zone")
|
||
self.main_page.wait_for_timeout(1000)
|
||
|
||
# Удаляем существующую стойку
|
||
self._delete_rack(browser, rack_data.name)
|
||
logger.debug(f"Existing rack '{rack_data.name}' deleted successfully")
|
||
|
||
# Создаем новую стойку
|
||
self._create_rack(browser, rack_data)
|
||
|
||
# Проверяем, что стойка создана и отображается
|
||
logger.debug(f"Verifying that rack '{rack_data.name}' was created...")
|
||
self.main_page.click_main_navigation_panel_item("test-zone")
|
||
|
||
rack_exists = self._check_rack_existance(browser, rack_data.name)
|
||
assert rack_exists, f"Rack '{rack_data.name}' should be visible in navigation panel after creation"
|
||
|
||
logger.debug(f"Rack '{rack_data.name}' is visible in navigation panel")
|
||
logger.debug("Test for creating 'Rack' child element completed successfully")
|
||
|
||
def test_create_rack_with_duplicate_name(self, browser: Page, cleanup_racks) -> None:
|
||
"""Тест создания стойки с уже существующим именем."""
|
||
|
||
logger.debug(f"Starting test for creating rack with duplicate name: {self.DUPLICATE_RACK_NAME}")
|
||
|
||
rack_name = self.DUPLICATE_RACK_NAME
|
||
|
||
# Создаем первую стойку если её нет
|
||
if not self._check_rack_existance(browser, rack_name):
|
||
logger.debug(f"Creating first rack with name '{rack_name}'")
|
||
|
||
first_rack_data = CreateRackData(
|
||
name=rack_name,
|
||
usize="42",
|
||
depth="1000"
|
||
)
|
||
self._create_rack(browser, first_rack_data)
|
||
cleanup_racks.append(rack_name)
|
||
|
||
# Пытаемся создать вторую стойку с тем же именем
|
||
logger.debug(f"Attempting to create second rack with name '{rack_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)
|
||
|
||
duplicate_rack_data = CreateRackData(
|
||
name=rack_name,
|
||
usize="42",
|
||
depth="450"
|
||
)
|
||
|
||
self.create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||
|
||
rack_form.fill_rack_data(duplicate_rack_data)
|
||
self.create_child_frame.click_add_button()
|
||
|
||
expected_alert_text = f"Имя {rack_name} уже используется"
|
||
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("System prevented creating rack with duplicate name")
|
||
|
||
def test_required_fields_validation(self, browser: Page, cleanup_racks) -> None:
|
||
"""Тест проверки обязательных полей при создании стойки."""
|
||
logger.debug("Starting required fields validation test")
|
||
|
||
expected_alert_text_height = "поле Высота в юнитах должно быть заполнено"
|
||
expected_alert_text_depth = "поле Глубина (мм) должно быть заполнено"
|
||
expected_alert_text_name = "Поле Имя должно быть установлено"
|
||
|
||
self.main_page.click_main_navigation_panel_item("test-zone")
|
||
|
||
# Открываем форму создания
|
||
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)
|
||
|
||
# ========== Тест 1: Обязательные поля высота и глубина пустые ==========
|
||
logger.debug("Test 1: Both required fields (height, depth) are empty")
|
||
|
||
# Очищаем поля высоты и глубины перед заполнением
|
||
rack_form.clear_field("Высота в юнитах")
|
||
rack_form.clear_field("Глубина (мм)")
|
||
|
||
test_data_1 = CreateRackData(
|
||
name=self.TEST_RACK_NAME,
|
||
usize="",
|
||
depth=""
|
||
)
|
||
|
||
rack_form.fill_rack_data(test_data_1)
|
||
self.create_child_frame.click_add_button()
|
||
self.create_child_frame.wait_for_timeout(500)
|
||
|
||
# Проверяем alert для высоты, глубины
|
||
self.alert.check_alert_presence(expected_alert_text_height, timeout=7000)
|
||
self.alert.check_alert_presence(expected_alert_text_depth, timeout=7000)
|
||
|
||
# Проверяем, закрылся ли автоматически alert для высоты, глубины
|
||
self.alert.check_alert_absence(expected_alert_text_height, timeout=7000)
|
||
self.alert.check_alert_absence(expected_alert_text_depth, timeout=500)
|
||
|
||
# Проверяем подсветку полей
|
||
field_status = rack_form.verify_required_fields_highlighted(["Высота в юнитах", "Глубина (мм)"])
|
||
logger.debug(f"Field status after test 1: {field_status}")
|
||
assert field_status.get("Высота в юнитах"), f"Height field should be highlighted, got: {field_status}"
|
||
assert field_status.get("Глубина (мм)"), f"Depth field should be highlighted, got: {field_status}"
|
||
|
||
# ========== Тест 2: Только высота заполнена ==========
|
||
logger.debug("Test 2: Only height field is filled")
|
||
|
||
# Очищаем поле глубины перед новым заполнением
|
||
rack_form.clear_field("Глубина (мм)")
|
||
|
||
test_data_2 = CreateRackData(
|
||
name=self.TEST_RACK_NAME,
|
||
usize="42",
|
||
depth=""
|
||
)
|
||
|
||
rack_form.fill_rack_data(test_data_2)
|
||
self.create_child_frame.click_add_button()
|
||
|
||
# Проверяем alert для глубины
|
||
self.alert.check_alert_presence(expected_alert_text_depth, timeout=7000)
|
||
|
||
# Проверяем, закрылся ли автоматически alert для глубины
|
||
self.alert.check_alert_absence(expected_alert_text_depth, timeout=7000)
|
||
|
||
# Проверяем подсветку полей
|
||
field_status = rack_form.verify_required_fields_highlighted(["Глубина (мм)"])
|
||
logger.debug(f"Field status after test 2: {field_status}")
|
||
assert field_status.get("Глубина (мм)"), f"Depth field should be highlighted, got: {field_status}"
|
||
|
||
# ========== Тест 3: Только глубина заполнена ==========
|
||
logger.debug("Test 3: Only depth field is filled")
|
||
|
||
# Очищаем поле высоты перед новым заполнением
|
||
rack_form.clear_field("Высота в юнитах")
|
||
|
||
test_data_3 = CreateRackData(
|
||
name=self.TEST_RACK_NAME,
|
||
usize="",
|
||
depth="1000"
|
||
)
|
||
|
||
rack_form.fill_rack_data(test_data_3)
|
||
self.create_child_frame.click_add_button()
|
||
|
||
# Проверяем alert для высоты
|
||
self.alert.check_alert_presence(expected_alert_text_height, timeout=7000)
|
||
|
||
# Проверяем, закрылся ли автоматически alert для высоты
|
||
self.alert.check_alert_absence(expected_alert_text_height, timeout=7000)
|
||
|
||
# Проверяем подсветку полей
|
||
field_status = rack_form.verify_required_fields_highlighted(["Высота в юнитах"])
|
||
logger.debug(f"Field status after test 3: {field_status}")
|
||
assert field_status.get("Высота в юнитах"), f"Height field should be highlighted, got: {field_status}"
|
||
|
||
# ========== Тест 4: Поле "Имя" не заполнено ==========
|
||
logger.debug("Test 4: Name field is empty")
|
||
|
||
# Очищаем поле имени
|
||
rack_form.clear_field("Имя")
|
||
|
||
test_data_4 = CreateRackData(
|
||
name="",
|
||
usize="42",
|
||
depth="1000"
|
||
)
|
||
|
||
rack_form.fill_rack_data(test_data_4)
|
||
self.create_child_frame.click_add_button()
|
||
self.create_child_frame.wait_for_timeout(500)
|
||
|
||
# Проверяем alert для имени
|
||
self.alert.check_alert_presence(expected_alert_text_name, timeout=7000)
|
||
|
||
# Проверяем, закрылся ли автоматически alert для высоты
|
||
self.alert.check_alert_absence(expected_alert_text_name, timeout=7000)
|
||
|
||
logger.debug("Test 4 completed: System correctly validates empty name field")
|