e-nms_qa_automation/components_derived/frames/create_child_element_frame.py

285 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""Модуль фрейма создания дочернего элемента."""
import re
from playwright.sync_api import expect, Page, Locator
from tools.logger import get_logger
from locators.rack_locators import RackLocators
from locators.selection_bar_locators import SelectionBarLocators
from components.alert_component import AlertComponent
from components.base_component import BaseComponent
from components.toolbar_component import ToolbarComponent
from components_derived.selection_bar_component import SelectionBarComponent
logger = get_logger("CREATE_CHILD_ELEMENT_FRAME")
logger.setLevel("INFO")
class CreateChildElementFrame(BaseComponent):
"""Фрейм создания дочернего элемента."""
def __init__(self, page: Page) -> None:
"""
Инициализирует фрейм создания дочернего элемента.
Args:
page: Экземпляр страницы Playwright
"""
super().__init__(page)
# Инициализация компонентов
self.toolbar = ToolbarComponent(page, "Создать дочерний элемент в")
self.selection_bar = SelectionBarComponent(page, "Класс объекта учета")
self.alert = AlertComponent(page)
# Кнопка "Добавить" - первая кнопка в тулбаре фрейма создания
add_button_locator = self.page.get_by_role("navigation").filter(
has_text="Создать дочерний элемент в"
).get_by_role("button").nth(0)
# Кнопка "Отменить" - используем рабочий локатор из старой версии
cancel_button_locator = self.page.get_by_role("navigation").filter(
has_text=re.compile('Создать дочерний элемент в')
).get_by_role("button").nth(1)
# Инициализация кнопок
self.toolbar.add_tooltip_button(add_button_locator, "add")
self.toolbar.add_tooltip_button(cancel_button_locator, "cancel")
# Действия:
def clear_combobox_field(self, field_name: str) -> None:
"""
Очищает combobox поле по его названию.
Args:
field_name: Название поля для очистки
"""
logger.debug(f"Clearing combobox field '{field_name}'...")
# Получаем контейнер формы
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
fields_locators = self.get_input_fields_locators(container_locator)
if field_name not in fields_locators:
logger.warning(f"Field '{field_name}' not found in form")
return
# Получаем контейнер поля
field_container = fields_locators[field_name]
# Прокручиваем до поля
field_container.scroll_into_view_if_needed()
self.wait_for_timeout(500)
# Проверяем видимость
if not field_container.is_visible():
logger.debug(f"Field '{field_name}' is not visible after scrolling")
return
# Ищем кнопку закрытия (крестик) внутри контейнера поля
close_button = field_container.locator("i.mdi-close").first
# Проверяем наличие и видимость кнопки закрытия
if close_button.count() > 0:
logger.debug(f"Found close button for field '{field_name}'")
# Если кнопка закрытия видима - кликаем на нее
close_button.click(force=True)
self.wait_for_timeout(500)
logger.debug(f"Combobox field '{field_name}' cleared using close button")
else:
logger.debug(f"Close button (i.mdi-close) not found for field '{field_name}'")
def click_add_button(self) -> None:
"""Кликает на кнопку 'Добавить'."""
logger.debug("Clicking on 'Add' button...")
self.toolbar.click_button("add")
def click_cancel_button(self) -> None:
"""Кликает на кнопку 'Отменить'."""
logger.debug("Clicking on 'Cancel' button...")
self.toolbar.click_button("cancel")
def get_selected_object_class(self) -> str:
"""
Получает выбранный класс объекта учета.
Returns:
str: Выбранный класс объекта или пустая строка если ничего не выбрано
"""
return self.selection_bar.get_selection_bar_title()
def open_object_class_combobox(self) -> None:
"""Открывает выпадающий список combobox."""
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER)
fields_locators = self.get_input_fields_locators(container_locator)
combobox_container = fields_locators.get("Класс объекта учета")
if not combobox_container:
logger.error("Combobox 'Класс объекта учета' not found")
return
# Проверяем, не открыт ли уже выпадающий список
menu_selector = "div.v-menu__content.menuable__content__active"
is_menu_open = self.page.locator(menu_selector).count() > 0
if not is_menu_open:
# Используем OPEN_PARAMETERS_LIST_BUTTON из SelectionBarLocators
open_button = combobox_container.locator(SelectionBarLocators.OPEN_PARAMETERS_LIST_BUTTON)
open_button.click(force=True, timeout=5000)
else:
logger.debug("Combobox menu is already open")
def select_object_class(self, class_name: str) -> None:
"""Выбирает класс объекта из выпадающего списка."""
logger.debug(f"Selecting object class: '{class_name}'...")
# Открываем combobox
self.open_object_class_combobox()
# Выбирает значение из списка
self.selection_bar.select_value(class_name)
# Даем время на применение выбора
self.wait_for_timeout(3000)
logger.debug(f"Object class '{class_name}' successfully selected")
# Проверки:
def check_field_error_highlighted(self, field_name: str) -> None:
"""
Проверяет, что поле подсвечено цветом ошибки (валидация не пройдена).
Args:
field_name: Название поля для проверки
"""
logger.debug(f"Checking field '{field_name}' for error highlighting...")
# Получаем контейнеры всех полей
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER)
fields_locators = self.get_input_fields_locators(container_locator)
# Получаем контейнер конкретного поля
field_container = fields_locators.get(field_name)
if not field_container:
raise ValueError(f"Field '{field_name}' not found in form")
# Ищем элементы с классами ошибки внутри контейнера поля
error_elements = field_container.locator(SelectionBarLocators.ERROR_CSS_SELECTORS)
# Проверяем, что есть хотя бы один элемент с классом ошибки
has_error = error_elements.count() > 0
assert has_error, (
f"Field '{field_name}' has no elements with error classes. "
f"Expected to find elements matching: {SelectionBarLocators.ERROR_CSS_SELECTORS}"
)
logger.debug(f"Field '{field_name}' is correctly highlighted with error color")
def check_field_error_not_highlighted(self, field_name: str) -> None:
"""
Проверяет, что поле НЕ подсвечено цветом ошибки (валидация успешна).
Args:
field_name: Название поля для проверки
"""
logger.debug(f"Checking field '{field_name}' for absence of error highlighting...")
# Получаем контейнеры всех полей
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER)
fields_locators = self.get_input_fields_locators(container_locator)
# Получаем контейнер конкретного поля
field_container = fields_locators.get(field_name)
if not field_container:
raise ValueError(f"Field '{field_name}' not found in form")
# Ищем элементы с классами ошибки внутри контейнера поля
error_elements = field_container.locator(SelectionBarLocators.ERROR_CSS_SELECTORS)
# Проверяем, что нет элементов с классами ошибки
has_error = error_elements.count() > 0
assert not has_error, (
f"Field '{field_name}' has {error_elements.count()} elements with error classes. "
f"Expected no elements matching: {SelectionBarLocators.ERROR_CSS_SELECTORS}"
)
logger.debug(f"Field '{field_name}' correctly has no error highlighting")
def check_object_class_selected(self, expected_class: str) -> None:
"""
Проверяет что выбран указанный класс объекта.
Args:
expected_class: Ожидаемый выбранный класс объекта
"""
logger.debug(f"Checking selected object class: '{expected_class}'...")
self.wait_for_timeout(1000)
actual_class = self.get_selected_object_class()
is_match = (expected_class.lower() in actual_class.lower() or
actual_class.lower() in expected_class.lower())
assert is_match, (
f"Selected class does not match expected. "
f"Expected: '{expected_class}', Got: '{actual_class}'"
)
logger.debug(
f"Object class '{expected_class}' successfully selected "
f"(actual: '{actual_class}')"
)
def check_toolbar_title(self, expected_title: str) -> None:
"""
Проверяет заголовок тулбара.
Args:
expected_title: Ожидаемый заголовок тулбара
"""
logger.debug(f"Checking toolbar title: '{expected_title}'...")
# Используем метод тулбара с фильтрацией по тексту
actual_text = self.toolbar.get_toolbar_title_text(
filter_text="Создать дочерний элемент в"
)
assert expected_title in actual_text, (
f"Title does not match. Expected: '{expected_title}', "
f"Got: '{actual_text}'"
)
logger.debug(f"Toolbar title is correct: '{actual_text}'")
def should_be_toolbar_buttons(self) -> None:
"""
Проверяет наличие и функциональность кнопок тулбара.
"""
self.wait_for_timeout(2000)
self.toolbar.check_button_visibility("add")
self.toolbar.check_button_tooltip("add", "Добавить")
self.toolbar.check_button_visibility("cancel")
self.toolbar.check_button_tooltip("cancel", "Отменить")
self.toolbar.click_button("cancel")
self.wait_for_timeout(2000)