Исправлена ошибка открытия подпанели панели навигации с большим уровнем вложенности

sidebar_filter
nsubbot 2025-10-28 09:45:51 +03:00
parent 8380bb38d3
commit 632cf4ee40
2 changed files with 79 additions and 26 deletions

View File

@ -54,23 +54,33 @@ class NavigationPanelComponent(BaseComponent):
item_name: Текст элемента для клика. item_name: Текст элемента для клика.
""" """
def find_and_click_item(page, root_locator, item_name: str, parent: None|str) -> bool: def find_and_click_item(page, root_locator, item_name: str, parent: None|str) -> Locator|None:
# Находим все локаторы корневых узлов на текущем уровне # Находим все локаторы корневых узлов на текущем уровне
root_node = root_locator.locator('>div.v-treeview-node') #root_node = root_locator.locator('>div.v-treeview-node')
# Получаем список текстов nodes_count = root_locator.locator('>div.v-treeview-node').count()
root_node_texts = root_node.all_inner_texts()
# Если искомый элемент находится на данном уровне, вычисляем локатор и делаем клик # Если искомый элемент находится на данном уровне, вычисляем локатор и делаем клик
if parent is None: if parent is None:
for index, node_text in enumerate(root_node_texts): for index in range(nodes_count):
node_text = node_text.replace("expand_more\n", "") node = root_locator.locator(f">div:nth-child({index + 1})").first
node_content = node.locator('div.v-treeview-node__content')
if node_content.count() > 0:
node_text = node_content.first.inner_text().strip()
if item_name == node_text: if item_name == node_text:
root_node.nth(index).click() node_attr = node.get_attribute('class')
return True if "v-treeview-node--leaf" not in node_attr:
toggle_button = node.\
locator(NavigationPanelLocators.NODE_ROOT). \
locator(NavigationPanelLocators.TOGGLE_BUTTON).first
toogle_class_attr = toggle_button.get_attribute('class')
if "v-treeview-node__toggle--open" not in toogle_class_attr:
toggle_button.click()
else:
node.locator(NavigationPanelLocators.NODE_ROOT).click()
page.wait_for_timeout(1000)
return node
# Если элемента нет, рекурсивно ищем дальше # Если элемента нет, рекурсивно ищем дальше
nodes_count = root_locator.locator('>div.v-treeview-node').count()
for index in range(nodes_count): for index in range(nodes_count):
node = root_locator.locator(f">div:nth-child({index + 1})").first node = root_locator.locator(f">div:nth-child({index + 1})").first
@ -83,16 +93,20 @@ class NavigationPanelComponent(BaseComponent):
# Проверяем лист это или начало поддерева # Проверяем лист это или начало поддерева
if "v-treeview-node--leaf" not in node_class_attr: if "v-treeview-node--leaf" not in node_class_attr:
# Проверяем, является ли узел раскрытым # Проверяем, является ли узел раскрытым
class_attr = node.locator(NavigationPanelLocators.TOGGLE_BUTTON).get_attribute('class') class_attr = node.\
locator(NavigationPanelLocators.NODE_ROOT). \
locator(NavigationPanelLocators.TOGGLE_BUTTON).first.get_attribute('class')
if "v-treeview-node__toggle--open" in class_attr: if "v-treeview-node__toggle--open" in class_attr:
is_expanded = True is_expanded = True
# Если узел закрыт можем его раскрыть # Если узел закрыт можем его раскрыть
if is_expanded is False: if is_expanded is False:
toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON) toggle_button = node.\
locator(NavigationPanelLocators.NODE_ROOT). \
locator(NavigationPanelLocators.TOGGLE_BUTTON).first
toggle_button.click() toggle_button.click()
# Ждем, пока дочерние элементы прогрузятся/появятся # Ждем, пока дочерние элементы прогрузятся/появятся
page.wait_for_timeout(300) page.wait_for_timeout(1000)
is_expanded = True is_expanded = True
# Проверяем, имеет ли узел дочерние элементы # Проверяем, имеет ли узел дочерние элементы
@ -105,25 +119,32 @@ class NavigationPanelComponent(BaseComponent):
# Ищем дочерние элементы *внутри* текущего узла # Ищем дочерние элементы *внутри* текущего узла
if has_children and is_expanded: if has_children and is_expanded:
child_nodes_locator = root_locator.locator(f">div:nth-child({index + 1})").locator('>div.v-treeview-node__children') child_nodes_locator = root_locator.locator(f">div:nth-child({index + 1})").locator('>div.v-treeview-node__children')
is_found = find_and_click_item(page, child_nodes_locator, item_name, parent=None) found_loc = find_and_click_item(page, child_nodes_locator, item_name, parent=None)
if is_found: if found_loc:
if parent is None: if parent is None:
return True return found_loc
else: else:
root_texts = root_locator.locator(f">div:nth-child({index + 1})").inner_text().splitlines() root_texts = root_locator.locator(f">div:nth-child({index + 1})").inner_text().splitlines()
if parent in root_texts: if parent in root_texts:
return True return found_loc
# закрываем узел, если в нем ничего не нашли # закрываем узел, если в нем ничего не нашли
if is_expanded: if is_expanded:
toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON) toggle_button = node.\
locator(NavigationPanelLocators.NODE_ROOT). \
locator(NavigationPanelLocators.TOGGLE_BUTTON).first
toggle_button.click() toggle_button.click()
page.wait_for_timeout(1000)
# элемент с заданным именем не найден # элемент с заданным именем не найден
return False return None
root_locator = self.get_locator(node_root_locator) root_locator = self.get_locator(node_root_locator)
found = find_and_click_item(self.page, root_locator, item_name, parent) if parent:
parent_loc = find_and_click_item(self.page, root_locator, parent, parent=None)
found = find_and_click_item(self.page, parent_loc.locator('>div.v-treeview-node__children'), item_name, parent=None)
else:
found = find_and_click_item(self.page, root_locator, item_name, parent=None)
assert found, f"Navigation panel item {item_name} is missing" assert found, f"Navigation panel item {item_name} is missing"
def traverse_panel_tree(self, node_root_locator: str | Locator, level=0, debug=False): def traverse_panel_tree(self, node_root_locator: str | Locator, level=0, debug=False):

View File

@ -4,7 +4,7 @@
панели навигации в приложении. панели навигации в приложении.
""" """
# import pytest import pytest
from playwright.sync_api import Page from playwright.sync_api import Page
from pages.main_page import MainPage from pages.main_page import MainPage
from pages.login_page import LoginPage from pages.login_page import LoginPage
@ -52,6 +52,7 @@ class TestNavigationPanel:
mp.expand_navigation_subpanel() mp.expand_navigation_subpanel()
@pytest.mark.develop
def test_sub_panel_item_click(self, browser: Page): def test_sub_panel_item_click(self, browser: Page):
"""Проверяет возможность клика заданного элемента в подпанели навигации. """Проверяет возможность клика заданного элемента в подпанели навигации.
@ -76,17 +77,48 @@ class TestNavigationPanel:
mp.click_subpanel_item("Обслуживание и диагностика") mp.click_subpanel_item("Обслуживание и диагностика")
mp.click_subpanel_item("Статус обслуживания") mp.click_subpanel_item("Статус обслуживания")
mp.wait_for_timeout(500) mp.wait_for_timeout(2000)
mp.click_subpanel_item("Сеансы")
mp.click_subpanel_item("Настройки", parent="Сеансы")
# Открываем/закрываем пункт панели # Открываем/закрываем пункт панели
mp.click_subpanel_item("Пользователи") mp.click_subpanel_item("Пользователи")
mp.click_subpanel_item("Пользователи") mp.click_subpanel_item("Пользователи")
mp.wait_for_timeout(500) mp.wait_for_timeout(2000)
# Открываем пункты панели с одинаковыми имнами, но разным расположением # Открываем пункты панели с одинаковыми имнами, но разным расположением
mp.click_subpanel_item("Шаблоны") mp.click_subpanel_item("Шаблоны")
mp.wait_for_timeout(500) mp.wait_for_timeout(2000)
mp.click_subpanel_item("Zero Touch Provisioning") mp.click_subpanel_item("Zero Touch Provisioning")
mp.click_subpanel_item("Шаблоны", parent="Zero Touch Provisioning") mp.click_subpanel_item("Шаблоны", parent="Zero Touch Provisioning")
mp.wait_for_timeout(500) mp.wait_for_timeout(2000)
# Переходим к Объектам
mp.click_main_navigation_panel_item("Объекты")
mp.wait_for_timeout(5000)
mp.click_subpanel_item("Физические устройства с опросом")
mp.wait_for_timeout(3000)
# Переходим Здание ЦОД 4
mp.click_subpanel_item("Здание ЦОД 4")
mp.wait_for_timeout(3000)
# Переходим к Стойка КСПД с указанием родителя
mp.click_subpanel_item("Стойка КСПД", parent="Здание ЦОД 4")
mp.wait_for_timeout(5000)
# Переходим к Объектам
mp.click_main_navigation_panel_item("Объекты")
mp.click_main_navigation_panel_item("Объекты") # баг
mp.wait_for_timeout(5000)
mp.click_subpanel_item("Виртуальные устройства")
mp.wait_for_timeout(3000)
# Переходим к Стойка систем питания с указанием родителя
mp.click_subpanel_item("Стойка систем питания", parent="Виртуальные устройства")
mp.wait_for_timeout(5000)