e-nms_qa_automation/components_derived/accounting_objects/rack_maker.py

269 lines
9.5 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.

"""Модуль создания объекта 'Стойка'."""
from dataclasses import dataclass
from playwright.sync_api import Page, Locator
from tools.logger import get_logger
from locators.rack_locators import RackLocators
from components.base_component import BaseComponent
logger = get_logger("RACK_MAKER")
logger.setLevel("INFO")
@dataclass
class RackData:
"""Класс для хранения данных стойки."""
name: str
height: str = "42"
depth: str = "1000"
serial: str = ""
inventory: str = ""
comment: str = ""
cable_entry: str = ""
state: str = ""
owner: str = ""
service_org: str = ""
project: str = ""
class RackObjectMaker(BaseComponent):
"""Компонент для создания и настройки стойки."""
def __init__(self, page: Page) -> None:
"""
Инициализирует компонент создания стойки.
Args:
page: Экземпляр страницы Playwright
"""
super().__init__(page)
# Действия:
def fill_rack_data(self, rack_data: RackData) -> None:
"""
Заполняет данные для создания стойки.
Args:
rack_data: Данные стойки
"""
logger.debug(f"Filling rack data: {rack_data.name}")
self._fill_text_fields(rack_data)
self._fill_combobox_fields(rack_data)
logger.debug("Rack data filled successfully")
def _fill_text_fields(self, rack_data: RackData) -> None:
"""Заполняет текстовые поля."""
def clear_and_fill(locator, value: str, field_name: str):
"""Очищает поле и заполняет его значением."""
field = self.page.locator(locator).first
# Очищаем поле
field.click()
field.press("Control+A")
field.press("Backspace")
# Заполняем значение
field.fill(value)
logger.debug(f"Filled '{field_name}': {value}")
# Обязательные поля.
if rack_data.name:
clear_and_fill(RackLocators.RACK_NAME_FIELD, rack_data.name, "Name")
# Опциональные поля.
if rack_data.serial:
clear_and_fill(RackLocators.RACK_SERIAL_FIELD, rack_data.serial, "Serial number")
if rack_data.inventory:
clear_and_fill(RackLocators.RACK_INVENTORY_FIELD, rack_data.inventory, "Inventory number")
if rack_data.comment:
clear_and_fill(RackLocators.RACK_COMMENT_FIELD, rack_data.comment, "Comment")
def _fill_combobox_fields(self, rack_data: RackData) -> None:
"""Заполняет combobox поля."""
# Обязательные поля.
if rack_data.height:
self._fill_combobox_field("Высота в юнитах", rack_data.height)
logger.debug(f"Selected height: {rack_data.height} units")
if rack_data.depth:
self._fill_combobox_field("Глубина (мм)", rack_data.depth)
logger.debug(f"Selected depth: {rack_data.depth} mm")
# Опциональные поля.
if rack_data.cable_entry:
self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry)
logger.debug(f"Selected cable entry: {rack_data.cable_entry}")
if rack_data.state:
self._fill_combobox_field("Состояние", rack_data.state)
logger.debug(f"Selected state: {rack_data.state}")
if rack_data.owner:
self._fill_combobox_field("Владелец", rack_data.owner)
logger.debug(f"Selected owner: {rack_data.owner}")
if rack_data.service_org:
self._fill_combobox_field("Обслуживающая организация", rack_data.service_org)
logger.debug(f"Selected service organization: {rack_data.service_org}")
if rack_data.project:
self._fill_combobox_field("Проект/Титул", rack_data.project)
logger.debug(f"Selected project/title: {rack_data.project}")
def _fill_combobox_field(self, field_name: str, value: str) -> None:
"""
Заполняет combobox поле.
Args:
field_name: Название поля
value: Значение для установки
"""
logger.debug(f"Filling field '{field_name}' with value '{value}'...")
# Используем универсальный локатор для combobox по имени поля
combobox_locator = RackLocators.COMBOBOX_BY_FIELD_NAME.format(field_name)
field_container = self.page.locator(combobox_locator).first
# Прокручиваем до поля
field_container.scroll_into_view_if_needed()
self.wait_for_timeout(500)
# Проверяем видимость поля
self.check_visibility(field_container, f"Field '{field_name}' not found")
# Кликаем и вводим значение
field_container.click(force=True)
self.wait_for_timeout(1000)
# Вводим значение из выпадающего списка
dropdown_item_locator = RackLocators.DROPDOWN_ITEM_BY_TEXT.format(value)
element = self.page.locator(dropdown_item_locator).first
# Скроллим к элементу если нужно
self._scroll_until_element(
self.page.locator(RackLocators.DROPDOWN_LIST).first,
value
)
self.wait_for_timeout(500)
element.click()
logger.debug(f"Field '{field_name}' filled successfully")
def _scroll_until_element(self, locator: Locator, name: str) -> None:
"""
Скроллит список до тех пор, пока не перестанут подгружаться новые элементы.
Args:
locator: Локатор элементов или строка с CSS/XPath.
"""
loc = self.get_locator(locator)
items_count = 0
attempts = 0
max_attempts = 3
last_item_name = ""
while attempts < max_attempts:
self.page.wait_for_timeout(300)
item_texts = loc.all_inner_texts()
item_names = item_texts[0].splitlines()
current_count = len(item_names)
if current_count == items_count:
attempts += 1
else:
items_count = current_count
attempts = 0
if name in item_names:
last_item_name = name
else:
last_item_name = item_names[current_count-1]
element = loc.get_by_role("listitem").filter(
has_text=last_item_name
)
element.scroll_into_view_if_needed()
self.wait_for_timeout(300)
def _get_field_locator(self, field_name: str) -> str:
"""
Возвращает локатор поля по его названию.
Args:
field_name: Название поля
Returns:
str: Локатор поля
"""
field_map = {
"Имя": RackLocators.RACK_NAME_FIELD,
"Высота в юнитах": RackLocators.RACK_HEIGHT_FIELD,
"Глубина (мм)": RackLocators.RACK_DEPTH_FIELD
}
if field_name not in field_map:
raise ValueError(f"Field '{field_name}' is not supported")
return field_map[field_name]
# Проверки:
def check_rack_fields_presence(self) -> None:
"""
Проверяет наличие полей специфичных для стойки.
Raises:
AssertionError: Если какое-либо поле не найдено
"""
logger.debug("Checking rack fields presence...")
# Основные обязательные поля
required_fields = [
(RackLocators.RACK_NAME_FIELD, "Name"),
(RackLocators.RACK_HEIGHT_FIELD, "Height in units"),
(RackLocators.RACK_DEPTH_FIELD, "Depth (mm)")
]
# Дополнительные поля
optional_fields = [
(RackLocators.RACK_SERIAL_FIELD, "Serial number"),
(RackLocators.RACK_INVENTORY_FIELD, "Inventory number"),
(RackLocators.RACK_COMMENT_FIELD, "Comment"),
(RackLocators.RACK_CABLE_ENTRY_FIELD, "Cable entry"),
(RackLocators.RACK_STATE_FIELD, "State"),
(RackLocators.RACK_OWNER_FIELD, "Owner"),
(RackLocators.RACK_SERVICE_ORG_FIELD, "Service organization"),
(RackLocators.RACK_PROJECT_FIELD, "Project/Title")
]
# Проверяем обязательные поля
for field_locator, field_name in required_fields:
field = self.page.locator(field_locator).first
self.check_visibility(field, f"Required field '{field_name}' not found")
logger.debug(f"Required field '{field_name}' found")
# Проверяем дополнительные поля
for field_locator, field_name in optional_fields:
field = self.page.locator(field_locator).first
if field.count() > 0 and field.is_visible():
logger.debug(f"Optional field '{field_name}' found")
else:
logger.debug(f"Optional field '{field_name}' not found or not visible")
logger.debug("All main rack fields are present")