Исправление тестов создания стойки и локаторов
parent
07906b9f76
commit
a3dc0a037c
|
|
@ -1,13 +1,14 @@
|
||||||
"""Модуль создания объекта 'Стойка'."""
|
"""Модуль создания объекта 'Стойка'."""
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from playwright.sync_api import Page
|
from playwright.sync_api import Page, Locator
|
||||||
from tools.logger import get_logger
|
from tools.logger import get_logger
|
||||||
from locators.rack_locators import RackLocators
|
from locators.rack_locators import RackLocators
|
||||||
from components.base_component import BaseComponent
|
from components.base_component import BaseComponent
|
||||||
|
|
||||||
logger = get_logger("RACK_MAKER")
|
logger = get_logger("RACK_MAKER")
|
||||||
|
|
||||||
|
logger.setLevel("INFO")
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RackData:
|
class RackData:
|
||||||
|
|
@ -49,12 +50,12 @@ class RackObjectMaker(BaseComponent):
|
||||||
rack_data: Данные стойки
|
rack_data: Данные стойки
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info(f"Filling rack data: {rack_data.name}")
|
logger.debug(f"Filling rack data: {rack_data.name}")
|
||||||
|
|
||||||
self._fill_text_fields(rack_data)
|
self._fill_text_fields(rack_data)
|
||||||
self._fill_combobox_fields(rack_data)
|
self._fill_combobox_fields(rack_data)
|
||||||
|
|
||||||
logger.info("Rack data filled successfully")
|
logger.debug("Rack data filled successfully")
|
||||||
|
|
||||||
def _fill_text_fields(self, rack_data: RackData) -> None:
|
def _fill_text_fields(self, rack_data: RackData) -> None:
|
||||||
"""Заполняет текстовые поля."""
|
"""Заполняет текстовые поля."""
|
||||||
|
|
@ -69,7 +70,7 @@ class RackObjectMaker(BaseComponent):
|
||||||
field.press("Backspace")
|
field.press("Backspace")
|
||||||
# Заполняем значение
|
# Заполняем значение
|
||||||
field.fill(value)
|
field.fill(value)
|
||||||
logger.info(f"Filled '{field_name}': {value}")
|
logger.debug(f"Filled '{field_name}': {value}")
|
||||||
|
|
||||||
# Обязательные поля.
|
# Обязательные поля.
|
||||||
if rack_data.name:
|
if rack_data.name:
|
||||||
|
|
@ -90,55 +91,48 @@ class RackObjectMaker(BaseComponent):
|
||||||
|
|
||||||
# Обязательные поля.
|
# Обязательные поля.
|
||||||
if rack_data.height:
|
if rack_data.height:
|
||||||
self._fill_combobox_field("Height in units", rack_data.height,
|
self._fill_combobox_field("Высота в юнитах", rack_data.height)
|
||||||
RackLocators.RACK_HEIGHT_FIELD)
|
logger.debug(f"Selected height: {rack_data.height} units")
|
||||||
logger.info(f"Selected height: {rack_data.height} units")
|
|
||||||
|
|
||||||
if rack_data.depth:
|
if rack_data.depth:
|
||||||
self._fill_combobox_field("Depth (mm)", rack_data.depth,
|
self._fill_combobox_field("Глубина (мм)", rack_data.depth)
|
||||||
RackLocators.RACK_DEPTH_FIELD)
|
logger.debug(f"Selected depth: {rack_data.depth} mm")
|
||||||
logger.info(f"Selected depth: {rack_data.depth} mm")
|
|
||||||
|
|
||||||
# Опциональные поля.
|
# Опциональные поля.
|
||||||
if rack_data.cable_entry:
|
if rack_data.cable_entry:
|
||||||
self._fill_combobox_field("Cable entry", rack_data.cable_entry,
|
self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry)
|
||||||
RackLocators.RACK_CABLE_ENTRY_FIELD)
|
logger.debug(f"Selected cable entry: {rack_data.cable_entry}")
|
||||||
logger.info(f"Selected cable entry: {rack_data.cable_entry}")
|
|
||||||
|
|
||||||
if rack_data.state:
|
if rack_data.state:
|
||||||
self._fill_combobox_field("State", rack_data.state,
|
self._fill_combobox_field("Состояние", rack_data.state)
|
||||||
RackLocators.RACK_STATE_FIELD)
|
logger.debug(f"Selected state: {rack_data.state}")
|
||||||
logger.info(f"Selected state: {rack_data.state}")
|
|
||||||
|
|
||||||
if rack_data.owner:
|
if rack_data.owner:
|
||||||
self._fill_combobox_field("Owner", rack_data.owner,
|
self._fill_combobox_field("Владелец", rack_data.owner)
|
||||||
RackLocators.RACK_OWNER_FIELD)
|
logger.debug(f"Selected owner: {rack_data.owner}")
|
||||||
logger.info(f"Selected owner: {rack_data.owner}")
|
|
||||||
|
|
||||||
if rack_data.service_org:
|
if rack_data.service_org:
|
||||||
self._fill_combobox_field("Service organization", rack_data.service_org,
|
self._fill_combobox_field("Обслуживающая организация", rack_data.service_org)
|
||||||
RackLocators.RACK_SERVICE_ORG_FIELD)
|
logger.debug(f"Selected service organization: {rack_data.service_org}")
|
||||||
logger.info(f"Selected service organization: {rack_data.service_org}")
|
|
||||||
|
|
||||||
if rack_data.project:
|
if rack_data.project:
|
||||||
self._fill_combobox_field("Project/Title", rack_data.project,
|
self._fill_combobox_field("Проект/Титул", rack_data.project)
|
||||||
RackLocators.RACK_PROJECT_FIELD)
|
logger.debug(f"Selected project/title: {rack_data.project}")
|
||||||
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) -> None:
|
||||||
"""
|
"""
|
||||||
Заполняет combobox поле.
|
Заполняет combobox поле.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
field_name: Название поля
|
field_name: Название поля
|
||||||
value: Значение для установки
|
value: Значение для установки
|
||||||
field_locator: Локатор поля
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info(f"Filling field '{field_name}' with value '{value}'...")
|
logger.debug(f"Filling field '{field_name}' with value '{value}'...")
|
||||||
|
|
||||||
# Используем first() для избежания strict mode violation
|
# Используем универсальный локатор для combobox по имени поля
|
||||||
field_container = self.page.locator(field_locator).first
|
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()
|
field_container.scroll_into_view_if_needed()
|
||||||
|
|
@ -151,12 +145,58 @@ class RackObjectMaker(BaseComponent):
|
||||||
field_container.click(force=True)
|
field_container.click(force=True)
|
||||||
self.wait_for_timeout(1000)
|
self.wait_for_timeout(1000)
|
||||||
|
|
||||||
# Вводим значение
|
# Вводим значение из выпадающего списка
|
||||||
self.page.keyboard.type(value)
|
dropdown_item_locator = RackLocators.DROPDOWN_ITEM_BY_TEXT.format(value)
|
||||||
self.wait_for_timeout(500)
|
element = self.page.locator(dropdown_item_locator).first
|
||||||
self.page.keyboard.press("Enter")
|
|
||||||
|
|
||||||
logger.info(f"Field '{field_name}' filled successfully")
|
# Скроллим к элементу если нужно
|
||||||
|
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:
|
def _get_field_locator(self, field_name: str) -> str:
|
||||||
"""
|
"""
|
||||||
|
|
@ -190,7 +230,7 @@ class RackObjectMaker(BaseComponent):
|
||||||
AssertionError: Если какое-либо поле не найдено
|
AssertionError: Если какое-либо поле не найдено
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info("Checking rack fields presence...")
|
logger.debug("Checking rack fields presence...")
|
||||||
|
|
||||||
# Основные обязательные поля
|
# Основные обязательные поля
|
||||||
required_fields = [
|
required_fields = [
|
||||||
|
|
@ -215,14 +255,14 @@ class RackObjectMaker(BaseComponent):
|
||||||
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")
|
||||||
logger.info(f"Required field '{field_name}' found")
|
logger.debug(f"Required field '{field_name}' found")
|
||||||
|
|
||||||
# Проверяем дополнительные поля
|
# Проверяем дополнительные поля
|
||||||
for field_locator, field_name in optional_fields:
|
for field_locator, field_name in optional_fields:
|
||||||
field = self.page.locator(field_locator).first
|
field = self.page.locator(field_locator).first
|
||||||
if field.count() > 0 and field.is_visible():
|
if field.count() > 0 and field.is_visible():
|
||||||
logger.info(f"Optional field '{field_name}' found")
|
logger.debug(f"Optional field '{field_name}' found")
|
||||||
else:
|
else:
|
||||||
logger.info(f"Optional field '{field_name}' not found or not visible")
|
logger.debug(f"Optional field '{field_name}' not found or not visible")
|
||||||
|
|
||||||
logger.info("All main rack fields are present")
|
logger.debug("All main rack fields are present")
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ from components_derived.selection_bar_component import SelectionBarComponent
|
||||||
|
|
||||||
logger = get_logger("CREATE_CHILD_ELEMENT_FRAME")
|
logger = get_logger("CREATE_CHILD_ELEMENT_FRAME")
|
||||||
|
|
||||||
|
logger.setLevel("INFO")
|
||||||
|
|
||||||
class CreateChildElementFrame(BaseComponent):
|
class CreateChildElementFrame(BaseComponent):
|
||||||
"""Фрейм создания дочернего элемента."""
|
"""Фрейм создания дочернего элемента."""
|
||||||
|
|
@ -55,10 +56,10 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
field_name: Название поля для очистки
|
field_name: Название поля для очистки
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info(f"Clearing combobox field '{field_name}'...")
|
logger.debug(f"Clearing combobox field '{field_name}'...")
|
||||||
|
|
||||||
# Получаем локатор поля по его названию
|
# Получаем локатор поля по его названию
|
||||||
field_locator = self._get_field_locator(field_name)
|
field_locator = self.get_field_locator(field_name)
|
||||||
|
|
||||||
# Используем метод из SelectionBarComponent
|
# Используем метод из SelectionBarComponent
|
||||||
self.selection_bar.clear_combobox_field(field_name, field_locator)
|
self.selection_bar.clear_combobox_field(field_name, field_locator)
|
||||||
|
|
@ -66,15 +67,28 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
def click_add_button(self) -> None:
|
def click_add_button(self) -> None:
|
||||||
"""Кликает на кнопку 'Добавить'."""
|
"""Кликает на кнопку 'Добавить'."""
|
||||||
|
|
||||||
logger.info("Clicking on 'Add' button...")
|
logger.debug("Clicking on 'Add' button...")
|
||||||
self.toolbar.click_button("add")
|
self.toolbar.click_button("add")
|
||||||
|
|
||||||
def click_cancel_button(self) -> None:
|
def click_cancel_button(self) -> None:
|
||||||
"""Кликает на кнопку 'Отменить'."""
|
"""Кликает на кнопку 'Отменить'."""
|
||||||
|
|
||||||
logger.info("Clicking on 'Cancel' button...")
|
logger.debug("Clicking on 'Cancel' button...")
|
||||||
self.toolbar.click_button("cancel")
|
self.toolbar.click_button("cancel")
|
||||||
|
|
||||||
|
def get_field_locator(self, field_name: str) -> str:
|
||||||
|
"""
|
||||||
|
Возвращает локатор поля по его названию.
|
||||||
|
Публичный метод для использования в тестах.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
field_name: Название поля
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Локатор поля
|
||||||
|
"""
|
||||||
|
return self._get_field_locator(field_name)
|
||||||
|
|
||||||
def get_object_class_options(self) -> list[str]:
|
def get_object_class_options(self) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Получает список доступных опций из combobox.
|
Получает список доступных опций из combobox.
|
||||||
|
|
@ -83,11 +97,11 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
list[str]: Список доступных классов объектов
|
list[str]: Список доступных классов объектов
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info("Getting combobox 'Accounting object class' options...")
|
logger.debug("Getting combobox 'Accounting object class' options...")
|
||||||
|
|
||||||
available_options = self.selection_bar.get_available_options()
|
available_options = self.selection_bar.get_available_options()
|
||||||
|
|
||||||
logger.info(f"Available object class options: {available_options}")
|
logger.debug(f"Available object class options: {available_options}")
|
||||||
return available_options
|
return available_options
|
||||||
|
|
||||||
def get_selected_object_class(self) -> str:
|
def get_selected_object_class(self) -> str:
|
||||||
|
|
@ -103,7 +117,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
def open_object_class_combobox(self) -> None:
|
def open_object_class_combobox(self) -> None:
|
||||||
"""Открывает выпадающий список combobox 'Класс объекта учета'."""
|
"""Открывает выпадающий список combobox 'Класс объекта учета'."""
|
||||||
|
|
||||||
logger.info("Opening combobox 'Accounting object class'...")
|
logger.debug("Opening combobox 'Accounting object class'...")
|
||||||
|
|
||||||
# Ждем стабильности combobox
|
# Ждем стабильности combobox
|
||||||
expect(self.selection_bar.selection_bar_locator).to_be_visible()
|
expect(self.selection_bar.selection_bar_locator).to_be_visible()
|
||||||
|
|
@ -113,11 +127,11 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
"class"
|
"class"
|
||||||
)
|
)
|
||||||
if is_menu_active and "v-select--is-menu-active" in is_menu_active:
|
if is_menu_active and "v-select--is-menu-active" in is_menu_active:
|
||||||
logger.info("Dropdown list is already open")
|
logger.debug("Dropdown list is already open")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Используем force click для обхода перекрывающих элементов
|
# Используем force click для обхода перекрывающих элементов
|
||||||
logger.info("Using force click for combobox")
|
logger.debug("Using force click for combobox")
|
||||||
self.selection_bar.selection_bar_locator.click(force=True)
|
self.selection_bar.selection_bar_locator.click(force=True)
|
||||||
|
|
||||||
# Ждем появления выпадающего списка
|
# Ждем появления выпадающего списка
|
||||||
|
|
@ -126,7 +140,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
def select_object_class(self, class_name: str) -> None:
|
def select_object_class(self, class_name: str) -> None:
|
||||||
"""Выбирает класс объекта из выпадающего списка."""
|
"""Выбирает класс объекта из выпадающего списка."""
|
||||||
|
|
||||||
logger.info(f"Selecting object class: '{class_name}'...")
|
logger.debug(f"Selecting object class: '{class_name}'...")
|
||||||
|
|
||||||
# Открываем combobox
|
# Открываем combobox
|
||||||
self.open_object_class_combobox()
|
self.open_object_class_combobox()
|
||||||
|
|
@ -139,12 +153,12 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
|
|
||||||
# Логируем текущее состояние без строгой проверки
|
# Логируем текущее состояние без строгой проверки
|
||||||
selected_value = self.get_selected_object_class()
|
selected_value = self.get_selected_object_class()
|
||||||
logger.info(f"Current combobox value: '{selected_value}'")
|
logger.debug(f"Current combobox value: '{selected_value}'")
|
||||||
|
|
||||||
# Временно пропускаем строгую проверку
|
# Временно пропускаем строгую проверку
|
||||||
logger.info(f"Assuming class '{class_name}' is selected")
|
logger.debug(f"Assuming class '{class_name}' is selected")
|
||||||
|
|
||||||
logger.info(f"Object class '{class_name}' successfully selected")
|
logger.debug(f"Object class '{class_name}' successfully selected")
|
||||||
|
|
||||||
# Проверки:
|
# Проверки:
|
||||||
|
|
||||||
|
|
@ -156,7 +170,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
field_name: Название поля для проверки
|
field_name: Название поля для проверки
|
||||||
"""
|
"""
|
||||||
|
|
||||||
field_locator = self._get_field_locator(field_name)
|
field_locator = self.get_field_locator(field_name)
|
||||||
self.selection_bar.check_field_error_highlighted(field_name, field_locator)
|
self.selection_bar.check_field_error_highlighted(field_name, field_locator)
|
||||||
|
|
||||||
def check_field_error_not_highlighted(self, field_name: str) -> None:
|
def check_field_error_not_highlighted(self, field_name: str) -> None:
|
||||||
|
|
@ -167,7 +181,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
field_name: Название поля для проверки
|
field_name: Название поля для проверки
|
||||||
"""
|
"""
|
||||||
|
|
||||||
field_locator = self._get_field_locator(field_name)
|
field_locator = self.get_field_locator(field_name)
|
||||||
self.selection_bar.check_field_error_not_highlighted(field_name, field_locator)
|
self.selection_bar.check_field_error_not_highlighted(field_name, field_locator)
|
||||||
|
|
||||||
def check_object_class_selected(self, expected_class: str) -> None:
|
def check_object_class_selected(self, expected_class: str) -> None:
|
||||||
|
|
@ -178,7 +192,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
expected_class: Ожидаемый выбранный класс объекта
|
expected_class: Ожидаемый выбранный класс объекта
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info(f"Checking selected object class: '{expected_class}'...")
|
logger.debug(f"Checking selected object class: '{expected_class}'...")
|
||||||
|
|
||||||
self.wait_for_timeout(1000)
|
self.wait_for_timeout(1000)
|
||||||
actual_class = self.get_selected_object_class()
|
actual_class = self.get_selected_object_class()
|
||||||
|
|
@ -191,7 +205,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
f"Expected: '{expected_class}', Got: '{actual_class}'"
|
f"Expected: '{expected_class}', Got: '{actual_class}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(
|
logger.debug(
|
||||||
f"Object class '{expected_class}' successfully selected "
|
f"Object class '{expected_class}' successfully selected "
|
||||||
f"(actual: '{actual_class}')"
|
f"(actual: '{actual_class}')"
|
||||||
)
|
)
|
||||||
|
|
@ -204,7 +218,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
expected_title: Ожидаемый заголовок тулбара
|
expected_title: Ожидаемый заголовок тулбара
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info(f"Checking toolbar title: '{expected_title}'...")
|
logger.debug(f"Checking toolbar title: '{expected_title}'...")
|
||||||
|
|
||||||
# Используем метод тулбара с фильтрацией по тексту
|
# Используем метод тулбара с фильтрацией по тексту
|
||||||
actual_text = self.toolbar.get_toolbar_title_text(
|
actual_text = self.toolbar.get_toolbar_title_text(
|
||||||
|
|
@ -216,7 +230,7 @@ class CreateChildElementFrame(BaseComponent):
|
||||||
f"Got: '{actual_text}'"
|
f"Got: '{actual_text}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"Toolbar title is correct: '{actual_text}'")
|
logger.debug(f"Toolbar title is correct: '{actual_text}'")
|
||||||
|
|
||||||
def should_be_toolbar_buttons(self) -> None:
|
def should_be_toolbar_buttons(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -27,26 +27,36 @@ class RackLocators:
|
||||||
EDIT_BUTTON ="//button[@data-testid='CABINET_SHOW__btn__edit']"
|
EDIT_BUTTON ="//button[@data-testid='CABINET_SHOW__btn__edit']"
|
||||||
|
|
||||||
# Кнопка "Скрыть стойку"
|
# Кнопка "Скрыть стойку"
|
||||||
HIDE_RACK_BUTTON = "//div[@data-testid='CABINET_SHOW__div__hideCabinet' and contains(@class, 'cabinet_hide_button_trigger_show')]"
|
HIDE_RACK_BUTTON = ("//div[@data-testid='CABINET_SHOW__div__hideCabinet' and "
|
||||||
|
"contains(@class, 'cabinet_hide_button_trigger_show')]")
|
||||||
|
|
||||||
# Кнопка "Показать стойку"
|
# Кнопка "Показать стойку"
|
||||||
SHOW_RACK_BUTTON = "//div[@data-testid='CABINET_SHOW__div__hideCabinet' and contains(@class, 'cabinet_hide_button_trigger_hide')]"
|
SHOW_RACK_BUTTON = ("//div[@data-testid='CABINET_SHOW__div__hideCabinet' and "
|
||||||
|
"contains(@class, 'cabinet_hide_button_trigger_hide')]")
|
||||||
|
|
||||||
# Универсальный локатор для любой вкладки по имени
|
# Универсальный локатор для любой вкладки по имени
|
||||||
TAB_BY_NAME = "//div[starts-with(@data-testid, 'CABINET_SHOW__') and contains(@class, 'v-tabs__div')]//a[contains(@class, 'v-tabs__item') and .//*[contains(., '{}')]]"
|
TAB_BY_NAME = ("//div[starts-with(@data-testid, 'CABINET_SHOW__') and "
|
||||||
|
"contains(@class, 'v-tabs__div')]//a[contains(@class, 'v-tabs__item') and "
|
||||||
|
".//*[contains(., '{}')]]")
|
||||||
|
|
||||||
# Конкретные вкладки по тексту
|
# Конкретные вкладки по тексту
|
||||||
COMPOSITION_TAB = "//div[@data-testid='CABINET_SHOW__composition_tab']//a[contains(@class, 'v-tabs__item')]"
|
COMPOSITION_TAB = ("//div[@data-testid='CABINET_SHOW__composition_tab']"
|
||||||
GENERAL_INFO_TAB = "//div[@data-testid='CABINET_SHOW__main_tab']//a[contains(@class, 'v-tabs__item')]"
|
"//a[contains(@class, 'v-tabs__item')]")
|
||||||
MAINTENANCE_TAB = "//div[@data-testid='CABINET_SHOW__service_tab']//a[contains(@class, 'v-tabs__item')]"
|
GENERAL_INFO_TAB = ("//div[@data-testid='CABINET_SHOW__main_tab']"
|
||||||
EVENTS_TAB = "//div[@data-testid='CABINET_SHOW__events_tab']//a[contains(@class, 'v-tabs__item')]"
|
"//a[contains(@class, 'v-tabs__item')]")
|
||||||
SERVICES_TAB = "//div[@data-testid='CABINET_SHOW__services_tab']//a[contains(@class, 'v-tabs__item')]"
|
MAINTENANCE_TAB = ("//div[@data-testid='CABINET_SHOW__service_tab']"
|
||||||
|
"//a[contains(@class, 'v-tabs__item')]")
|
||||||
|
EVENTS_TAB = ("//div[@data-testid='CABINET_SHOW__events_tab']"
|
||||||
|
"//a[contains(@class, 'v-tabs__item')]")
|
||||||
|
SERVICES_TAB = ("//div[@data-testid='CABINET_SHOW__services_tab']"
|
||||||
|
"//a[contains(@class, 'v-tabs__item')]")
|
||||||
|
|
||||||
# Классы для проверки активности
|
# Классы для проверки активности
|
||||||
ACTIVE_TAB_CLASSES = ["accent--text", "v-tabs__item--active"]
|
ACTIVE_TAB_CLASSES = ["accent--text", "v-tabs__item--active"]
|
||||||
|
|
||||||
# Локатор для активной вкладки
|
# Локатор для активной вкладки
|
||||||
ACTIVE_TAB = "//div[@data-testid='CABINET_SHOW__tabs']//a[contains(@class, 'v-tabs__item--active')]"
|
ACTIVE_TAB = ("//div[@data-testid='CABINET_SHOW__tabs']"
|
||||||
|
"//a[contains(@class, 'v-tabs__item--active')]")
|
||||||
|
|
||||||
# Контейнер формы
|
# Контейнер формы
|
||||||
FORM_CONTAINER = "//div[contains(@class, 'container')]"
|
FORM_CONTAINER = "//div[contains(@class, 'container')]"
|
||||||
|
|
@ -63,18 +73,49 @@ class RackLocators:
|
||||||
PROJECT_FIELD = "//input[@aria-label='Проект/Титул']"
|
PROJECT_FIELD = "//input[@aria-label='Проект/Титул']"
|
||||||
|
|
||||||
# Локаторы полей формы создания стойки
|
# Локаторы полей формы создания стойки
|
||||||
RACK_NAME_FIELD = "//div[contains(@class, 'container')]//label[text()='Имя']/following-sibling::input"
|
RACK_NAME_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
RACK_HEIGHT_FIELD = "//div[contains(@class, 'container')]//div[contains(@class, 'v-input__slot') and .//label[text()='Высота в юнитах']]"
|
"//label[text()='Имя']/following-sibling::input")
|
||||||
RACK_DEPTH_FIELD = "//div[contains(@class, 'container')]//div[contains(@class, 'v-input__slot') and .//label[text()='Глубина (мм)']]"
|
RACK_HEIGHT_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
RACK_SERIAL_FIELD = "//div[contains(@class, 'container')]//label[text()='Серийный номер']/following-sibling::input"
|
"//div[contains(@class, 'v-input__slot') and "
|
||||||
RACK_INVENTORY_FIELD = "//div[contains(@class, 'container')]//label[text()='Инвентарный номер']/following-sibling::input"
|
".//label[text()='Высота в юнитах']]")
|
||||||
RACK_COMMENT_FIELD = "//div[contains(@class, 'container')]//label[text()='Комментарий']/following-sibling::input"
|
RACK_DEPTH_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
RACK_CABLE_ENTRY_FIELD = "//div[contains(@class, 'container')]//div[contains(@class, 'v-input__slot') and .//label[text()='Ввод кабеля']]"
|
"//div[contains(@class, 'v-input__slot') and "
|
||||||
RACK_STATE_FIELD = "//div[contains(@class, 'container')]//div[contains(@class, 'v-input__slot') and .//label[text()='Состояние']]"
|
".//label[text()='Глубина (мм)']]")
|
||||||
|
RACK_SERIAL_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
|
"//label[text()='Серийный номер']/following-sibling::input")
|
||||||
|
RACK_INVENTORY_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
|
"//label[text()='Инвентарный номер']/following-sibling::input")
|
||||||
|
RACK_COMMENT_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
|
"//label[text()='Комментарий']/following-sibling::input")
|
||||||
|
RACK_CABLE_ENTRY_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
|
"//div[contains(@class, 'v-input__slot') and "
|
||||||
|
".//label[text()='Ввод кабеля']]")
|
||||||
|
RACK_STATE_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
|
"//div[contains(@class, 'v-input__slot') and "
|
||||||
|
".//label[text()='Состояние']]")
|
||||||
|
|
||||||
RACK_OWNER_FIELD = "//div[contains(@class, 'container')]//div[contains(@class, 'v-input__slot') and .//label[text()='Владелец']]"
|
RACK_OWNER_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
RACK_SERVICE_ORG_FIELD = "//div[contains(@class, 'container')]//div[contains(@class, 'v-input__slot') and .//label[text()='Обслуживающая организация']]"
|
"//div[contains(@class, 'v-input__slot') and "
|
||||||
RACK_PROJECT_FIELD = "//div[contains(@class, 'container')]//div[contains(@class, 'v-input__slot') and .//label[text()='Проект/Титул']]"
|
".//label[text()='Владелец']]")
|
||||||
|
RACK_SERVICE_ORG_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
|
"//div[contains(@class, 'v-input__slot') and "
|
||||||
|
".//label[text()='Обслуживающая организация']]")
|
||||||
|
RACK_PROJECT_FIELD = ("//div[contains(@class, 'container')]"
|
||||||
|
"//div[contains(@class, 'v-input__slot') and "
|
||||||
|
".//label[text()='Проект/Титул']]")
|
||||||
|
|
||||||
|
# Универсальные локаторы для поиска combobox полей по имени
|
||||||
|
COMBOBOX_BY_FIELD_NAME = ('//form[contains(@class, "v-form")]'
|
||||||
|
'//div[@role="combobox"][.//label[contains(text(), "{}")]]')
|
||||||
|
COMBOBOX_BY_LABEL = 'form.v-form div[role="combobox"]:has(label:has-text("{}"))'
|
||||||
|
|
||||||
|
# Локаторы для выпадающего меню
|
||||||
|
ACTIVE_MENU = 'div.menuable__content__active'
|
||||||
|
DROPDOWN_LIST = 'div.menuable__content__active div[role="list"]'
|
||||||
|
DROPDOWN_ITEM_BY_TEXT = ('div.menuable__content__active '
|
||||||
|
'div[role="listitem"]:has(span:has-text("{}"))')
|
||||||
|
DROPDOWN_ITEM_XPATH = ('//div[contains(@class, "menuable__content__active")]'
|
||||||
|
'//div[@role="list"]//div[@role="listitem"][.//*[text()="{}"]]')
|
||||||
|
|
||||||
# Локатор для родительского контейнера поля ввода
|
# Локатор для родительского контейнера поля ввода
|
||||||
INPUT_PARENT_CONTAINER = "xpath=./ancestor::div[contains(@class, 'v-input')]"
|
INPUT_PARENT_CONTAINER = "xpath=./ancestor::div[contains(@class, 'v-input')]"
|
||||||
|
|
@ -85,7 +126,8 @@ class RackLocators:
|
||||||
# ================ ЛОКАТОРЫ ДЛЯ СТРУКТУРЫ СТОЙКИ ===================
|
# ================ ЛОКАТОРЫ ДЛЯ СТРУКТУРЫ СТОЙКИ ===================
|
||||||
|
|
||||||
# Общий контейнер стойки (включает кнопки переключения сторон и MAIN_CONTAINER)
|
# Общий контейнер стойки (включает кнопки переключения сторон и MAIN_CONTAINER)
|
||||||
RACK_CONTAINER = "//div[contains(@class, 'layout active') and contains(@class, 'row') and contains(@class, 'shrink')]"
|
RACK_CONTAINER = ("//div[contains(@class, 'layout active') and "
|
||||||
|
"contains(@class, 'row') and contains(@class, 'shrink')]")
|
||||||
|
|
||||||
# Основной контейнер стойки (изображение стойки)
|
# Основной контейнер стойки (изображение стойки)
|
||||||
MAIN_CONTAINER = "//div[contains(@class, 'layout cabinet')]"
|
MAIN_CONTAINER = "//div[contains(@class, 'layout cabinet')]"
|
||||||
|
|
@ -99,7 +141,8 @@ class RackLocators:
|
||||||
INACTIVE_SIDE_BUTTON = "//button[contains(@class, 'secondary--text')]"
|
INACTIVE_SIDE_BUTTON = "//button[contains(@class, 'secondary--text')]"
|
||||||
|
|
||||||
# Для получения текста активной стороны
|
# Для получения текста активной стороны
|
||||||
ACTIVE_SIDE_BUTTON_TEXT = "//button[contains(@class, 'primary--text')]//div[contains(@class, 'v-btn__content')]"
|
ACTIVE_SIDE_BUTTON_TEXT = ("//button[contains(@class, 'primary--text')]"
|
||||||
|
"//div[contains(@class, 'v-btn__content')]")
|
||||||
|
|
||||||
# Кнопка добавления (add_circle)
|
# Кнопка добавления (add_circle)
|
||||||
ADD_CIRCLE_BUTTON = "//i[contains(text(), 'add_circle')]"
|
ADD_CIRCLE_BUTTON = "//i[contains(text(), 'add_circle')]"
|
||||||
|
|
@ -108,11 +151,12 @@ class RackLocators:
|
||||||
ALL_UNITS = "//div[contains(@class, 'unit')]"
|
ALL_UNITS = "//div[contains(@class, 'unit')]"
|
||||||
|
|
||||||
# Позиции юнитов
|
# Позиции юнитов
|
||||||
UNIT_POSITIONS = "//div[contains(@class, 'headline') and contains(@class, 'test-xs-center') and contains(@class, 'unit-positions')]"
|
UNIT_POSITIONS = ("//div[contains(@class, 'headline') and "
|
||||||
|
"contains(@class, 'test-xs-center') and "
|
||||||
|
"contains(@class, 'unit-positions')]")
|
||||||
|
|
||||||
# Локатор для устройств
|
# Локатор для устройств
|
||||||
DEVICE_ELEMENTS = "//div[contains(@class, 'parent-class')]"
|
DEVICE_ELEMENTS = "//div[contains(@class, 'parent-class')]"
|
||||||
|
|
||||||
# Локатор для слотов в устройствах
|
# Локатор для слотов в устройствах
|
||||||
DEVICE_SLOTS = "//div[contains(@class, 'slot')]"
|
DEVICE_SLOTS = "//div[contains(@class, 'slot')]"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ from pages.main_page import MainPage
|
||||||
|
|
||||||
logger = get_logger("CREATE_RACK_ELEMENT_TEST")
|
logger = get_logger("CREATE_RACK_ELEMENT_TEST")
|
||||||
|
|
||||||
|
logger.setLevel("INFO")
|
||||||
|
|
||||||
# @pytest.mark.smoke
|
# @pytest.mark.smoke
|
||||||
class TestCreateRackElement:
|
class TestCreateRackElement:
|
||||||
"""Тест создания дочернего элемента типа 'Стойка'.
|
"""Тест создания дочернего элемента типа 'Стойка'.
|
||||||
|
|
@ -55,7 +57,7 @@ class TestCreateRackElement:
|
||||||
# Создаем экземпляр страницы локации
|
# Создаем экземпляр страницы локации
|
||||||
self.location_page = LocationPage(browser)
|
self.location_page = LocationPage(browser)
|
||||||
|
|
||||||
@pytest.mark.develop
|
#@pytest.mark.develop
|
||||||
def test_create_rack_content(self, browser: Page) -> None:
|
def test_create_rack_content(self, browser: Page) -> None:
|
||||||
"""Тест создания дочернего элемента типа 'Стойка'."""
|
"""Тест создания дочернего элемента типа 'Стойка'."""
|
||||||
|
|
||||||
|
|
@ -82,7 +84,7 @@ class TestCreateRackElement:
|
||||||
|
|
||||||
# Проверяем что после выбора 'Стойка' появляются специфичные поля
|
# Проверяем что после выбора 'Стойка' появляются специфичные поля
|
||||||
rack_maker.check_rack_fields_presence()
|
rack_maker.check_rack_fields_presence()
|
||||||
logger.info("Rack-specific fields are displayed correctly")
|
logger.debug("Rack-specific fields are displayed correctly")
|
||||||
|
|
||||||
create_child_frame.should_be_toolbar_buttons()
|
create_child_frame.should_be_toolbar_buttons()
|
||||||
|
|
||||||
|
|
@ -112,8 +114,8 @@ class TestCreateRackElement:
|
||||||
serial="TEST123456",
|
serial="TEST123456",
|
||||||
inventory="INV-001",
|
inventory="INV-001",
|
||||||
comment="Тестовая стойка для автоматизации",
|
comment="Тестовая стойка для автоматизации",
|
||||||
cable_entry="Сверху",
|
state="Введен в эксплуатацию",
|
||||||
state="В эксплуатации"
|
cable_entry="сверху"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Заполняем данные стойки
|
# Заполняем данные стойки
|
||||||
|
|
@ -123,7 +125,7 @@ class TestCreateRackElement:
|
||||||
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)
|
||||||
|
|
||||||
logger.info("Test for creating 'Rack' child element completed successfully")
|
logger.debug("Test for creating 'Rack' child element completed successfully")
|
||||||
|
|
||||||
def test_create_rack_with_duplicate_name(self, browser: Page) -> None:
|
def test_create_rack_with_duplicate_name(self, browser: Page) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -133,20 +135,20 @@ class TestCreateRackElement:
|
||||||
стойки с именем, которое уже используется.
|
стойки с именем, которое уже используется.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger.info("Starting test for creating rack with duplicate name")
|
logger.debug("Starting test for creating rack with duplicate name")
|
||||||
|
|
||||||
rack_name = "Test-Rack-01"
|
rack_name = "Test-Rack-01"
|
||||||
|
|
||||||
# Проверяем, существует ли уже стойка с таким именем
|
# Проверяем, существует ли уже стойка с таким именем
|
||||||
if not self._check_rack_existance(browser, rack_name):
|
if not self._check_rack_existance(browser, rack_name):
|
||||||
logger.info(f"Rack with name '{rack_name}' not found. Creating first rack.")
|
logger.debug(f"Rack with name '{rack_name}' not found. Creating first rack.")
|
||||||
self._create_rack(browser, rack_name)
|
self._create_rack(browser, rack_name)
|
||||||
logger.info(f"First rack with name '{rack_name}' created successfully")
|
logger.debug(f"First rack with name '{rack_name}' created successfully")
|
||||||
else:
|
else:
|
||||||
logger.info(f"Rack with name '{rack_name}' already exists, proceeding to create second one")
|
logger.debug(f"Rack with name '{rack_name}' already exists, proceeding to create second one")
|
||||||
|
|
||||||
# Создаем вторую стойку с тем же именем
|
# Создаем вторую стойку с тем же именем
|
||||||
logger.info(f"Attempting to create second rack with name '{rack_name}'")
|
logger.debug(f"Attempting to create second rack with name '{rack_name}'")
|
||||||
|
|
||||||
# Переходим обратно к созданию новой стойки
|
# Переходим обратно к созданию новой стойки
|
||||||
self.main_page.click_main_navigation_panel_item("test-zone")
|
self.main_page.click_main_navigation_panel_item("test-zone")
|
||||||
|
|
@ -192,7 +194,7 @@ class TestCreateRackElement:
|
||||||
create_child_frame.wait_for_timeout(2000)
|
create_child_frame.wait_for_timeout(2000)
|
||||||
create_child_frame.alert.close_alert_by_text(expected_alert_text)
|
create_child_frame.alert.close_alert_by_text(expected_alert_text)
|
||||||
|
|
||||||
logger.info("System prevented creating rack with duplicate name")
|
logger.debug("System prevented creating rack with duplicate name")
|
||||||
|
|
||||||
def _perform_required_fields_test(self, create_child_frame, rack_maker, test_data):
|
def _perform_required_fields_test(self, create_child_frame, rack_maker, test_data):
|
||||||
"""Выполняет один тест валидации обязательных полей.
|
"""Выполняет один тест валидации обязательных полей.
|
||||||
|
|
@ -215,13 +217,13 @@ class TestCreateRackElement:
|
||||||
"""Проверяет, заполнено ли combobox поле."""
|
"""Проверяет, заполнено ли combobox поле."""
|
||||||
|
|
||||||
# Получаем локатор поля
|
# Получаем локатор поля
|
||||||
field_locator = create_child_frame._get_field_locator(field_name)
|
field_locator = create_child_frame.get_field_locator(field_name)
|
||||||
|
|
||||||
# Находим элемент поля
|
# Находим элемент поля
|
||||||
field_element = create_child_frame.page.locator(field_locator).first
|
field_element = create_child_frame.page.locator(field_locator).first
|
||||||
|
|
||||||
if not field_element.is_visible():
|
if not field_element.is_visible():
|
||||||
logger.info(f"Field '{field_name}' not visible")
|
logger.debug(f"Field '{field_name}' not visible")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Проверяем наличие кнопки закрытия (крестика) - признак заполненного поля
|
# Проверяем наличие кнопки закрытия (крестика) - признак заполненного поля
|
||||||
|
|
@ -236,27 +238,27 @@ class TestCreateRackElement:
|
||||||
field_text = field_element.text_content() or ""
|
field_text = field_element.text_content() or ""
|
||||||
has_text = bool(field_text.strip())
|
has_text = bool(field_text.strip())
|
||||||
|
|
||||||
logger.info(f"Field '{field_name}' - has close button: {has_close_button}, has text: {has_text}")
|
logger.debug(f"Field '{field_name}' - has close button: {has_close_button}, has text: {has_text}")
|
||||||
|
|
||||||
return has_close_button or has_text
|
return has_close_button or has_text
|
||||||
|
|
||||||
# Проверяем и очищаем поле "Глубина (мм)" только если оно заполнено
|
# Проверяем и очищаем поле "Глубина (мм)" только если оно заполнено
|
||||||
logger.info("Checking field: Depth (mm)")
|
logger.debug("Checking field: Depth (mm)")
|
||||||
if is_field_filled("Глубина (мм)"):
|
if is_field_filled("Глубина (мм)"):
|
||||||
logger.info("Field 'Depth (mm)' is filled, performing clearing")
|
logger.debug("Field 'Depth (mm)' is filled, performing clearing")
|
||||||
create_child_frame.clear_combobox_field("Глубина (мм)")
|
create_child_frame.clear_combobox_field("Глубина (мм)")
|
||||||
logger.info("Clearing completed for 'Depth (mm)'")
|
logger.debug("Clearing completed for 'Depth (mm)'")
|
||||||
else:
|
else:
|
||||||
logger.info("Field 'Depth (mm)' is already empty, skipping clearing")
|
logger.debug("Field 'Depth (mm)' is already empty, skipping clearing")
|
||||||
|
|
||||||
# Проверяем и очищаем поле "Высота в юнитах" только если оно заполнено
|
# Проверяем и очищаем поле "Высота в юнитах" только если оно заполнено
|
||||||
logger.info("Checking field: Height in units")
|
logger.debug("Checking field: Height in units")
|
||||||
if is_field_filled("Высота в юнитах"):
|
if is_field_filled("Высота в юнитах"):
|
||||||
logger.info("Field 'Height in units' is filled, performing clearing")
|
logger.debug("Field 'Height in units' is filled, performing clearing")
|
||||||
create_child_frame.clear_combobox_field("Высота в юнитах")
|
create_child_frame.clear_combobox_field("Высота в юнитах")
|
||||||
logger.info("Clearing completed for 'Height in units'")
|
logger.debug("Clearing completed for 'Height in units'")
|
||||||
else:
|
else:
|
||||||
logger.info("Field 'Height in units' is already empty, skipping clearing")
|
logger.debug("Field 'Height in units' is already empty, skipping clearing")
|
||||||
|
|
||||||
# Создаем объект данных стойки
|
# Создаем объект данных стойки
|
||||||
rack_data = RackData(
|
rack_data = RackData(
|
||||||
|
|
@ -266,47 +268,47 @@ class TestCreateRackElement:
|
||||||
)
|
)
|
||||||
|
|
||||||
# Заполняем данные стойки
|
# Заполняем данные стойки
|
||||||
logger.info(f"Setting test data - Name: '{name_value}', Height: '{height_value}', Depth: '{depth_value}'")
|
logger.debug(f"Setting test data - Name: '{name_value}', Height: '{height_value}', Depth: '{depth_value}'")
|
||||||
rack_maker.fill_rack_data(rack_data)
|
rack_maker.fill_rack_data(rack_data)
|
||||||
|
|
||||||
# Нажимаем кнопку создания
|
# Нажимаем кнопку создания
|
||||||
logger.info("Submitting form for validation")
|
logger.debug("Submitting form for validation")
|
||||||
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)
|
||||||
|
|
||||||
# Проверяем валидацию полей
|
# Проверяем валидацию полей
|
||||||
logger.info("Checking validation results")
|
logger.debug("Checking validation results")
|
||||||
|
|
||||||
if height_value:
|
if height_value:
|
||||||
create_child_frame.check_field_error_not_highlighted("Высота в юнитах")
|
create_child_frame.check_field_error_not_highlighted("Высота в юнитах")
|
||||||
logger.info("Height field validation passed")
|
logger.debug("Height field validation passed")
|
||||||
else:
|
else:
|
||||||
create_child_frame.check_field_error_highlighted("Высота в юнитах")
|
create_child_frame.check_field_error_highlighted("Высота в юнитах")
|
||||||
logger.info("Height field validation failed as expected")
|
logger.debug("Height field validation failed as expected")
|
||||||
|
|
||||||
if depth_value:
|
if depth_value:
|
||||||
create_child_frame.check_field_error_not_highlighted("Глубина (мм)")
|
create_child_frame.check_field_error_not_highlighted("Глубина (мм)")
|
||||||
logger.info("Depth field validation passed")
|
logger.debug("Depth field validation passed")
|
||||||
else:
|
else:
|
||||||
create_child_frame.check_field_error_highlighted("Глубина (мм)")
|
create_child_frame.check_field_error_highlighted("Глубина (мм)")
|
||||||
logger.info("Depth field validation failed as expected")
|
logger.debug("Depth field validation failed as expected")
|
||||||
|
|
||||||
# Обрабатываем alert-окна
|
# Обрабатываем alert-окна
|
||||||
if not height_value:
|
if not height_value:
|
||||||
logger.info("Expecting height validation alert")
|
logger.debug("Expecting height validation alert")
|
||||||
create_child_frame.alert.check_alert_presence(expected_alert_height)
|
create_child_frame.alert.check_alert_presence(expected_alert_height)
|
||||||
create_child_frame.alert.close_alert_by_text(expected_alert_height)
|
create_child_frame.alert.close_alert_by_text(expected_alert_height)
|
||||||
logger.info("Height alert handled")
|
logger.debug("Height alert handled")
|
||||||
|
|
||||||
if not depth_value:
|
if not depth_value:
|
||||||
logger.info("Expecting depth validation alert")
|
logger.debug("Expecting depth validation alert")
|
||||||
create_child_frame.alert.check_alert_presence(expected_alert_depth)
|
create_child_frame.alert.check_alert_presence(expected_alert_depth)
|
||||||
create_child_frame.alert.close_alert_by_text(expected_alert_depth)
|
create_child_frame.alert.close_alert_by_text(expected_alert_depth)
|
||||||
logger.info("Depth alert handled")
|
logger.debug("Depth alert handled")
|
||||||
|
|
||||||
# Проверяем, что остались на странице создания
|
# Проверяем, что остались на странице создания
|
||||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||||
logger.info("Test completed successfully")
|
logger.debug("Test completed successfully")
|
||||||
|
|
||||||
def test_required_fields_validation(self, browser: Page) -> None:
|
def test_required_fields_validation(self, browser: Page) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -382,14 +384,14 @@ class TestCreateRackElement:
|
||||||
|
|
||||||
# Выполняем тестовые случаи
|
# Выполняем тестовые случаи
|
||||||
for test_case in test_cases:
|
for test_case in test_cases:
|
||||||
logger.info(test_case["name"])
|
logger.debug(test_case["name"])
|
||||||
self._perform_required_fields_test(
|
self._perform_required_fields_test(
|
||||||
create_child_frame, rack_maker, test_case["data"]
|
create_child_frame, rack_maker, test_case["data"]
|
||||||
)
|
)
|
||||||
logger.info("System prevented creating rack with invalid required fields")
|
logger.debug("System prevented creating rack with invalid required fields")
|
||||||
|
|
||||||
# 5. Тест: Заполняем все обязательные поля
|
# 5. Тест: Заполняем все обязательные поля
|
||||||
logger.info("Test 5: All required fields are filled")
|
logger.debug("Test 5: All required fields are filled")
|
||||||
|
|
||||||
# Генерируем уникальное имя для финального теста
|
# Генерируем уникальное имя для финального теста
|
||||||
final_rack_name = "Test-Rack-Required-Final"
|
final_rack_name = "Test-Rack-Required-Final"
|
||||||
|
|
@ -408,7 +410,7 @@ class TestCreateRackElement:
|
||||||
create_child_frame.check_field_error_not_highlighted("Имя")
|
create_child_frame.check_field_error_not_highlighted("Имя")
|
||||||
create_child_frame.check_field_error_not_highlighted("Высота в юнитах")
|
create_child_frame.check_field_error_not_highlighted("Высота в юнитах")
|
||||||
create_child_frame.check_field_error_not_highlighted("Глубина (мм)")
|
create_child_frame.check_field_error_not_highlighted("Глубина (мм)")
|
||||||
logger.info("No required fields are highlighted with error color - all fields filled correctly")
|
logger.debug("No required fields are highlighted with error color - all fields filled correctly")
|
||||||
|
|
||||||
# Нажимаем кнопку создания
|
# Нажимаем кнопку создания
|
||||||
create_child_frame.click_add_button()
|
create_child_frame.click_add_button()
|
||||||
|
|
@ -417,21 +419,21 @@ class TestCreateRackElement:
|
||||||
# Проверяем, что НЕТ alert-окон для всех обязательных полей
|
# Проверяем, что НЕТ alert-окон для всех обязательных полей
|
||||||
create_child_frame.alert.check_alert_absence(expected_alert_text_height, 1000)
|
create_child_frame.alert.check_alert_absence(expected_alert_text_height, 1000)
|
||||||
create_child_frame.alert.check_alert_absence(expected_alert_text_depth, 1000)
|
create_child_frame.alert.check_alert_absence(expected_alert_text_depth, 1000)
|
||||||
logger.info("No alert windows for required fields appeared - all fields filled correctly")
|
logger.debug("No alert windows for required fields appeared - all fields filled correctly")
|
||||||
|
|
||||||
# Проверяем, что ушли со страницы создания
|
# Проверяем, что ушли со страницы создания
|
||||||
try:
|
try:
|
||||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||||
logger.warning("Rack creation may not have completed successfully")
|
logger.warning("Rack creation may not have completed successfully")
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
logger.info("Creation page closed - rack successfully created")
|
logger.debug("Creation page closed - rack successfully created")
|
||||||
|
|
||||||
logger.info("Required fields validation test completed successfully")
|
logger.debug("Required fields validation test completed successfully")
|
||||||
|
|
||||||
def _check_rack_existance(self, browser: Page, rack_name: str) -> bool:
|
def _check_rack_existance(self, browser: Page, rack_name: str) -> bool:
|
||||||
"""Проверяет существование стойки."""
|
"""Проверяет существование стойки."""
|
||||||
|
|
||||||
logger.info(f"Checking existence of rack with name '{rack_name}'")
|
logger.debug(f"Checking existence of rack with name '{rack_name}'")
|
||||||
|
|
||||||
# Обновляем навигационную панель
|
# Обновляем навигационную панель
|
||||||
self.main_page.click_main_navigation_panel_item("Объекты")
|
self.main_page.click_main_navigation_panel_item("Объекты")
|
||||||
|
|
@ -446,16 +448,16 @@ class TestCreateRackElement:
|
||||||
element = browser.locator(nav_panel_locator).get_by_text(rack_name).first
|
element = browser.locator(nav_panel_locator).get_by_text(rack_name).first
|
||||||
|
|
||||||
if element.is_visible():
|
if element.is_visible():
|
||||||
logger.info(f"Rack with name '{rack_name}' found")
|
logger.debug(f"Rack with name '{rack_name}' found")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
logger.info(f"Rack with name '{rack_name}' not found")
|
logger.debug(f"Rack with name '{rack_name}' not found")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _create_rack(self, browser: Page, rack_name: str) -> None:
|
def _create_rack(self, browser: Page, rack_name: str) -> None:
|
||||||
"""Создает стойку."""
|
"""Создает стойку."""
|
||||||
|
|
||||||
logger.info(f"Creating rack with name '{rack_name}'")
|
logger.debug(f"Creating rack with name '{rack_name}'")
|
||||||
|
|
||||||
# Переходим обратно к созданию новой стойки
|
# Переходим обратно к созданию новой стойки
|
||||||
self.main_page.click_main_navigation_panel_item("test-zone")
|
self.main_page.click_main_navigation_panel_item("test-zone")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue