Рефакторинг тестов создания стойки с использованием dataclass

- Добавлен класс RackData для типобезопасного хранения данных стойки
- Обновлен RackObjectMaker для работы с dataclass
- Обновлены тесты для использования нового интерфейса
- Решены проблемы pylint с импортами и количеством аргументов
- Сохранена обратная совместимость со старыми тестами
radislav/tests_rack
Radislav 2025-12-05 08:05:43 +03:00
parent 69606d7b05
commit 84393b3a40
2 changed files with 112 additions and 81 deletions

View File

@ -1,5 +1,6 @@
"""Модуль создания объекта 'Стойка'.""" """Модуль создания объекта 'Стойка'."""
from dataclasses import dataclass
from playwright.sync_api import Page from playwright.sync_api import Page
from tools.logger import get_logger from tools.logger import get_logger
from locators.rack_locators import RackLocators from locators.rack_locators import RackLocators
@ -8,6 +9,22 @@ from components.base_component import BaseComponent
logger = get_logger("RACK_MAKER") logger = get_logger("RACK_MAKER")
@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): class RackObjectMaker(BaseComponent):
"""Компонент для создания и настройки стойки.""" """Компонент для создания и настройки стойки."""
@ -22,81 +39,82 @@ class RackObjectMaker(BaseComponent):
# Действия: # Действия:
def fill_rack_data(self, name: str, height: str = "42", depth: str = "1000", def fill_rack_data(self, rack_data: RackData) -> None:
serial: str = "", inventory: str = "", comment: str = "",
cable_entry: str = "", state: str = "", owner: str = "",
service_org: str = "", project: str = "") -> None:
""" """
Заполняет данные для создания стойки. Заполняет данные для создания стойки.
Args: Args:
name: Наименование стойки rack_data: Данные стойки
height: Высота в юнитах (по умолчанию 42)
depth: Глубина в мм (по умолчанию 1000)
serial: Серийный номер
inventory: Инвентарный номер
comment: Комментарий
cable_entry: Ввод кабеля
state: Состояние
owner: Владелец
service_org: Обслуживающая организация
project: Проект/Титул
""" """
logger.info(f"Filling rack data: {name}") logger.info(f"Filling rack data: {rack_data.name}")
# Заполняем обязательные поля с использованием first() self._fill_required_fields(rack_data)
if name: self._fill_optional_fields(rack_data)
name_field = self.page.locator(RackLocators.RACK_NAME_FIELD).first self._fill_combobox_fields(rack_data)
name_field.fill(name)
logger.info(f"Filled 'Name' field: {name}")
if height:
self._fill_combobox_field("Height in units", height, RackLocators.RACK_HEIGHT_FIELD)
logger.info(f"Selected height: {height} units")
if depth:
self._fill_combobox_field("Depth (mm)", depth, RackLocators.RACK_DEPTH_FIELD)
logger.info(f"Selected depth: {depth} mm")
# Заполняем опциональные поля с использованием first()
if serial:
serial_field = self.page.locator(RackLocators.RACK_SERIAL_FIELD).first
serial_field.fill(serial)
logger.info(f"Filled serial number: {serial}")
if inventory:
inventory_field = self.page.locator(RackLocators.RACK_INVENTORY_FIELD).first
inventory_field.fill(inventory)
logger.info(f"Filled inventory number: {inventory}")
if comment:
comment_field = self.page.locator(RackLocators.RACK_COMMENT_FIELD).first
comment_field.fill(comment)
logger.info(f"Added comment: {comment}")
# Заполняем дополнительные combobox поля
if cable_entry:
self._fill_combobox_field("Cable entry", cable_entry, RackLocators.RACK_CABLE_ENTRY_FIELD)
logger.info(f"Selected cable entry: {cable_entry}")
if state:
self._fill_combobox_field("State", state, RackLocators.RACK_STATE_FIELD)
logger.info(f"Selected state: {state}")
if owner:
self._fill_combobox_field("Owner", owner, RackLocators.RACK_OWNER_FIELD)
logger.info(f"Selected owner: {owner}")
if service_org:
self._fill_combobox_field("Service organization", service_org, RackLocators.RACK_SERVICE_ORG_FIELD)
logger.info(f"Selected service organization: {service_org}")
if project:
self._fill_combobox_field("Project/Title", project, RackLocators.RACK_PROJECT_FIELD)
logger.info(f"Selected project/title: {project}")
logger.info("Rack data filled successfully") logger.info("Rack data filled successfully")
def _fill_required_fields(self, rack_data: RackData) -> None:
"""Заполняет обязательные поля."""
if rack_data.name:
name_field = self.page.locator(RackLocators.RACK_NAME_FIELD).first
name_field.fill(rack_data.name)
logger.info(f"Filled 'Name' field: {rack_data.name}")
def _fill_optional_fields(self, rack_data: RackData) -> None:
"""Заполняет опциональные поля."""
if rack_data.serial:
serial_field = self.page.locator(RackLocators.RACK_SERIAL_FIELD).first
serial_field.fill(rack_data.serial)
logger.info(f"Filled serial number: {rack_data.serial}")
if rack_data.inventory:
inventory_field = self.page.locator(RackLocators.RACK_INVENTORY_FIELD).first
inventory_field.fill(rack_data.inventory)
logger.info(f"Filled inventory number: {rack_data.inventory}")
if rack_data.comment:
comment_field = self.page.locator(RackLocators.RACK_COMMENT_FIELD).first
comment_field.fill(rack_data.comment)
logger.info(f"Added comment: {rack_data.comment}")
def _fill_combobox_fields(self, rack_data: RackData) -> None:
"""Заполняет combobox поля."""
if rack_data.height:
self._fill_combobox_field("Height in units", rack_data.height,
RackLocators.RACK_HEIGHT_FIELD)
logger.info(f"Selected height: {rack_data.height} units")
if rack_data.depth:
self._fill_combobox_field("Depth (mm)", rack_data.depth,
RackLocators.RACK_DEPTH_FIELD)
logger.info(f"Selected depth: {rack_data.depth} mm")
if rack_data.cable_entry:
self._fill_combobox_field("Cable entry", rack_data.cable_entry,
RackLocators.RACK_CABLE_ENTRY_FIELD)
logger.info(f"Selected cable entry: {rack_data.cable_entry}")
if rack_data.state:
self._fill_combobox_field("State", rack_data.state,
RackLocators.RACK_STATE_FIELD)
logger.info(f"Selected state: {rack_data.state}")
if rack_data.owner:
self._fill_combobox_field("Owner", rack_data.owner,
RackLocators.RACK_OWNER_FIELD)
logger.info(f"Selected owner: {rack_data.owner}")
if rack_data.service_org:
self._fill_combobox_field("Service organization", rack_data.service_org,
RackLocators.RACK_SERVICE_ORG_FIELD)
logger.info(f"Selected service organization: {rack_data.service_org}")
if rack_data.project:
self._fill_combobox_field("Project/Title", rack_data.project,
RackLocators.RACK_PROJECT_FIELD)
logger.info(f"Selected project/title: {rack_data.project}")
def _fill_combobox_field(self, field_name: str, value: str, field_locator: str) -> None: def _fill_combobox_field(self, field_name: str, value: str, field_locator: str) -> None:
""" """
Заполняет combobox поле. Заполняет combobox поле.
@ -189,7 +207,7 @@ class RackObjectMaker(BaseComponent):
(RackLocators.RACK_PROJECT_FIELD, "Project/Title") (RackLocators.RACK_PROJECT_FIELD, "Project/Title")
] ]
# Проверяем обязательные поля с использованием first() для избежания strict mode violation # Проверяем обязательные поля
for field_locator, field_name in required_fields: for field_locator, field_name in required_fields:
field = self.page.locator(field_locator).first field = self.page.locator(field_locator).first
self.check_visibility(field, f"Required field '{field_name}' not found") self.check_visibility(field, f"Required field '{field_name}' not found")

View File

@ -4,7 +4,7 @@ import pytest
from playwright.sync_api import Page from playwright.sync_api import Page
from tools.logger import get_logger from tools.logger import get_logger
from locators.navigation_panel_locators import NavigationPanelLocators from locators.navigation_panel_locators import NavigationPanelLocators
from components_derived.accounting_objects.rack_maker import RackObjectMaker from components_derived.accounting_objects.rack_maker import RackObjectMaker, RackData
from components_derived.frames.create_child_element_frame import CreateChildElementFrame from components_derived.frames.create_child_element_frame import CreateChildElementFrame
from pages.location_page import LocationPage from pages.location_page import LocationPage
from pages.login_page import LoginPage from pages.login_page import LoginPage
@ -103,11 +103,9 @@ class TestCreateRackElement:
rack_maker.check_rack_fields_presence() rack_maker.check_rack_fields_presence()
logger.info("Rack-specific fields are displayed correctly") logger.info("Rack-specific fields are displayed correctly")
# Заполняем данные стойки # Создаем объект данных стойки
rack_name = "Test-Rack-01" rack_data = RackData(
name="Test-Rack-01",
rack_maker.fill_rack_data(
name=rack_name,
height="42", height="42",
depth="1000", depth="1000",
serial="TEST123456", serial="TEST123456",
@ -117,6 +115,9 @@ class TestCreateRackElement:
state="В эксплуатации" state="В эксплуатации"
) )
# Заполняем данные стойки
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку "Добавить" # Нажимаем кнопку "Добавить"
create_child_frame.click_add_button() create_child_frame.click_add_button()
create_child_frame.wait_for_timeout(2000) create_child_frame.wait_for_timeout(2000)
@ -164,13 +165,16 @@ class TestCreateRackElement:
# Открывается набор плашек для задания параметров стойки # Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser) rack_maker = RackObjectMaker(browser)
# Пытаемся создать вторую стойку с тем же именем # Создаем объект данных для второй стойки
rack_maker.fill_rack_data( rack_data = RackData(
name=rack_name, name=rack_name,
height="42", height="42",
depth="1000" depth="1000"
) )
# Пытаемся создать вторую стойку с тем же именем
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку создания # Нажимаем кнопку создания
create_child_frame.click_add_button() create_child_frame.click_add_button()
create_child_frame.wait_for_timeout(2000) create_child_frame.wait_for_timeout(2000)
@ -207,13 +211,16 @@ class TestCreateRackElement:
create_child_frame.clear_combobox_field("Глубина (мм)") create_child_frame.clear_combobox_field("Глубина (мм)")
create_child_frame.clear_combobox_field("Высота в юнитах") create_child_frame.clear_combobox_field("Высота в юнитах")
# Заполняем данные # Создаем объект данных стойки
rack_maker.fill_rack_data( rack_data = RackData(
name=name_value, name=name_value,
height=height_value, height=height_value,
depth=depth_value depth=depth_value
) )
# Заполняем данные
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку создания # Нажимаем кнопку создания
create_child_frame.click_add_button() create_child_frame.click_add_button()
create_child_frame.wait_for_timeout(3000) create_child_frame.wait_for_timeout(3000)
@ -329,13 +336,16 @@ class TestCreateRackElement:
# Генерируем уникальное имя для финального теста # Генерируем уникальное имя для финального теста
final_rack_name = "Test-Rack-Required-Final" final_rack_name = "Test-Rack-Required-Final"
# Заполняем все обязательные поля # Создаем объект данных стойки
rack_maker.fill_rack_data( rack_data = RackData(
name=final_rack_name, name=final_rack_name,
height="42", height="42",
depth="1000" depth="1000"
) )
# Заполняем все обязательные поля
rack_maker.fill_rack_data(rack_data)
# Проверяем, что ни одно поле не подсвечено цветом ошибки # Проверяем, что ни одно поле не подсвечено цветом ошибки
create_child_frame.check_field_not_highlighted_error("Имя") create_child_frame.check_field_not_highlighted_error("Имя")
create_child_frame.check_field_not_highlighted_error("Высота в юнитах") create_child_frame.check_field_not_highlighted_error("Высота в юнитах")
@ -406,13 +416,16 @@ class TestCreateRackElement:
# Открывается набор плашек для задания параметров стойки # Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser) rack_maker = RackObjectMaker(browser)
# Заполняем данные стойки # Создаем объект данных стойки
rack_maker.fill_rack_data( rack_data = RackData(
name=rack_name, name=rack_name,
height="42", height="42",
depth="1000" depth="1000"
) )
# Заполняем данные стойки
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку создания # Нажимаем кнопку создания
create_child_frame.click_add_button() create_child_frame.click_add_button()
create_child_frame.wait_for_timeout(2000) create_child_frame.wait_for_timeout(2000)