Изменено: в методе click_sub_item, убрана проверка 'Если не нашли среди непосредственных детей, ищем рекурсивно

Radislav 2025-10-22 19:58:40 +03:00
parent ccbd7a6727
commit 8a9228e75e
1 changed files with 105 additions and 60 deletions

View File

@ -47,79 +47,124 @@ class NavigationPanelComponent(BaseComponent):
loc.get_by_text(item_name).click() loc.get_by_text(item_name).click()
def click_sub_item(self, node_root_locator: str | Locator, item_name: str, parent: None|str) -> None: def click_sub_item(self, node_root_locator: str | Locator, item_name: str, parent: None|str) -> None:
"""Кликает по вложенному элементу с указанным текстом. """Кликает по вложенному элементу с указанным текстом."""
Args:
node_root_locator: Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath).
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) -> bool:
# Находим все локаторы корневых узлов на текущем уровне """Рекурсивно ищет элемент в дереве и кликает по нему."""
root_node = root_locator.locator('>div.v-treeview-node')
# Получаем список текстов
root_node_texts = root_node.all_inner_texts()
# Если искомый элемент находится на данном уровне, вычисляем локатор и делаем клик # Если указан родитель, сначала находим его
if parent is None: if parent:
for index, node_text in enumerate(root_node_texts): # Ищем родительский элемент
node_text = node_text.replace("expand_more\n", "") parent_found = False
if item_name == node_text:
root_node.nth(index).click()
return True
# Если элемента нет, рекурсивно ищем дальше
nodes_count = root_locator.locator('>div.v-treeview-node').count() 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
# Извлекаем аттрибуты из корневого узла # Получаем текст контента для точного сравнения
node_class_attr = node.get_attribute('class') content_locator = node.locator('div.v-treeview-node__content')
if content_locator.count() > 0:
content_text = content_locator.first.inner_text().strip()
is_expanded = False # Ищем родителя в тексте контента
has_children = False if parent == content_text:
parent_found = True
# Проверяем лист это или начало поддерева # Раскрываем родительский элемент если нужно
if "v-treeview-node--leaf" not in node_class_attr: toggle_buttons = node.locator(NavigationPanelLocators.TOGGLE_BUTTON)
# Проверяем, является ли узел раскрытым if toggle_buttons.count() > 0:
class_attr = node.locator(NavigationPanelLocators.TOGGLE_BUTTON).get_attribute('class') class_attr = toggle_buttons.first.get_attribute('class')
if "v-treeview-node__toggle--open" in class_attr: is_expanded = class_attr and "v-treeview-node__toggle--open" in class_attr
is_expanded = True
# Если узел закрыт можем его раскрыть if not is_expanded:
if is_expanded is False: toggle_buttons.first.click()
toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON) page.wait_for_timeout(1000)
toggle_button.click()
# Ждем, пока дочерние элементы прогрузятся/появятся # После раскрытия ждем появления дочерних элементов
page.wait_for_timeout(300) page.wait_for_timeout(500)
is_expanded = True
# Ищем целевой элемент как непосредственного ребенка родителя
children_locator = node.locator('>div.v-treeview-node__children')
if children_locator.count() > 0:
# Ищем среди непосредственных детей
direct_children = children_locator.locator('>div.v-treeview-node')
direct_children_count = direct_children.count()
for child_index in range(direct_children_count):
child_node = direct_children.nth(child_index)
child_content = child_node.locator('div.v-treeview-node__content')
if child_content.count() > 0:
child_text = child_content.first.inner_text().strip()
if child_text == item_name:
child_content.first.click()
return True
# Если не нашли среди непосредственных детей, ищем рекурсивно
for child_index in range(direct_children_count):
child_node = direct_children.nth(child_index)
found = find_and_click_item(page, children_locator, item_name, parent=None)
if found:
return True
break
if not parent_found:
# Рекурсивный поиск родителя в дочерних элементах
for index in range(nodes_count):
node = root_locator.locator(f">div:nth-child({index + 1})").first
# Проверяем, имеет ли узел дочерние элементы # Проверяем, имеет ли узел дочерние элементы
children_count = node.locator('>div.v-treeview-node__children').count() toggle_buttons = node.locator(NavigationPanelLocators.TOGGLE_BUTTON)
content = node.locator('>div.v-treeview-node__children').inner_html() if toggle_buttons.count() > 0:
if children_count > 0 and len(content) != 0: class_attr = toggle_buttons.first.get_attribute('class')
has_children = True is_expanded = class_attr and "v-treeview-node__toggle--open" in class_attr
# Рекурсивный вызов для дочерних элементов if not is_expanded:
# Ищем дочерние элементы *внутри* текущего узла toggle_buttons.first.click()
if has_children and is_expanded: page.wait_for_timeout(500)
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) children_locator = node.locator('>div.v-treeview-node__children')
if is_found: if children_locator.count() > 0:
if parent is None: found = find_and_click_item(page, children_locator, item_name, parent)
if found:
return True return True
return False
else: else:
root_texts = root_locator.locator(f">div:nth-child({index + 1})").inner_text().splitlines() # Поиск без указания родителя
if parent in root_texts: nodes_count = root_locator.locator('>div.v-treeview-node').count()
for index in range(nodes_count):
node = root_locator.locator(f">div:nth-child({index + 1})").first
# Получаем только текст контента
content_locator = node.locator('div.v-treeview-node__content')
if content_locator.count() > 0:
content_text = content_locator.first.inner_text().strip()
if content_text == item_name:
content_locator.first.click()
return True return True
# закрываем узел, если в нем ничего не нашли # Рекурсивный поиск в дочерних элементах
if is_expanded: node_class_attr = node.get_attribute('class')
toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON) if "v-treeview-node--leaf" not in node_class_attr:
toggle_button.click() toggle_buttons = node.locator(NavigationPanelLocators.TOGGLE_BUTTON)
if toggle_buttons.count() > 0:
class_attr = toggle_buttons.first.get_attribute('class')
is_expanded = class_attr and "v-treeview-node__toggle--open" in class_attr
if not is_expanded:
toggle_buttons.first.click()
page.wait_for_timeout(500)
children_locator = node.locator('>div.v-treeview-node__children')
if children_locator.count() > 0:
found = find_and_click_item(page, children_locator, item_name, parent=None)
if found:
return True
# элемент с заданным именем не найден
return False return False
root_locator = self.get_locator(node_root_locator) root_locator = self.get_locator(node_root_locator)