720 lines
30 KiB
Python
720 lines
30 KiB
Python
"""Модуль тестов вкладки 'Стойка'.
|
||
|
||
Содержит тесты для проверки функциональности
|
||
работы со стойкой оборудования.
|
||
|
||
"""
|
||
from typing import Optional
|
||
from playwright.sync_api import Page, expect
|
||
from tools.logger import get_logger
|
||
from locators.rack_locators import RackLocators
|
||
from elements.tooltip_button_element import TooltipButton
|
||
from components.toolbar_component import ToolbarComponent
|
||
from pages.base_page import BasePage
|
||
|
||
|
||
logger = get_logger("RACK_PAGE")
|
||
|
||
logger.setLevel("INFO")
|
||
|
||
# Специфичные локаторы оставленые в основном коде
|
||
PANEL_HEADER = "//span[text()='Объекты']/following-sibling::i"
|
||
TOOLBAR_CONTENT = "//div[@class='v-toolbar__content']"
|
||
PANEL_HEADER_ANCESTOR_DIV2 = "xpath=/ancestor::div[2]"
|
||
|
||
|
||
class RackPage(BasePage):
|
||
"""Класс для работы с вкладкой стойки оборудования."""
|
||
|
||
def __init__(self, page: Page) -> None:
|
||
"""
|
||
Инициализирует объект вкладки стойки.
|
||
|
||
Args:
|
||
page (Page): Экземпляр страницы Playwright
|
||
"""
|
||
|
||
super().__init__(page)
|
||
|
||
# Кнопка "Изменить"
|
||
locator_button = self.page.locator(RackLocators.EDIT_BUTTON)
|
||
self.edit_button = TooltipButton(page, locator_button, "edit")
|
||
|
||
# Кнопка "Скрыть стойку"
|
||
hide_button_locator = self.page.locator(RackLocators.HIDE_RACK_BUTTON)
|
||
self.hide_button = TooltipButton(page, hide_button_locator, "hide_rack")
|
||
|
||
# Кнопка "Показать стойку"
|
||
show_button_locator = self.page.locator(RackLocators.SHOW_RACK_BUTTON)
|
||
self.show_button = TooltipButton(page, show_button_locator, "show_rack")
|
||
|
||
# Кнопка "Переместить"
|
||
replace_button_locator = self.page.locator(RackLocators.TOOLBAR_REPLACE_BUTTON)
|
||
self.replace_button = TooltipButton(page, replace_button_locator, "replace")
|
||
|
||
# Кнопка "Сохранить"
|
||
done_button_locator = self.page.locator(RackLocators.TOOLBAR_DONE_BUTTON)
|
||
self.done_button = TooltipButton(page, done_button_locator, "done")
|
||
|
||
# Кнопка "Отменить"
|
||
close_button_locator = self.page.locator(RackLocators.TOOLBAR_CLOSE_BUTTON)
|
||
self.close_button = TooltipButton(page, close_button_locator, "close")
|
||
|
||
# Кнопка "Удалить"
|
||
remove_button_locator = self.page.locator(RackLocators.TOOLBAR_REMOVE_BUTTON)
|
||
self.remove_button = TooltipButton(page, remove_button_locator, "remove")
|
||
|
||
self.toolbar = ToolbarComponent(page, "")
|
||
self.toolbar.add_tooltip_button(locator_button, "edit")
|
||
self.toolbar.add_tooltip_button(hide_button_locator, "hide_rack")
|
||
self.toolbar.add_tooltip_button(show_button_locator, "show_rack")
|
||
self.toolbar.add_tooltip_button(replace_button_locator, "replace")
|
||
self.toolbar.add_tooltip_button(done_button_locator, "done")
|
||
self.toolbar.add_tooltip_button(close_button_locator, "close")
|
||
self.toolbar.add_tooltip_button(remove_button_locator, "remove")
|
||
|
||
# Действия
|
||
|
||
def click_remove_button(self) -> None:
|
||
"""
|
||
Кликает на кнопку 'Удалить' и обрабатывает диалог подтверждения.
|
||
"""
|
||
logger.debug("Clicking on 'Remove' button...")
|
||
|
||
# Проверяем видимость кнопки
|
||
self.toolbar.check_button_visibility("remove")
|
||
|
||
# Проверяем тултип кнопки (может быть "Удалить" или "Remove")
|
||
try:
|
||
self.toolbar.check_button_tooltip("remove", "Удалить")
|
||
except AssertionError:
|
||
try:
|
||
self.toolbar.check_button_tooltip("remove", "Remove")
|
||
except AssertionError:
|
||
logger.debug("Could not verify tooltip text for remove button")
|
||
|
||
# Кликаем на кнопку удаления
|
||
self.toolbar.get_button_by_name("remove").click()
|
||
self.wait_for_timeout(1000)
|
||
|
||
# Ожидаем появления диалога подтверждения
|
||
self._handle_remove_confirmation_dialog()
|
||
|
||
def confirm_remove_dialog(self, confirm: bool = True) -> None:
|
||
"""
|
||
Подтверждает или отклоняет удаление в диалоговом окне.
|
||
|
||
Args:
|
||
confirm (bool): Если True - подтвердить удаление, если False - отменить
|
||
"""
|
||
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]:
|
||
"""
|
||
Возвращает список доступных вкладок.
|
||
|
||
Returns:
|
||
list[str]: Список названий доступных вкладок
|
||
"""
|
||
|
||
tabs = []
|
||
|
||
# Используем локатор для верхних вкладок
|
||
tab_elements = self.page.locator(RackLocators.ALL_TABS)
|
||
|
||
# Ждем появления элементов
|
||
tab_elements.first.wait_for(state="visible", timeout=5000)
|
||
|
||
total_count = tab_elements.count()
|
||
logger.debug("Total top tab elements found: %d", total_count)
|
||
|
||
for i in range(total_count):
|
||
element = tab_elements.nth(i)
|
||
|
||
# Проверяем видимость и доступность элемента
|
||
if element.is_visible() and element.is_enabled():
|
||
tab_text = element.text_content()
|
||
if tab_text:
|
||
tab_text = tab_text.strip()
|
||
if tab_text and tab_text not in tabs:
|
||
tabs.append(tab_text)
|
||
logger.debug("Top tab found: '%s'", tab_text)
|
||
|
||
logger.debug("Available top tabs found: %s", tabs)
|
||
return tabs
|
||
|
||
def get_current_active_side(self) -> Optional[str]:
|
||
"""
|
||
Возвращает текущую активную сторону стойки.
|
||
|
||
Returns:
|
||
Optional[str]: "Лицевая сторона", "Обратная сторона" или None если ни одна не активна
|
||
"""
|
||
|
||
# Проверяем конкретно кнопку "Лицевая сторона"
|
||
front_btn = self.page.locator(RackLocators.FRONT_SIDE_BUTTON)
|
||
if front_btn.count() > 0:
|
||
classes = front_btn.first.get_attribute("class") or ""
|
||
if "primary--text" in classes.split():
|
||
return "Лицевая сторона"
|
||
|
||
# Проверяем конкретно кнопку "Обратная сторона"
|
||
back_btn = self.page.locator(RackLocators.BACK_SIDE_BUTTON)
|
||
if back_btn.count() > 0:
|
||
classes = back_btn.first.get_attribute("class") or ""
|
||
if "primary--text" in classes.split():
|
||
return "Обратная сторона"
|
||
|
||
return None
|
||
|
||
def get_toolbar_title(self) -> list[str]:
|
||
"""
|
||
Получает заголовок панели инструментов.
|
||
|
||
Returns:
|
||
list[str]: Список элементов заголовка панели инструментов
|
||
"""
|
||
|
||
toolbar_title_locator = self.page.locator(PANEL_HEADER).\
|
||
locator(PANEL_HEADER_ANCESTOR_DIV2).\
|
||
get_by_role("navigation").\
|
||
locator(TOOLBAR_CONTENT)
|
||
|
||
return self.toolbar.get_toolbar_composite_title_text(toolbar_title_locator)
|
||
|
||
def switch_to_composition_tab(self) -> None:
|
||
"""Переключается на вкладку 'Состав'."""
|
||
|
||
self.switch_to_tab("Состав")
|
||
|
||
def switch_to_events_tab(self) -> None:
|
||
"""Переключается на вкладку 'События'."""
|
||
|
||
self.switch_to_tab("События")
|
||
|
||
def switch_to_general_info_tab(self) -> None:
|
||
"""Переключается на вкладку 'Общая информация'."""
|
||
|
||
self.switch_to_tab("Общая информация")
|
||
|
||
def switch_to_maintenance_tab(self) -> None:
|
||
"""Переключается на вкладку 'Обслуживание'."""
|
||
|
||
self.switch_to_tab("Обслуживание")
|
||
|
||
def switch_to_services_tab(self) -> None:
|
||
"""Переключается на вкладку 'Сервисы'."""
|
||
|
||
self.switch_to_tab("Сервисы")
|
||
|
||
def switch_to_tab(self, tab_name: str) -> None:
|
||
"""
|
||
Переключается на указанную вкладку.
|
||
|
||
Args:
|
||
tab_name (str): Название вкладки для переключения
|
||
|
||
Raises:
|
||
AssertionError: Если вкладка не найдена или недоступна
|
||
"""
|
||
|
||
logger.debug("Switching to tab '%s'...", tab_name)
|
||
|
||
tab = self.page.locator(RackLocators.TAB_BY_NAME.format(tab_name))
|
||
|
||
assert tab.count() > 0, f"Tab '{tab_name}' not found"
|
||
|
||
# Проверяем активность ДО клика
|
||
if self.is_tab_active(tab_name):
|
||
logger.debug("Tab '%s' is already active", tab_name)
|
||
return
|
||
|
||
# Находим первую видимую вкладку с нужным именем
|
||
target_tab = None
|
||
for i in range(tab.count()):
|
||
element = tab.nth(i)
|
||
if element.is_visible() and element.is_enabled():
|
||
target_tab = element
|
||
break
|
||
|
||
assert target_tab is not None, f"No visible/available tab '{tab_name}' found"
|
||
|
||
# Кликаем на вкладку
|
||
logger.debug("Clicking on tab '%s'...", tab_name)
|
||
target_tab.click()
|
||
|
||
# Ждем изменения активной вкладки
|
||
self._wait_for_tab_activation(tab_name)
|
||
|
||
# Ждем загрузки контента
|
||
self.wait_for_timeout(500)
|
||
|
||
def wait_for_rack_loading(self) -> None:
|
||
"""Ожидает загрузки интерфейса стойки."""
|
||
|
||
logger.debug("Waiting for rack interface to load...")
|
||
|
||
# Проверяем наличие кнопок переключения сторон
|
||
front_button = self.page.locator(RackLocators.FRONT_SIDE_BUTTON)
|
||
back_button = self.page.locator(RackLocators.BACK_SIDE_BUTTON)
|
||
|
||
expect(front_button).to_be_visible(timeout=5000)
|
||
expect(back_button).to_be_visible(timeout=5000)
|
||
logger.debug("Side toggle buttons loaded")
|
||
|
||
# Проверяем, что есть активная кнопка
|
||
active_button = self.page.locator(RackLocators.ACTIVE_SIDE_BUTTON)
|
||
if active_button.count() > 0:
|
||
logger.debug("Active side button found")
|
||
else:
|
||
logger.warning("No active side button found")
|
||
|
||
# Проверяем наличие основного контейнера
|
||
main_container = self.page.locator(RackLocators.MAIN_CONTAINER)
|
||
if main_container.count() == 0:
|
||
logger.warning("Main rack container not found")
|
||
else:
|
||
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("Unit positions found: %d", unit_positions.count())
|
||
if unit_positions.first.text_content():
|
||
content = unit_positions.first.text_content().strip()
|
||
logger.debug("First position: %s", content)
|
||
|
||
# Проверяем наличие кнопок добавления
|
||
open_buttons = self.page.locator(RackLocators.ADD_CIRCLE_BUTTON)
|
||
if open_buttons.count() > 0:
|
||
logger.debug("'add_circle' buttons found: %d", open_buttons.count())
|
||
|
||
logger.debug("Rack interface loaded")
|
||
|
||
# Проверки
|
||
|
||
def check_physical_devices_presence(self) -> None:
|
||
"""Проверяет наличие физических устройств на стойке."""
|
||
|
||
# Поиск устройств по классу parent-class
|
||
devices = self.page.locator(RackLocators.DEVICE_ELEMENTS)
|
||
device_count = devices.count()
|
||
|
||
if device_count > 0:
|
||
# Выводим информацию только о первом устройстве
|
||
first_device = devices.first
|
||
device_id = first_device.get_attribute("id") or "No id"
|
||
device_title = first_device.get_attribute("title") or "No title"
|
||
|
||
logger.debug(
|
||
"Devices found: %d (first: ID=%s, Title=%s)",
|
||
device_count, device_id, device_title
|
||
)
|
||
else:
|
||
logger.debug("No devices detected")
|
||
|
||
def check_tab_switching(self) -> None:
|
||
"""
|
||
Проверяет переключение между вкладками стойки.
|
||
|
||
Raises:
|
||
AssertionError: Если не удалось переключиться на все вкладки
|
||
"""
|
||
|
||
logger.debug("Testing rack tab switching functionality...")
|
||
|
||
# Вкладки в правильном порядке
|
||
defined_tabs = [
|
||
"Состав",
|
||
"Общая информация",
|
||
"Обслуживание",
|
||
"События",
|
||
"Сервисы"
|
||
]
|
||
|
||
logger.debug("Defined tabs to test: %s", defined_tabs)
|
||
|
||
successful_switches = 0
|
||
failed_switches = []
|
||
|
||
# Тестируем переключение на каждую определенную вкладку
|
||
for tab_name in defined_tabs:
|
||
logger.debug("Testing switch to tab '%s'...", tab_name)
|
||
|
||
try:
|
||
# Переключаемся на вкладку
|
||
self.switch_to_tab(tab_name)
|
||
|
||
# Проверяем, что вкладка активна
|
||
if self.is_tab_active(tab_name):
|
||
logger.debug("Successfully switched to tab '%s'", tab_name)
|
||
successful_switches += 1
|
||
else:
|
||
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("Error switching to tab '%s': %s", tab_name, e)
|
||
failed_switches.append(f"Tab '{tab_name}' error: {str(e)}")
|
||
|
||
# Небольшая пауза между переключениями
|
||
self.wait_for_timeout(1000)
|
||
|
||
# Формируем итоговый отчет
|
||
logger.debug("=== TAB SWITCHING RESULTS ===")
|
||
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(" - %s", failure)
|
||
|
||
# Требуем успешного переключения на все определенные вкладки
|
||
assert successful_switches == len(defined_tabs), (
|
||
f"Tab switching test failed. "
|
||
f"Only {successful_switches} out of {len(defined_tabs)} defined tabs "
|
||
f"were successfully switched. "
|
||
f"Errors: {', '.join(failed_switches)}"
|
||
)
|
||
|
||
logger.debug("All %d defined tabs successfully switched!", successful_switches)
|
||
|
||
def is_tab_active(self, tab_name: str) -> bool:
|
||
"""
|
||
Проверяет, активна ли указанная вкладка.
|
||
|
||
Args:
|
||
tab_name (str): Название вкладки для проверки
|
||
|
||
Returns:
|
||
bool: True если вкладка активна, False в противном случае
|
||
"""
|
||
|
||
# Проверяем по активному классу и тексту
|
||
active_tab = self.page.locator(RackLocators.ACTIVE_TAB)
|
||
|
||
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("Tab '%s' is active (via active tab class)", tab_name)
|
||
return True
|
||
|
||
logger.debug("Tab '%s' is not active", tab_name)
|
||
return False
|
||
|
||
def should_be_panel_header(self, expected_toolbar_title_items: list[str]) -> None:
|
||
"""
|
||
Проверяет наличие и корректность заголовка панели.
|
||
|
||
Args:
|
||
expected_toolbar_title_items (list[str]): Ожидаемые элементы заголовка
|
||
|
||
Raises:
|
||
AssertionError: Если заголовок панели не соответствует ожиданиям
|
||
"""
|
||
|
||
panel_header_locator = self.page.locator(PANEL_HEADER)
|
||
expect(panel_header_locator).to_be_visible(), "Panel header 'Объекты'"
|
||
|
||
if panel_header_locator.inner_text() != 'chevron_right':
|
||
assert False, "No separator 'chevron_right' after header 'Объекты'"
|
||
|
||
actual_toolbar_title_items = self.get_toolbar_title()
|
||
|
||
self.check_lists_equals(
|
||
actual_toolbar_title_items,
|
||
expected_toolbar_title_items,
|
||
f"Miscomparison actual {actual_toolbar_title_items} "
|
||
f"and expected {expected_toolbar_title_items}"
|
||
)
|
||
|
||
def should_be_rack_sides_displayed(self) -> None:
|
||
"""
|
||
Проверка отображения и структуры сторон стойки.
|
||
|
||
Raises:
|
||
AssertionError: Если стороны стойки не отображаются корректно
|
||
"""
|
||
|
||
logger.debug("Checking rack sides display and structure...")
|
||
|
||
# Ожидаем загрузки
|
||
self.wait_for_rack_loading()
|
||
|
||
# БАЗОВАЯ ПРОВЕРКА: наличие кнопок переключения сторон
|
||
|
||
front_side_button = self.page.locator(RackLocators.FRONT_SIDE_BUTTON)
|
||
back_side_button = self.page.locator(RackLocators.BACK_SIDE_BUTTON)
|
||
|
||
# Проверяем наличие кнопок
|
||
expect(front_side_button).to_be_visible(timeout=5000), \
|
||
"Front side button not found"
|
||
expect(back_side_button).to_be_visible(timeout=5000), \
|
||
"Back side button not found"
|
||
|
||
logger.debug("Side toggle buttons found")
|
||
|
||
# Проверяем, какая сторона активна по умолчанию
|
||
current_active = self.get_current_active_side()
|
||
logger.debug("Current active side: %s", current_active)
|
||
|
||
# Дополнительная проверка устройств
|
||
self.check_physical_devices_presence()
|
||
|
||
# ПРОВЕРКА ЛИЦЕВОЙ СТОРОНЫ
|
||
self._check_side_details("Лицевая сторона", front_side_button)
|
||
|
||
# ПРОВЕРКА ОБРАТНОЙ СТОРОНЫ
|
||
self._check_side_details("Обратная сторона", back_side_button)
|
||
|
||
# Возвращаемся на исходную активную сторону
|
||
if current_active:
|
||
logger.debug("Returning to original active side: %s", current_active)
|
||
if current_active == "Лицевая сторона":
|
||
front_side_button.click()
|
||
else:
|
||
back_side_button.click()
|
||
self.wait_for_timeout(1000)
|
||
|
||
final_active = self.get_current_active_side()
|
||
logger.debug("Final active side: %s", final_active)
|
||
|
||
logger.debug("All rack sides checks passed successfully")
|
||
|
||
def should_be_toolbar_buttons(self) -> None:
|
||
"""
|
||
Проверяет наличие и функциональность кнопок тулбара.
|
||
|
||
Raises:
|
||
AssertionError: Если кнопки недоступны или подсказки неверны
|
||
"""
|
||
|
||
logger.debug("Checking toolbar buttons...")
|
||
|
||
# Проверяем основные кнопки
|
||
self.toolbar.check_button_visibility("edit")
|
||
self.toolbar.check_button_tooltip("edit", "Изменить")
|
||
|
||
# Кликаем на кнопку "Изменить" для проверки функциональности
|
||
self.toolbar.get_button_by_name("edit").click()
|
||
|
||
# Проверяем новые кнопки тулбара
|
||
self.toolbar.check_button_visibility("replace")
|
||
self.toolbar.check_button_tooltip("replace", "Переместить")
|
||
|
||
self.toolbar.check_button_visibility("done")
|
||
self.toolbar.check_button_tooltip("done", "Сохранить")
|
||
|
||
self.toolbar.check_button_visibility("close")
|
||
self.toolbar.check_button_tooltip("close", "Отменить")
|
||
|
||
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...")
|
||
|
||
# Проверяем видимость кнопки
|
||
self.toolbar.check_button_visibility("hide_rack")
|
||
self.toolbar.check_button_tooltip("hide_rack", "Скрыть стойку")
|
||
|
||
# Получаем общий контейнер стойки до клика
|
||
rack_container = self.page.locator(RackLocators.RACK_CONTAINER)
|
||
|
||
# Проверяем, что контейнер существует
|
||
expect(rack_container).to_be_visible(timeout=5000)
|
||
|
||
# Кликаем на кнопку "Скрыть стойку"
|
||
self.toolbar.get_button_by_name("hide_rack").click()
|
||
self.wait_for_timeout(2000)
|
||
|
||
# Проверяем, что общий контейнер стойки теперь скрыт (имеет display: none)
|
||
expect(rack_container).to_have_css("display", "none", timeout=5000)
|
||
logger.debug("Rack container successfully hidden (display: none)")
|
||
|
||
logger.debug("'Hide rack' button test completed successfully")
|
||
|
||
def should_have_show_rack_button(self) -> None:
|
||
"""
|
||
Проверка кнопки "Показать стойку".
|
||
|
||
Raises:
|
||
AssertionError: Если кнопка не отображается или не работает
|
||
"""
|
||
logger.debug("Checking 'Show rack' button...")
|
||
|
||
# Проверяем видимость кнопки
|
||
self.toolbar.check_button_visibility("show_rack")
|
||
self.toolbar.check_button_tooltip("show_rack", "Показать стойку")
|
||
|
||
# Получаем общий контейнер стойки
|
||
rack_container = self.page.locator(RackLocators.RACK_CONTAINER)
|
||
|
||
# Проверяем, что контейнер существует
|
||
expect(rack_container).to_be_attached(timeout=5000)
|
||
|
||
# Кликаем на кнопку "Показать стойку"
|
||
self.toolbar.get_button_by_name("show_rack").click()
|
||
self.wait_for_timeout(2000) # Даем время для применения стилей
|
||
|
||
# Проверяем, что общий контейнер стойки теперь видим (display не равен "none")
|
||
expect(rack_container).not_to_have_css("display", "none", timeout=5000)
|
||
logger.debug("Rack container successfully shown (display is not 'none')")
|
||
|
||
logger.debug("'Show rack' button test completed successfully")
|
||
|
||
# Вспомогательные методы
|
||
|
||
def _check_side_details(self, side_name: str, side_button) -> None:
|
||
"""
|
||
Проверка структуры конкретной стороны стойки.
|
||
|
||
Args:
|
||
side_name (str): Название стороны для логов
|
||
side_button: Локатор кнопки стороны
|
||
|
||
Raises:
|
||
AssertionError: Если структура стороны некорректна
|
||
"""
|
||
|
||
logger.debug("Checking %s...", side_name)
|
||
|
||
# Логируем текущее состояние кнопки перед кликом
|
||
button_classes = side_button.get_attribute("class") or ""
|
||
logger.debug("Button classes before click: %s", button_classes)
|
||
|
||
# Проверяем, активна ли уже эта сторона
|
||
current_active = self.get_current_active_side()
|
||
logger.debug("Current active side (before click): '%s'", current_active)
|
||
|
||
if current_active == side_name:
|
||
logger.debug("%s is already active", side_name)
|
||
else:
|
||
# Если не активна, кликаем для переключения
|
||
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("Button classes after click: %s", button_classes_after)
|
||
|
||
# Проверяем, что нужная сторона стала активной
|
||
active_side = self.get_current_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("%s successfully activated", side_name)
|
||
|
||
# Проверяем позиции юнитов
|
||
unit_positions = self.page.locator(RackLocators.UNIT_POSITIONS)
|
||
total_positions = unit_positions.count()
|
||
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("Units on %s: %d", side_name, units_per_side)
|
||
|
||
# Проверяем устройства
|
||
devices = self.page.locator(RackLocators.DEVICE_ELEMENTS)
|
||
device_count = devices.count()
|
||
|
||
if device_count > 0:
|
||
# Выводим информацию только о первом устройстве
|
||
first_device = devices.first
|
||
device_id = first_device.get_attribute("id") or "No id"
|
||
device_title = first_device.get_attribute("title") or "No title"
|
||
device_classes = first_device.get_attribute("class") or "No classes"
|
||
|
||
# Ищем слоты внутри устройства
|
||
slots = first_device.locator(RackLocators.DEVICE_SLOTS)
|
||
slot_count = slots.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("%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 (str): Название вкладки для ожидания
|
||
timeout (int, optional): Время ожидания в миллисекундах, по умолчанию 5000
|
||
|
||
Raises:
|
||
AssertionError: Если вкладка не активирована в течение таймаута
|
||
"""
|
||
|
||
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("Tab '%s' successfully activated", tab_name)
|
||
return
|
||
self.wait_for_timeout(100)
|
||
|
||
assert False, f"Tab '{tab_name}' not activated within {timeout}ms"
|