From 8a9228e75eb2a6d0c95fee9a1b4205d01477f54e Mon Sep 17 00:00:00 2001 From: Radislav Date: Wed, 22 Oct 2025 19:58:40 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=BE:=20=D0=B2=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B5=20click?= =?UTF-8?q?=5Fsub=5Fitem,=20=D1=83=D0=B1=D1=80=D0=B0=D0=BD=D0=B0=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B0=20'=D0=95=D1=81?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=BD=D0=B5=20=D0=BD=D0=B0=D1=88=D0=BB=D0=B8=20?= =?UTF-8?q?=D1=81=D1=80=D0=B5=D0=B4=D0=B8=20=D0=BD=D0=B5=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D1=80=D0=B5=D0=B4=D1=81=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=B4=D0=B5=D1=82=D0=B5=D0=B9,=20=D0=B8=D1=89=D0=B5?= =?UTF-8?q?=D0=BC=20=D1=80=D0=B5=D0=BA=D1=83=D1=80=D1=81=D0=B8=D0=B2=D0=BD?= =?UTF-8?q?=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/navbar_component.py | 165 +++++++++++++++++++++------------ 1 file changed, 105 insertions(+), 60 deletions(-) diff --git a/components/navbar_component.py b/components/navbar_component.py index 68339e9..f3567b9 100644 --- a/components/navbar_component.py +++ b/components/navbar_component.py @@ -47,80 +47,125 @@ class NavigationPanelComponent(BaseComponent): loc.get_by_text(item_name).click() 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: - # Находим все локаторы корневых узлов на текущем уровне - root_node = root_locator.locator('>div.v-treeview-node') - # Получаем список текстов - root_node_texts = root_node.all_inner_texts() + """Рекурсивно ищет элемент в дереве и кликает по нему.""" - # Если искомый элемент находится на данном уровне, вычисляем локатор и делаем клик - if parent is None: - for index, node_text in enumerate(root_node_texts): - node_text = node_text.replace("expand_more\n", "") - if item_name == node_text: - root_node.nth(index).click() - return True + # Если указан родитель, сначала находим его + if parent: + # Ищем родительский элемент + parent_found = False + 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): + node = root_locator.locator(f">div:nth-child({index + 1})").first - 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() - # Извлекаем аттрибуты из корневого узла - node_class_attr = node.get_attribute('class') + # Ищем родителя в тексте контента + if parent == content_text: + parent_found = True - is_expanded = False - has_children = False + # Раскрываем родительский элемент если нужно + 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 "v-treeview-node--leaf" not in node_class_attr: - # Проверяем, является ли узел раскрытым - class_attr = node.locator(NavigationPanelLocators.TOGGLE_BUTTON).get_attribute('class') - if "v-treeview-node__toggle--open" in class_attr: - is_expanded = True + if not is_expanded: + toggle_buttons.first.click() + page.wait_for_timeout(1000) - # Если узел закрыт можем его раскрыть - if is_expanded is False: - toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON) - toggle_button.click() - # Ждем, пока дочерние элементы прогрузятся/появятся - page.wait_for_timeout(300) - is_expanded = True + # После раскрытия ждем появления дочерних элементов + page.wait_for_timeout(500) - # Проверяем, имеет ли узел дочерние элементы - children_count = node.locator('>div.v-treeview-node__children').count() - content = node.locator('>div.v-treeview-node__children').inner_html() - if children_count > 0 and len(content) != 0: - has_children = 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() - # Рекурсивный вызов для дочерних элементов - # Ищем дочерние элементы *внутри* текущего узла - if has_children and is_expanded: - 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) - if is_found: - if parent is None: + 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 + + # Проверяем, имеет ли узел дочерние элементы + 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) + if found: return True - else: - root_texts = root_locator.locator(f">div:nth-child({index + 1})").inner_text().splitlines() - if parent in root_texts: - return True - # закрываем узел, если в нем ничего не нашли - if is_expanded: - toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON) - toggle_button.click() + return False - # элемент с заданным именем не найден - return False + else: + # Поиск без указания родителя + 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 + + # Рекурсивный поиск в дочерних элементах + node_class_attr = node.get_attribute('class') + if "v-treeview-node--leaf" not in node_class_attr: + 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 root_locator = self.get_locator(node_root_locator) found = find_and_click_item(self.page, root_locator, item_name, parent)