Изменения после проверки pylint

ra2/create_element_rack
Radislav 2026-01-19 08:24:45 +03:00
parent a25db67097
commit 3680e42c86
4 changed files with 514 additions and 589 deletions

View File

@ -35,44 +35,98 @@ class RackObjectMaker(BaseComponent):
Инициализирует компонент создания стойки.
Args:
page: Экземпляр страницы Playwright
page (Page): Экземпляр страницы Playwright
"""
super().__init__(page)
# Действия:
def fill_rack_data(self, rack_data: RackData) -> None:
def _fill_combobox_field(self, field_name: str, value: str, fields_locators: dict) -> None:
"""
Заполняет данные для создания стойки.
Заполняет combobox поле.
Args:
rack_data: Данные стойки
field_name (str): Название поля
value (str): Значение для установки
fields_locators (dict): Словарь с найденными полями формы
Raises:
ValueError: Если поле не найдено в форме
"""
logger.debug(f"Filling rack data: {rack_data.name}")
# Получаем контейнер поля по его названию
field_container = fields_locators.get(field_name)
self._fill_text_fields(rack_data)
self._fill_combobox_fields(rack_data)
if not field_container:
logger.error(f"Field '{field_name}' not found in form. Available fields: {list(fields_locators.keys())}")
raise ValueError(f"Field '{field_name}' not found in form")
logger.debug("Rack data filled successfully")
logger.debug(f"Filling field '{field_name}' with value '{value}'...")
def _get_form_fields(self) -> dict:
"""
Получает все поля формы стойки.
# Прокручиваем до поля
field_container.scroll_into_view_if_needed()
self.wait_for_timeout(300)
Returns:
dict: Словарь {название поля: Locator контейнера поля}
"""
# Проверяем видимость поля
self.check_visibility(field_container, f"Field '{field_name}' not found")
# Получаем контейнер формы (второй элемент)
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
# Находим кнопку открытия выпадающего списка внутри контейнера поля
open_button = field_container.locator(".v-input__append-inner").first
if container_locator.count() == 0:
logger.error("Form container not found")
raise ValueError("Form container not found")
# Кликаем для открытия выпадающего списка
open_button.click(force=True)
self.wait_for_timeout(300)
return self.get_input_fields_locators(container_locator)
# Вводим значение из выпадающего списка
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(300)
element.click()
logger.debug(f"Field '{field_name}' filled successfully")
def _fill_combobox_fields(self, rack_data: RackData) -> None:
"""Заполняет combobox поля."""
# Получаем все поля формы
fields_locators = self._get_form_fields()
# Обязательные поля.
if rack_data.height:
self._fill_combobox_field("Высота в юнитах", rack_data.height, fields_locators)
logger.debug(f"Selected height: {rack_data.height} units")
if rack_data.depth:
self._fill_combobox_field("Глубина (мм)", rack_data.depth, fields_locators)
logger.debug(f"Selected depth: {rack_data.depth} mm")
# Опциональные поля.
if rack_data.cable_entry:
self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry, fields_locators)
logger.debug(f"Selected cable entry: {rack_data.cable_entry}")
if rack_data.state:
self._fill_combobox_field("Состояние", rack_data.state, fields_locators)
logger.debug(f"Selected state: {rack_data.state}")
if rack_data.owner:
self._fill_combobox_field("Владелец", rack_data.owner, fields_locators)
logger.debug(f"Selected owner: {rack_data.owner}")
if rack_data.service_org:
self._fill_combobox_field("Обслуживающая организация", rack_data.service_org, fields_locators)
logger.debug(f"Selected service organization: {rack_data.service_org}")
if rack_data.project:
self._fill_combobox_field("Проект/Титул", rack_data.project, fields_locators)
logger.debug(f"Selected project/title: {rack_data.project}")
def _fill_text_fields(self, rack_data: RackData) -> None:
"""Заполняет текстовые поля."""
@ -144,95 +198,33 @@ class RackObjectMaker(BaseComponent):
logger.debug("Text fields filled successfully")
def _fill_combobox_fields(self, rack_data: RackData) -> None:
"""Заполняет combobox поля."""
# Получаем все поля формы
fields_locators = self._get_form_fields()
# Обязательные поля.
if rack_data.height:
self._fill_combobox_field("Высота в юнитах", rack_data.height, fields_locators)
logger.debug(f"Selected height: {rack_data.height} units")
if rack_data.depth:
self._fill_combobox_field("Глубина (мм)", rack_data.depth, fields_locators)
logger.debug(f"Selected depth: {rack_data.depth} mm")
# Опциональные поля.
if rack_data.cable_entry:
self._fill_combobox_field("Ввод кабеля", rack_data.cable_entry, fields_locators)
logger.debug(f"Selected cable entry: {rack_data.cable_entry}")
if rack_data.state:
self._fill_combobox_field("Состояние", rack_data.state, fields_locators)
logger.debug(f"Selected state: {rack_data.state}")
if rack_data.owner:
self._fill_combobox_field("Владелец", rack_data.owner, fields_locators)
logger.debug(f"Selected owner: {rack_data.owner}")
if rack_data.service_org:
self._fill_combobox_field("Обслуживающая организация", rack_data.service_org, fields_locators)
logger.debug(f"Selected service organization: {rack_data.service_org}")
if rack_data.project:
self._fill_combobox_field("Проект/Титул", rack_data.project, fields_locators)
logger.debug(f"Selected project/title: {rack_data.project}")
def _fill_combobox_field(self, field_name: str, value: str, fields_locators: dict) -> None:
def _get_form_fields(self) -> dict:
"""
Заполняет combobox поле.
Получает все поля формы стойки.
Args:
field_name: Название поля
value: Значение для установки
fields_locators: Словарь с найденными полями формы
Returns:
dict: Словарь {название поля: Locator контейнера поля}
Raises:
ValueError: Если контейнер формы не найден
"""
# Получаем контейнер поля по его названию
field_container = fields_locators.get(field_name)
# Получаем контейнер формы (второй элемент)
container_locator = self.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
if not field_container:
logger.error(f"Field '{field_name}' not found in form. Available fields: {list(fields_locators.keys())}")
raise ValueError(f"Field '{field_name}' not found in form")
if container_locator.count() == 0:
logger.error("Form container not found")
raise ValueError("Form container not found")
logger.debug(f"Filling field '{field_name}' with value '{value}'...")
# Прокручиваем до поля
field_container.scroll_into_view_if_needed()
self.wait_for_timeout(300)
# Проверяем видимость поля
self.check_visibility(field_container, f"Field '{field_name}' not found")
# Находим кнопку открытия выпадающего списка внутри контейнера поля
open_button = field_container.locator(".v-input__append-inner").first
# Кликаем для открытия выпадающего списка
open_button.click(force=True)
self.wait_for_timeout(300)
# Вводим значение из выпадающего списка
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(300)
element.click()
logger.debug(f"Field '{field_name}' filled successfully")
return self.get_input_fields_locators(container_locator)
def _scroll_until_element(self, locator: Locator, name: str) -> None:
"""
Скроллит список до тех пор, пока не перестанут подгружаться новые элементы.
Args:
locator: Локатор элементов или строка с CSS/XPath.
locator (Locator): Локатор элементов или строка с CSS/XPath
name (str): Имя элемента для поиска
"""
loc = self.get_locator(locator)
@ -266,6 +258,21 @@ class RackObjectMaker(BaseComponent):
self.wait_for_timeout(300)
def fill_rack_data(self, rack_data: RackData) -> None:
"""
Заполняет данные для создания стойки.
Args:
rack_data (RackData): Данные стойки
"""
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 check_rack_fields_presence(self) -> None:

View File

@ -1,7 +1,7 @@
"""Модуль фрейма создания дочернего элемента."""
import re
from playwright.sync_api import expect, Page, Locator
from playwright.sync_api import Page, Locator
from tools.logger import get_logger
from locators.rack_locators import RackLocators
from locators.selection_bar_locators import SelectionBarLocators
@ -23,7 +23,7 @@ class CreateChildElementFrame(BaseComponent):
Инициализирует фрейм создания дочернего элемента.
Args:
page: Экземпляр страницы Playwright
page (Page): Экземпляр страницы Playwright
"""
super().__init__(page)
@ -54,7 +54,7 @@ class CreateChildElementFrame(BaseComponent):
Очищает combobox поле по его названию.
Args:
field_name: Название поля для очистки
field_name (str): Название поля для очистки
"""
logger.debug(f"Clearing combobox field '{field_name}'...")
@ -114,13 +114,14 @@ class CreateChildElementFrame(BaseComponent):
"""
return self.selection_bar.get_selection_bar_title()
def is_field_filled(self, field_name: str, container_locator: Locator = None) -> bool:
"""
Проверяет, заполнено ли combobox или текстовое поле.
Args:
field_name: Название поля для проверки
container_locator: Локатор контейнера формы (опционально)
field_name (str): Название поля для проверки
container_locator (Locator, optional): Локатор контейнера формы
Returns:
bool: True если поле заполнено, False в противном случае
@ -192,7 +193,12 @@ class CreateChildElementFrame(BaseComponent):
logger.debug("Combobox menu is already open")
def select_object_class(self, class_name: str) -> None:
"""Выбирает класс объекта из выпадающего списка."""
"""
Выбирает класс объекта из выпадающего списка.
Args:
class_name (str): Название класса объекта для выбора
"""
logger.debug(f"Selecting object class: '{class_name}'...")
@ -214,7 +220,11 @@ class CreateChildElementFrame(BaseComponent):
Проверяет, что поле подсвечено цветом ошибки (валидация не пройдена).
Args:
field_name: Название поля для проверки
field_name (str): Название поля для проверки
Raises:
ValueError: Если поле не найдено в форме
AssertionError: Если поле не подсвечено ошибкой
"""
logger.debug(f"Checking field '{field_name}' for error highlighting...")
@ -247,7 +257,11 @@ class CreateChildElementFrame(BaseComponent):
Проверяет, что поле НЕ подсвечено цветом ошибки (валидация успешна).
Args:
field_name: Название поля для проверки
field_name (str): Название поля для проверки
Raises:
ValueError: Если поле не найдено в форме
AssertionError: Если поле подсвечено ошибкой
"""
logger.debug(f"Checking field '{field_name}' for absence of error highlighting...")
@ -280,7 +294,10 @@ class CreateChildElementFrame(BaseComponent):
Проверяет что выбран указанный класс объекта.
Args:
expected_class: Ожидаемый выбранный класс объекта
expected_class (str): Ожидаемый выбранный класс объекта
Raises:
AssertionError: Если выбранный класс не соответствует ожидаемому
"""
logger.debug(f"Checking selected object class: '{expected_class}'...")
@ -306,7 +323,10 @@ class CreateChildElementFrame(BaseComponent):
Проверяет заголовок тулбара.
Args:
expected_title: Ожидаемый заголовок тулбара
expected_title (str): Ожидаемый заголовок тулбара
Raises:
AssertionError: Если заголовок не соответствует ожидаемому
"""
logger.debug(f"Checking toolbar title: '{expected_title}'...")

View File

@ -15,7 +15,7 @@ from pages.base_page import BasePage
logger = get_logger("RACK_PAGE")
#logger.setLevel("INFO")
logger.setLevel("INFO")
# Специфичные локаторы оставленые в основном коде
PANEL_HEADER = "//span[text()='Объекты']/following-sibling::i"
@ -31,7 +31,7 @@ class RackPage(BasePage):
Инициализирует объект вкладки стойки.
Args:
page: Экземпляр страницы Playwright
page (Page): Экземпляр страницы Playwright
"""
super().__init__(page)
@ -87,10 +87,10 @@ class RackPage(BasePage):
# Проверяем тултип кнопки (может быть "Удалить" или "Remove")
try:
self.toolbar.check_button_tooltip("remove", "Удалить")
except:
except AssertionError:
try:
self.toolbar.check_button_tooltip("remove", "Remove")
except:
except AssertionError:
logger.debug("Could not verify tooltip text for remove button")
# Кликаем на кнопку удаления
@ -100,12 +100,50 @@ class RackPage(BasePage):
# Ожидаем появления диалога подтверждения
self._handle_remove_confirmation_dialog()
def _handle_remove_confirmation_dialog(self) -> None:
def confirm_remove_dialog(self, confirm: bool = True) -> None:
"""
Обрабатывает диалог подтверждения удаления.
Подтверждает или отклоняет удаление в диалоговом окне.
Args:
confirm (bool): Если True - подтвердить удаление, если False - отменить
"""
logger.debug("Handling remove confirmation dialog...")
self.confirm_remove_dialog(confirm=True)
logger.debug(f"Confirming remove dialog with: {'Да' if confirm else 'Нет'}")
# Ждем немного перед поиском диалога
self.wait_for_timeout(1500)
# Ищем активный диалог
dialog = self.page.locator("div.v-dialog--active")
# Проверяем, что диалог найден и содержит нужный текст
assert dialog.count() > 0, "No active dialog found"
# Проверяем текст диалога
dialog_text = dialog.first.text_content()
logger.debug("Dialog text: %s", dialog_text)
# Должен содержать "Запрос подтверждения" и "Удалить"
assert "Запрос подтверждения" in dialog_text, "Not a confirmation dialog"
# Ищем кнопку по data-testid
if confirm:
button = self.page.locator(RackLocators.CONFIRM_REMOVE_YES_BUTTON)
else:
button = self.page.locator(RackLocators.CONFIRM_REMOVE_NO_BUTTON)
# Проверяем, что кнопка найдена
assert button.count() > 0, "Button not found with selector"
# Кликаем на кнопку
button_text = button.first.text_content()
logger.debug("Clicking button with text: %s", button_text)
button.first.click()
self.wait_for_timeout(2000)
# Проверяем, что диалог закрылся
self.wait_for_timeout(1000)
logger.debug("Remove confirmation completed")
def get_available_tabs(self) -> list[str]:
"""
@ -124,7 +162,7 @@ class RackPage(BasePage):
tab_elements.first.wait_for(state="visible", timeout=5000)
total_count = tab_elements.count()
logger.debug(f"Total top tab elements found: {total_count}")
logger.debug("Total top tab elements found: %d", total_count)
for i in range(total_count):
element = tab_elements.nth(i)
@ -136,9 +174,9 @@ class RackPage(BasePage):
tab_text = tab_text.strip()
if tab_text and tab_text not in tabs:
tabs.append(tab_text)
logger.debug(f"Top tab found: '{tab_text}'")
logger.debug("Top tab found: '%s'", tab_text)
logger.debug(f"Available top tabs found: {tabs}")
logger.debug("Available top tabs found: %s", tabs)
return tabs
def get_current_active_side(self) -> Optional[str]:
@ -210,13 +248,13 @@ class RackPage(BasePage):
Переключается на указанную вкладку.
Args:
tab_name: Название вкладки для переключения
tab_name (str): Название вкладки для переключения
Raises:
AssertionError: Если вкладка не найдена или недоступна
"""
logger.debug(f"Switching to tab '{tab_name}'...")
logger.debug("Switching to tab '%s'...", tab_name)
tab = self.page.locator(RackLocators.TAB_BY_NAME.format(tab_name))
@ -224,7 +262,7 @@ class RackPage(BasePage):
# Проверяем активность ДО клика
if self.is_tab_active(tab_name):
logger.debug(f"Tab '{tab_name}' is already active")
logger.debug("Tab '%s' is already active", tab_name)
return
# Находим первую видимую вкладку с нужным именем
@ -238,7 +276,7 @@ class RackPage(BasePage):
assert target_tab is not None, f"No visible/available tab '{tab_name}' found"
# Кликаем на вкладку
logger.debug(f"Clicking on tab '{tab_name}'...")
logger.debug("Clicking on tab '%s'...", tab_name)
target_tab.click()
# Ждем изменения активной вкладки
@ -272,21 +310,21 @@ class RackPage(BasePage):
if main_container.count() == 0:
logger.warning("Main rack container not found")
else:
logger.debug(f"Main rack container found (count: {main_container.count()})")
logger.debug("Main rack container found (count: %d)", main_container.count())
expect(main_container.first).to_be_attached()
# Проверяем наличие позиций юнитов
unit_positions = self.page.locator(RackLocators.UNIT_POSITIONS)
if unit_positions.count() > 0:
logger.debug(f"Unit positions found: {unit_positions.count()}")
logger.debug("Unit positions found: %d", unit_positions.count())
if unit_positions.first.text_content():
content = unit_positions.first.text_content().strip()
logger.debug(f"First position: {content}")
logger.debug("First position: %s", content)
# Проверяем наличие кнопок добавления
open_buttons = self.page.locator(RackLocators.ADD_CIRCLE_BUTTON)
if open_buttons.count() > 0:
logger.debug(f"'add_circle' buttons found: {open_buttons.count()}")
logger.debug("'add_circle' buttons found: %d", open_buttons.count())
logger.debug("Rack interface loaded")
@ -306,8 +344,8 @@ class RackPage(BasePage):
device_title = first_device.get_attribute("title") or "No title"
logger.debug(
f"Devices found: {device_count} "
f"(first: ID={device_id}, Title={device_title})"
"Devices found: %d (first: ID=%s, Title=%s)",
device_count, device_id, device_title
)
else:
logger.debug("No devices detected")
@ -315,6 +353,9 @@ class RackPage(BasePage):
def check_tab_switching(self) -> None:
"""
Проверяет переключение между вкладками стойки.
Raises:
AssertionError: Если не удалось переключиться на все вкладки
"""
logger.debug("Testing rack tab switching functionality...")
@ -328,14 +369,14 @@ class RackPage(BasePage):
"Сервисы"
]
logger.debug(f"Defined tabs to test: {defined_tabs}")
logger.debug("Defined tabs to test: %s", defined_tabs)
successful_switches = 0
failed_switches = []
# Тестируем переключение на каждую определенную вкладку
for tab_name in defined_tabs:
logger.debug(f"Testing switch to tab '{tab_name}'...")
logger.debug("Testing switch to tab '%s'...", tab_name)
try:
# Переключаемся на вкладку
@ -343,15 +384,15 @@ class RackPage(BasePage):
# Проверяем, что вкладка активна
if self.is_tab_active(tab_name):
logger.debug(f"Successfully switched to tab '{tab_name}'")
logger.debug("Successfully switched to tab '%s'", tab_name)
successful_switches += 1
else:
logger.warning(f"Tab '{tab_name}' not active after switching")
logger.warning("Tab '%s' not active after switching", tab_name)
failed_switches.append(f"Tab '{tab_name}' is not active after click")
except (AssertionError, TimeoutError) as e:
# Ловим только конкретные исключения, которые могут возникнуть при переключении вкладок
logger.error(f"Error switching to tab '{tab_name}': {e}")
logger.error("Error switching to tab '%s': %s", tab_name, e)
failed_switches.append(f"Tab '{tab_name}' error: {str(e)}")
# Небольшая пауза между переключениями
@ -359,12 +400,12 @@ class RackPage(BasePage):
# Формируем итоговый отчет
logger.debug("=== TAB SWITCHING RESULTS ===")
logger.debug(f"Successful switches: {successful_switches}/{len(defined_tabs)}")
logger.debug("Successful switches: %d/%d", successful_switches, len(defined_tabs))
if failed_switches:
logger.debug("Failed switches:")
for failure in failed_switches:
logger.debug(f" - {failure}")
logger.debug(" - %s", failure)
# Требуем успешного переключения на все определенные вкладки
assert successful_switches == len(defined_tabs), (
@ -374,14 +415,14 @@ class RackPage(BasePage):
f"Errors: {', '.join(failed_switches)}"
)
logger.debug(f"All {successful_switches} defined tabs successfully switched!")
logger.debug("All %d defined tabs successfully switched!", successful_switches)
def is_tab_active(self, tab_name: str) -> bool:
"""
Проверяет, активна ли указанная вкладка.
Args:
tab_name: Название вкладки для проверки
tab_name (str): Название вкладки для проверки
Returns:
bool: True если вкладка активна, False в противном случае
@ -393,10 +434,10 @@ class RackPage(BasePage):
if active_tab.count() > 0 and active_tab.first.is_visible():
active_text = active_tab.first.text_content()
if active_text and active_text.strip() == tab_name:
logger.debug(f"Tab '{tab_name}' is active (via active tab class)")
logger.debug("Tab '%s' is active (via active tab class)", tab_name)
return True
logger.debug(f"Tab '{tab_name}' is not active")
logger.debug("Tab '%s' is not active", tab_name)
return False
def should_be_panel_header(self, expected_toolbar_title_items: list[str]) -> None:
@ -404,7 +445,7 @@ class RackPage(BasePage):
Проверяет наличие и корректность заголовка панели.
Args:
expected_toolbar_title_items: Ожидаемые элементы заголовка
expected_toolbar_title_items (list[str]): Ожидаемые элементы заголовка
Raises:
AssertionError: Если заголовок панели не соответствует ожиданиям
@ -426,7 +467,12 @@ class RackPage(BasePage):
)
def should_be_rack_sides_displayed(self) -> None:
"""Проверка отображения и структуры сторон стойки."""
"""
Проверка отображения и структуры сторон стойки.
Raises:
AssertionError: Если стороны стойки не отображаются корректно
"""
logger.debug("Checking rack sides display and structure...")
@ -448,7 +494,7 @@ class RackPage(BasePage):
# Проверяем, какая сторона активна по умолчанию
current_active = self.get_current_active_side()
logger.debug(f"Current active side: {current_active}")
logger.debug("Current active side: %s", current_active)
# Дополнительная проверка устройств
self.check_physical_devices_presence()
@ -461,7 +507,7 @@ class RackPage(BasePage):
# Возвращаемся на исходную активную сторону
if current_active:
logger.debug(f"Returning to original active side: {current_active}")
logger.debug("Returning to original active side: %s", current_active)
if current_active == "Лицевая сторона":
front_side_button.click()
else:
@ -469,7 +515,7 @@ class RackPage(BasePage):
self.wait_for_timeout(1000)
final_active = self.get_current_active_side()
logger.debug(f"Final active side: {final_active}")
logger.debug("Final active side: %s", final_active)
logger.debug("All rack sides checks passed successfully")
@ -478,7 +524,7 @@ class RackPage(BasePage):
Проверяет наличие и функциональность кнопок тулбара.
Raises:
AssertionError: Если кнопки недоступны или подсказки неверны.
AssertionError: Если кнопки недоступны или подсказки неверны
"""
logger.debug("Checking toolbar buttons...")
@ -503,11 +549,12 @@ class RackPage(BasePage):
self.toolbar.check_button_visibility("remove")
self.toolbar.check_button_tooltip("remove", "Удалить")
def should_have_hide_rack_button(self) -> None:
"""
Проверка кнопки "Скрыть стойку".
Проверяет видимость, тултип, кликабельность и эффект скрытия стойки.
Raises:
AssertionError: Если кнопка не отображается или не работает
"""
logger.debug("Checking 'Hide rack' button...")
@ -534,7 +581,9 @@ class RackPage(BasePage):
def should_have_show_rack_button(self) -> None:
"""
Проверка кнопки "Показать стойку".
Проверяет наличие, тултип, кликабельность и эффект показа стойки.
Raises:
AssertionError: Если кнопка не отображается или не работает
"""
logger.debug("Checking 'Show rack' button...")
@ -565,56 +614,56 @@ class RackPage(BasePage):
Проверка структуры конкретной стороны стойки.
Args:
side_name: Название стороны для логов
side_name (str): Название стороны для логов
side_button: Локатор кнопки стороны
Raises:
AssertionError: Если структура стороны некорректна
"""
logger.debug(f"Checking {side_name}...")
logger.debug("Checking %s...", side_name)
# Логируем текущее состояние кнопки перед кликом
button_classes = side_button.get_attribute("class") or ""
logger.debug(f"Button classes before click: {button_classes}")
logger.debug("Button classes before click: %s", button_classes)
# Проверяем, активна ли уже эта сторона
current_active = self.get_current_active_side()
logger.debug(f"Current active side (before click): '{current_active}'")
logger.debug("Current active side (before click): '%s'", current_active)
if current_active == side_name:
logger.debug(f"{side_name} is already active")
logger.debug("%s is already active", side_name)
else:
# Если не активна, кликаем для переключения
logger.debug(f"Switching to {side_name}...")
logger.debug("Switching to %s...", side_name)
side_button.click()
# Даем время на перерисовку классов (увеличиваем время)
self.wait_for_timeout(2500)
# Проверяем классы после клика
button_classes_after = side_button.get_attribute("class") or ""
logger.debug(f"Button classes after click: {button_classes_after}")
logger.debug("Button classes after click: %s", button_classes_after)
# Проверяем, что нужная сторона стала активной
active_side = self.get_current_active_side()
logger.debug(f"Active side after switching: '{active_side}'")
logger.debug("Active side after switching: '%s'", active_side)
assert active_side == side_name, \
f"Wrong side is active: '{active_side}', expected: '{side_name}'"
logger.debug(f"{side_name} successfully activated")
logger.debug("%s successfully activated", side_name)
# Проверяем позиции юнитов
unit_positions = self.page.locator(RackLocators.UNIT_POSITIONS)
total_positions = unit_positions.count()
logger.debug(f"Total unit positions: {total_positions}")
logger.debug("Total unit positions: %d", total_positions)
assert total_positions > 0, f"No unit positions found on {side_name}"
# Проверяем юниты
all_units = self.page.locator(RackLocators.ALL_UNITS)
all_units_count = all_units.count()
units_per_side = all_units_count // 2
logger.debug(f"Units on {side_name}: {units_per_side}")
logger.debug("Units on %s: %d", side_name, units_per_side)
# Проверяем устройства
devices = self.page.locator(RackLocators.DEVICE_ELEMENTS)
@ -631,77 +680,40 @@ class RackPage(BasePage):
slots = first_device.locator(RackLocators.DEVICE_SLOTS)
slot_count = slots.count()
logger.debug(f"Devices found: {device_count} (showing first)")
logger.debug(f" Device: ID={device_id}")
logger.debug(f" Title: {device_title}")
logger.debug(f" Classes: {device_classes}")
logger.debug(f" Slots: {slot_count}")
logger.debug("Devices found: %d (showing first)", device_count)
logger.debug(" Device: ID=%s", device_id)
logger.debug(" Title: %s", device_title)
logger.debug(" Classes: %s", device_classes)
logger.debug(" Slots: %d", slot_count)
else:
logger.debug("No devices detected")
logger.debug(f"{side_name} check completed successfully")
logger.debug("%s check completed successfully", side_name)
def _handle_remove_confirmation_dialog(self) -> None:
"""Обрабатывает диалог подтверждения удаления."""
logger.debug("Handling remove confirmation dialog...")
self.confirm_remove_dialog(confirm=True)
def _wait_for_tab_activation(self, tab_name: str, timeout: int = 5000) -> None:
"""
Ожидает активации вкладки.
Args:
tab_name: Название вкладки для ожидания
timeout: Время ожидания в миллисекундах
tab_name (str): Название вкладки для ожидания
timeout (int, optional): Время ожидания в миллисекундах, по умолчанию 5000
Raises:
AssertionError: Если вкладка не активирована в течение таймаута
"""
logger.debug(f"Waiting for tab '{tab_name}' activation...")
logger.debug("Waiting for tab '%s' activation...", tab_name)
start_time = self.page.evaluate("Date.now()")
while self.page.evaluate("Date.now()") - start_time < timeout:
if self.is_tab_active(tab_name):
logger.debug(f"Tab '{tab_name}' successfully activated")
logger.debug("Tab '%s' successfully activated", tab_name)
return
self.wait_for_timeout(100)
assert False, f"Tab '{tab_name}' not activated within {timeout}ms"
def confirm_remove_dialog(self, confirm: bool = True) -> None:
"""
Подтверждает или отклоняет удаление в диалоговом окне.
"""
logger.debug(f"Confirming remove dialog with: {'Да' if confirm else 'Нет'}")
# Ждем немного перед поиском диалога
self.wait_for_timeout(1500)
# Ищем активный диалог
dialog = self.page.locator("div.v-dialog--active")
# Проверяем, что диалог найден и содержит нужный текст
assert dialog.count() > 0, "No active dialog found"
# Проверяем текст диалога
dialog_text = dialog.first.text_content()
logger.debug(f"Dialog text: {dialog_text}")
# Должен содержать "Запрос подтверждения" и "Удалить"
assert "Запрос подтверждения" in dialog_text, "Not a confirmation dialog"
# Ищем кнопку по data-testid
if confirm:
button = self.page.locator(RackLocators.CONFIRM_REMOVE_YES_BUTTON)
else:
button = self.page.locator(RackLocators.CONFIRM_REMOVE_NO_BUTTON)
# Проверяем, что кнопка найдена
assert button.count() > 0, f"Button not found with selector"
# Кликаем на кнопку
logger.debug(f"Clicking button with text: {button.first.text_content()}")
button.first.click()
self.wait_for_timeout(2000)
# Проверяем, что диалог закрылся
self.wait_for_timeout(1000)
logger.debug("Remove confirmation completed")

View File

@ -15,7 +15,7 @@ from pages.rack_page import RackPage
logger = get_logger("CREATE_RACK_ELEMENT_TEST")
#logger.setLevel("INFO")
logger.setLevel("INFO")
# @pytest.mark.smoke
class TestCreateRackElement:
@ -26,7 +26,6 @@ class TestCreateRackElement:
2. test_create_rack_child_element: Проверяет создание дочернего элемента типа 'Стойка'
3. test_create_rack_with_duplicate_name: Проверяет создание стойки с дублирующимся именем
4. test_required_fields_validation: Проверяет валидацию обязательных полей при создании стойки
5. test_delete_created_rack: Тест удаления созданной стойки
"""
# Инициализируем атрибуты
@ -57,87 +56,57 @@ class TestCreateRackElement:
# Создаем экземпляр страницы локации
self.location_page = LocationPage(browser)
@pytest.fixture(scope="function", autouse=True)
def rack_cleanup_fixture(self, request, browser: Page):
"""
Фикстура для удаления статических тестовых стоек после тестов.
Удаляет стойки, которые создаются в тестах.
"""
# Список статических стоек, которые создаются в тестах
static_racks = [
"Test-Rack-01",
"Test-Rack-Duplicate",
"Test-Rack-Required-Final",
"Test-Rack-Delete"
]
@pytest.fixture
def cleanup_racks(self, browser: Page):
"""Фикстура для очистки созданных стоек."""
# Список для хранения созданных в тесте стоек
created_racks = []
yield
yield created_racks
# После завершения теста удаляем созданные стойки
logger.debug("Cleaning up test 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)
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 static_racks:
# Проверяем существование стойки
if self._check_rack_existance(browser, rack_name):
logger.debug(f"Deleting rack '{rack_name}'...")
# Удаляем каждую стойку если она существует
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.main_page.click_subpanel_item(rack_name, parent="test-zone")
self.main_page.wait_for_timeout(1000)
# Удаляем стойку
self._delete_rack_from_context_menu(browser, rack_name)
# Удаляем стойку
self._delete_rack_from_context_menu(browser, rack_name)
# Проверяем удаление
self.main_page.click_subpanel_item("test-zone")
self.main_page.wait_for_timeout(500)
# Проверяем удаление
self.main_page.click_subpanel_item("test-zone")
self.main_page.wait_for_timeout(500)
# Дополнительная проверка удаления
rack_still_exists = self._check_rack_existance(browser, rack_name)
if rack_still_exists:
logger.error(f"Rack '{rack_name}' still exists after deletion attempt")
# Дополнительная проверка удаления
rack_still_exists = self._check_rack_existance(browser, rack_name)
if rack_still_exists:
logger.error(f"Rack '{rack_name}' still exists after deletion attempt")
logger.debug("Test racks cleanup completed")
logger.debug("Racks cleanup completed")
else:
logger.debug("No racks to cleanup")
#@pytest.mark.develop
def test_create_rack_content(self, browser: Page) -> None:
"""Тест создания дочернего элемента типа 'Стойка'."""
# Проверяем что кнопка "Создать" доступна
self.location_page.should_be_toolbar_buttons()
def _create_rack(self, browser: Page, rack_name: str) -> None:
"""Создает стойку.
# Нажимаем кнопку "Создать" на тулбаре
self.location_page.click_create_button()
# Создаем фрейм создания дочернего элемента
create_child_frame = CreateChildElementFrame(browser)
# Нажимаем на плашку "Класс объекта учета"
create_child_frame.open_object_class_combobox()
# Из выпадающего меню выбираем пункт "Стойка"
create_child_frame.select_object_class("Стойка")
# Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser)
# Проверяем заголовок формы создания
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
# Проверяем что после выбора 'Стойка' появляются специфичные поля
rack_maker.check_rack_fields_presence()
logger.debug("Rack-specific fields are displayed correctly")
create_child_frame.should_be_toolbar_buttons()
#@pytest.mark.develop
def test_create_rack_child_element(self, browser: Page) -> None:
"""Тест создания дочернего элемента типа 'Стойка'."""
Args:
browser: Страница Playwright
rack_name: Имя стойки для создания
"""
logger.debug(f"Creating rack with name '{rack_name}'")
# Нажимаем кнопку "Создать" на тулбаре
self.location_page.click_create_button()
@ -156,151 +125,71 @@ class TestCreateRackElement:
# Создаем объект данных стойки
rack_data = RackData(
name="Test-Rack-01",
name=rack_name,
height="42",
depth="1000",
serial="TEST123456",
inventory="INV-001",
comment="Тестовая стойка для автоматизации",
state="Введен в эксплуатацию",
cable_entry="сверху"
depth="1000"
)
# Сохраняем имя стойки в переменную
rack_name = rack_data.name
# Заполняем данные стойки
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку "Добавить"
# Нажимаем кнопку создания
create_child_frame.click_add_button()
# 1. Проверяем уведомление об успешном создании стойки - требуется создать разработчику (заведена задача)
# Проверяем наличие alert-окна
def _delete_rack_from_context_menu(self, browser: Page, rack_name: str) -> None:
"""Удаляет стойку через контекстное меню.
Args:
browser: Страница Playwright
rack_name: Имя стойки для удаления
"""
logger.debug(f"Deleting rack '{rack_name}' from context menu...")
# 1. Находим элемент стойки в навигационной панели
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)
# 2. Проверяем и нажимаем кнопку "Изменить"
logger.debug("Step 1: Clicking 'Edit' button...")
rack_page = RackPage(browser)
# Проверяем видимость кнопки
rack_page.toolbar.check_button_visibility("edit")
# Проверяем тултип кнопки
rack_page.toolbar.check_button_tooltip("edit", "Изменить")
# Кликаем на кнопку "Изменить"
rack_page.toolbar.get_button_by_name("edit").click()
logger.debug("Edit button clicked, waiting for edit form...")
# 3. Используем метод click_remove_button, который обрабатывает весь процесс удаления
# включая диалог подтверждения
logger.debug("Clicking remove button...")
rack_page.click_remove_button()
# 4. Проверяем уведомление об успешном удалении - требуется создать разработчику (заведена задача)
# Создаем экземпляр фрейма для доступа к alert компоненту
# create_child_frame = CreateChildElementFrame(browser)
# Проверяем наличие любого alert-окна (не обязательно точного текста)
# create_child_frame.alert.check_alert_presence("")
# Получаем текст alert
# Получаем текст alert, чтобы убедиться что удаление прошло успешно
# alert_text = create_child_frame.alert.get_text()
# logger.debug(f"Alert text after creation: {alert_text}")
# logger.debug(f"Alert text after deletion: {alert_text}")
# Проверяем, что в тексте есть указание на успешное создание
# assert "создан" in alert_text.lower() or "успешно" in alert_text.lower()
# assert final_rack_name in alert_text
# Проверяем что в тексте есть указание на успешное удаление
# assert "удален" in alert_text.lower() or "успешно" in alert_text.lower()
# Закрываем alert
# create_child_frame.alert.close_alert()
# 2. Проверяем, что стойка создана и отображается
logger.debug(f"Verifying that rack '{rack_name}' was created...")
# Обновляем навигационную панель
self.main_page.click_main_navigation_panel_item("test-zone")
# Проверяем существование стойки в навигационной панели
rack_exists = self._check_rack_existance(browser, rack_name)
assert rack_exists, f"Rack '{rack_name}' should be visible in navigation panel after creation"
logger.debug(f"Rack '{rack_name}' is visible in navigation panel")
# 3. Очистка: Удаление созданной стойки
logger.debug(f"Cleaning up: deleting test rack '{rack_name}'...")
# Переходим на страницу стойки для удаления
self.main_page.click_subpanel_item(rack_name, parent="test-zone")
self.main_page.wait_for_timeout(1000)
# Удаляем стойку
self._delete_rack_from_context_menu(browser, rack_name)
# Проверяем, что стойка удалена
self.main_page.wait_for_timeout(2000)
rack_still_exists = self._check_rack_existance(browser, rack_name)
assert not rack_still_exists, f"Rack '{rack_name}' should be deleted"
logger.debug(f"Test rack '{rack_name}' successfully cleaned up")
logger.debug("Test for creating 'Rack' child element completed successfully")
@pytest.mark.develop
def test_create_rack_with_duplicate_name(self, browser: Page) -> None:
"""
Тест создания стойки с уже существующим именем.
Проверяет, что система корректно обрабатывает попытку создания
стойки с именем, которое уже используется.
"""
logger.debug("Starting test for creating rack with duplicate name")
rack_name = "Test-Rack-Duplicate"
# Проверяем, существует ли уже стойка с таким именем
if not self._check_rack_existance(browser, rack_name):
logger.debug(f"Rack with name '{rack_name}' not found. Creating first rack.")
self._create_rack(browser, rack_name)
logger.debug(f"First rack with name '{rack_name}' created successfully")
else:
logger.debug(f"Rack with name '{rack_name}' already exists, proceeding to create second one")
# Создаем вторую стойку с тем же именем
logger.debug(f"Attempting to create second rack with name '{rack_name}'")
# Нажимаем кнопку "Создать" на тулбаре
self.location_page.click_create_button()
# Создаем фрейм создания дочернего элемента
create_child_frame = CreateChildElementFrame(browser)
# Нажимаем на плашку "Класс объекта учета"
create_child_frame.open_object_class_combobox()
# Из выпадающего меню выбираем пункт "Стойка"
create_child_frame.select_object_class("Стойка")
# Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser)
# Создаем объект данных для второй стойки
rack_data = RackData(
name=rack_name,
height="42",
depth="450"
)
# Пытаемся создать вторую стойку с тем же именем
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку создания
create_child_frame.click_add_button()
create_child_frame.wait_for_timeout(2000)
# Проверяем наличие alert-окна с сообщением о дублирующемся имени
expected_alert_text = f"Имя {rack_name} уже используется"
create_child_frame.alert.check_alert_presence(expected_alert_text)
# Проверяем, что остались на странице создания (стойка не создана)
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
# Закрываем alert-окно с помощью кнопки закрытия
create_child_frame.wait_for_timeout(2000)
create_child_frame.alert.close_alert_by_text(expected_alert_text)
# 3. Очистка: Удаление созданной стойки
logger.debug(f"Cleaning up: deleting test rack '{rack_name}'...")
# Переходим на страницу стойки для удаления
self.main_page.click_subpanel_item(rack_name, parent="test-zone")
self.main_page.wait_for_timeout(1000)
# Удаляем стойку
self._delete_rack_from_context_menu(browser, rack_name)
# Проверяем, что стойка удалена
self.main_page.wait_for_timeout(2000)
rack_still_exists = self._check_rack_existance(browser, rack_name)
assert not rack_still_exists, f"Rack '{rack_name}' should be deleted"
logger.debug(f"Test rack '{rack_name}' successfully cleaned up")
logger.debug("System prevented creating rack with duplicate name")
logger.debug("Rack deletion completed")
def _perform_required_fields_test(self, create_child_frame, rack_maker, test_data):
"""Выполняет один тест валидации обязательных полей.
@ -310,7 +199,6 @@ class TestCreateRackElement:
rack_maker: Объект для работы со стойкой
test_data: Словарь с данными теста
"""
# Распаковываем данные теста
name_value = test_data["name"]
height_value = test_data["height"]
@ -321,7 +209,8 @@ class TestCreateRackElement:
# Получаем контейнер формы
container_locator = create_child_frame.page.locator(RackLocators.FORM_INPUT_CONTAINER).nth(1)
logger.debug(f"Available fields: {list(create_child_frame.get_input_fields_locators(container_locator).keys())}")
logger.debug(f"Available fields:\
{list(create_child_frame.get_input_fields_locators(container_locator).keys())}")
# Проверяем и очищаем поле "Глубина (мм)" только если оно заполнено
logger.debug("Checking field: Глубина (мм)")
@ -392,16 +281,176 @@ class TestCreateRackElement:
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
logger.debug("Test completed successfully")
#@pytest.mark.develop
def test_required_fields_validation(self, browser: Page) -> None:
def test_create_rack_child_element(self, browser: Page, cleanup_racks) -> None:
"""Тест создания дочернего элемента типа 'Стойка'."""
# Нажимаем кнопку "Создать" на тулбаре
self.location_page.click_create_button()
# Создаем фрейм создания дочернего элемента
create_child_frame = CreateChildElementFrame(browser)
# Нажимаем на плашку "Класс объекта учета"
create_child_frame.open_object_class_combobox()
# Из выпадающего меню выбираем пункт "Стойка"
create_child_frame.select_object_class("Стойка")
# Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser)
# Создаем объект данных стойки
rack_data = RackData(
name="Test-Rack-01",
height="42",
depth="1000",
serial="TEST123456",
inventory="INV-001",
comment="Тестовая стойка для автоматизации",
state="Введен в эксплуатацию",
cable_entry="сверху"
)
# Сохраняем имя стойки в переменную
rack_name = rack_data.name
cleanup_racks.append(rack_name)
# Заполняем данные стойки
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку "Добавить"
create_child_frame.click_add_button()
# 1. Проверяем уведомление об успешном создании стойки - требуется создать разработчику (заведена задача)
# Проверяем наличие alert-окна
# create_child_frame.alert.check_alert_presence("")
# Получаем текст alert
# alert_text = create_child_frame.alert.get_text()
# logger.debug(f"Alert text after creation: {alert_text}")
# Проверяем, что в тексте есть указание на успешное создание
# assert "создан" in alert_text.lower() or "успешно" in alert_text.lower()
# assert final_rack_name in alert_text
# Закрываем alert
# create_child_frame.alert.close_alert()
# 2. Проверяем, что стойка создана и отображается
logger.debug(f"Verifying that rack '{rack_name}' was created...")
# Обновляем навигационную панель
self.main_page.click_main_navigation_panel_item("test-zone")
# Проверяем существование стойки в навигационной панели
rack_exists = self._check_rack_existance(browser, rack_name)
assert rack_exists, f"Rack '{rack_name}' should be visible in navigation panel after creation"
logger.debug(f"Rack '{rack_name}' is visible in navigation panel")
logger.debug("Test for creating 'Rack' child element completed successfully")
def test_create_rack_content(self, browser: Page) -> None:
"""Тест проверки содержимого формы создания стойки."""
# Проверяем что кнопка "Создать" доступна
self.location_page.should_be_toolbar_buttons()
# Нажимаем кнопку "Создать" на тулбаре
self.location_page.click_create_button()
# Создаем фрейм создания дочернего элемента
create_child_frame = CreateChildElementFrame(browser)
# Нажимаем на плашку "Класс объекта учета"
create_child_frame.open_object_class_combobox()
# Из выпадающего меню выбираем пункт "Стойка"
create_child_frame.select_object_class("Стойка")
# Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser)
# Проверяем заголовок формы создания
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
# Проверяем что после выбора 'Стойка' появляются специфичные поля
rack_maker.check_rack_fields_presence()
logger.debug("Rack-specific fields are displayed correctly")
create_child_frame.should_be_toolbar_buttons()
def test_create_rack_with_duplicate_name(self, browser: Page, cleanup_racks) -> None:
"""Тест создания стойки с уже существующим именем.
Проверяет, что система корректно обрабатывает попытку создания
стойки с именем, которое уже используется.
"""
Тест проверки обязательных полей при создании стойки.
logger.debug("Starting test for creating rack with duplicate name")
rack_name = "Test-Rack-Duplicate"
# Проверяем, существует ли уже стойка с таким именем
if not self._check_rack_existance(browser, rack_name):
logger.debug(f"Rack with name '{rack_name}' not found. Creating first rack.")
self._create_rack(browser, rack_name)
logger.debug(f"First rack with name '{rack_name}' created successfully")
# Добавляем стойку в список для очистки
cleanup_racks.append(rack_name)
else:
logger.debug(f"Rack with name '{rack_name}' already exists, proceeding to create second one")
# Создаем вторую стойку с тем же именем
logger.debug(f"Attempting to create second rack with name '{rack_name}'")
# Нажимаем кнопку "Создать" на тулбаре
self.location_page.click_create_button()
# Создаем фрейм создания дочернего элемента
create_child_frame = CreateChildElementFrame(browser)
# Нажимаем на плашку "Класс объекта учета"
create_child_frame.open_object_class_combobox()
# Из выпадающего меню выбираем пункт "Стойка"
create_child_frame.select_object_class("Стойка")
# Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser)
# Создаем объект данных для второй стойки
rack_data = RackData(
name=rack_name,
height="42",
depth="450"
)
# Пытаемся создать вторую стойку с тем же именем
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку создания
create_child_frame.click_add_button()
create_child_frame.wait_for_timeout(2000)
# Проверяем наличие alert-окна с сообщением о дублирующемся имени
expected_alert_text = f"Имя {rack_name} уже используется"
create_child_frame.alert.check_alert_presence(expected_alert_text)
# Проверяем, что остались на странице создания (стойка не создана)
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
# Закрываем alert-окно с помощью кнопки закрытия
create_child_frame.wait_for_timeout(2000)
create_child_frame.alert.close_alert_by_text(expected_alert_text)
logger.debug("System prevented creating rack with duplicate name")
def test_required_fields_validation(self, browser: Page, cleanup_racks) -> None:
"""Тест проверки обязательных полей при создании стойки.
Проверяет, что система корректно валидирует обязательные поля:
- Поле 'Высота в юнитах' должно быть заполнено
- Поле 'Глубина (мм)' должно быть заполнено
"""
# Текст сообщения alert-окна
expected_alert_text_height = "поле Высота в юнитах должно быть заполнено"
expected_alert_text_depth = "поле Глубина (мм) должно быть заполнено"
@ -459,15 +508,15 @@ class TestCreateRackElement:
for test_case in test_cases:
logger.debug(test_case["name"])
self._perform_required_fields_test(
create_child_frame, rack_maker, test_case["data"]
)
create_child_frame, rack_maker, test_case["data"])
logger.debug("System prevented creating rack with invalid required fields")
# 4. Тест: Заполняем все обязательные поля
logger.debug("Test 4: All required fields are filled")
# Генерируем уникальное имя для финального теста
final_rack_name = "Test-Rack-Required-Final"
final_rack_name = "Test-Rack-Required-04"
cleanup_racks.append(final_rack_name)
# **ВАЖНО: Очищаем поля перед заполнением**
logger.debug("Clearing fields before filling...")
@ -538,147 +587,20 @@ class TestCreateRackElement:
# Закрываем alert
# create_child_frame.alert.close_alert()
# Переходим на страницу стойки для удаления
self.main_page.click_subpanel_item(final_rack_name, parent="test-zone")
self.main_page.wait_for_timeout(500)
# Удаляем стойку
self._delete_rack_from_context_menu(browser, final_rack_name)
# Проверяем, что стойка удалена
self.main_page.wait_for_timeout(1000)
rack_still_exists = self._check_rack_existance(browser, final_rack_name)
assert not rack_still_exists, f"Rack '{final_rack_name}' should be deleted"
logger.debug("Required fields validation test completed successfully")
#@pytest.mark.develop
def test_delete_created_rack(self, browser: Page) -> None:
"""
Тест удаления созданной стойки.
# Вспомогательные методы проверки
Сценарий:
1. Создаем стойку с уникальным именем
2. Проверяем её существование
3. Переходим к стойке и удаляем её
4. Проверяем, что стойка больше не существует
"""
logger.debug("Starting test for deleting created rack")
# Генерируем уникальное имя для стойки
rack_name = f"Test-Rack-Delete"
logger.debug(f"Test rack name: {rack_name}")
# 1. Создаем стойку
logger.debug("Step 1: Creating rack...")
self._create_rack(browser, rack_name)
logger.debug(f"Rack '{rack_name}' created successfully")
# 2. Проверяем существование стойки
logger.debug("Step 2: Verifying rack existence...")
# Используем существующий метод _check_rack_existance
rack_exists = self._check_rack_existance(browser, rack_name)
assert rack_exists, f"Rack '{rack_name}' not found after creation"
logger.debug(f"Rack '{rack_name}' exists - verified with _check_rack_existance method")
# Кликаем на стойку для перехода
self.main_page.click_subpanel_item(rack_name, parent="test-zone")
# 3. Проверяем, что мы на странице стойки
logger.debug("Step 3: Checking we're on rack page...")
expected_toolbar_subtitles = [
"test-zone",
'chevron_right',
rack_name
]
rack_page = RackPage(browser)
rack_page.should_be_panel_header(expected_toolbar_subtitles)
# 4. Открываем контекстное меню и удаляем стойку
logger.debug("Step 4: Deleting rack...")
self._delete_rack_from_context_menu(browser, rack_name)
# 5. Проверяем, что стойка удалена с использованием существующего метода
logger.debug("Step 5: Verifying rack deletion...")
# Переходим обратно в test-zone для проверки
self.main_page.click_subpanel_item("test-zone")
# Используем существующий метод для проверки отсутствия стойки
rack_still_exists = self._check_rack_existance(browser, rack_name)
assert not rack_still_exists, f"Rack '{rack_name}' still exists after deletion"
logger.debug(f"Rack '{rack_name}' successfully deleted - verified with _check_rack_existance method")
logger.debug("Rack deletion test completed successfully")
def _delete_rack_from_context_menu(self, browser: Page, rack_name: str) -> None:
"""
Удаляет стойку через контекстное меню.
def _check_rack_existance(self, browser: Page, rack_name: str) -> bool:
"""Проверяет существование стойки.
Args:
browser: Страница Playwright
rack_name: Имя стойки для удаления
rack_name: Имя стойки для проверки
Returns:
bool: True если стойка существует, False в противном случае
"""
logger.debug(f"Deleting rack '{rack_name}' from context menu...")
# 1. Находим элемент стойки в навигационной панели
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)
# 2. Проверяем и нажимаем кнопку "Изменить"
logger.debug("Step 1: Clicking 'Edit' button...")
rack_page = RackPage(browser)
# Проверяем видимость кнопки
rack_page.toolbar.check_button_visibility("edit")
# Проверяем тултип кнопки
rack_page.toolbar.check_button_tooltip("edit", "Изменить")
# Кликаем на кнопку "Изменить"
rack_page.toolbar.get_button_by_name("edit").click()
logger.debug("Edit button clicked, waiting for edit form...")
# 3. Используем метод click_remove_button, который обрабатывает весь процесс удаления
# включая диалог подтверждения
logger.debug("Clicking remove button...")
rack_page.click_remove_button()
# 4. Проверяем уведомление об успешном удалении - требуется создать разработчику (заведена задача)
# Создаем экземпляр фрейма для доступа к alert компоненту
# create_child_frame = CreateChildElementFrame(browser)
# Проверяем наличие любого alert-окна (не обязательно точного текста)
# create_child_frame.alert.check_alert_presence("")
# Получаем текст alert, чтобы убедиться что удаление прошло успешно
# alert_text = create_child_frame.alert.get_text()
# logger.debug(f"Alert text after deletion: {alert_text}")
# Проверяем что в тексте есть указание на успешное удаление
# assert "удален" in alert_text.lower() or "успешно" in alert_text.lower()
# Закрываем alert
# create_child_frame.alert.close_alert()
logger.debug("Rack deletion completed")
def _check_rack_existance(self, browser: Page, rack_name: str) -> bool:
"""Проверяет существование стойки."""
logger.debug(f"Checking existence of rack with name '{rack_name}'")
# Обновляем навигационную панель
@ -697,39 +619,3 @@ class TestCreateRackElement:
logger.debug(f"Rack with name '{rack_name}' not found")
return False
def _create_rack(self, browser: Page, rack_name: str) -> None:
"""Создает стойку."""
logger.debug(f"Creating rack with name '{rack_name}'")
# Переходим обратно к созданию новой стойки
#self.main_page.click_main_navigation_panel_item("test-zone")
# Нажимаем кнопку "Создать" на тулбаре
self.location_page.click_create_button()
# Создаем фрейм создания дочернего элемента
create_child_frame = CreateChildElementFrame(browser)
# Нажимаем на плашку "Класс объекта учета"
create_child_frame.open_object_class_combobox()
# Из выпадающего меню выбираем пункт "Стойка"
create_child_frame.select_object_class("Стойка")
# Открывается набор плашек для задания параметров стойки
rack_maker = RackObjectMaker(browser)
# Создаем объект данных стойки
rack_data = RackData(
name=rack_name,
height="42",
depth="1000"
)
# Заполняем данные стойки
rack_maker.fill_rack_data(rack_data)
# Нажимаем кнопку создания
create_child_frame.click_add_button()