From 27ca4596fac2778621d8efc156913003af9fbb8b Mon Sep 17 00:00:00 2001 From: Radislav Date: Tue, 25 Nov 2025 13:59:33 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?=20is=5Fitem=5Fvisible=20=D0=B2=20=D0=BD=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=B3=D0=B0=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=83=D1=8E=20=D0=BF?= =?UTF-8?q?=D0=B0=D0=BD=D0=B5=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавлен метод для проверки видимости элемента без исключений - Возвращает boolean значение для условных проверок --- components/navbar_component.py | 108 +++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/components/navbar_component.py b/components/navbar_component.py index 6825859..4a8b318 100644 --- a/components/navbar_component.py +++ b/components/navbar_component.py @@ -21,20 +21,6 @@ class NavigationPanelComponent(BaseComponent): super().__init__(page) # Действия: - def get_item_names(self, locator: str | Locator) -> list[str]: - """Возвращает тексты всех элементов по указанному локатору. - - Args: - locator: Локатор элементов или строка с CSS/XPath. - - Returns: - Список текстов элементов. - """ - - loc = self.get_locator(locator) - return loc.all_inner_texts() - - def click_item(self, locator: str | Locator, item_name: str) -> None: """Кликает по элементу с указанным текстом. @@ -50,13 +36,12 @@ class NavigationPanelComponent(BaseComponent): """Кликает по вложенному элементу с указанным текстом. Args: - node_root_locator: Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath). + node_root_locator: Локатор для поиска корневых элементов дерева. item_name: Текст элемента для клика. """ 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') nodes_count = root_locator.locator('>div.v-treeview-node').count() # Если искомый элемент находится на данном уровне, вычисляем локатор и делаем клик @@ -69,9 +54,9 @@ class NavigationPanelComponent(BaseComponent): if item_name == node_text: node_attr = node.get_attribute('class') if "v-treeview-node--leaf" not in node_attr: - toggle_button = node.\ - locator(NavigationPanelLocators.NODE_ROOT). \ - locator(NavigationPanelLocators.TOGGLE_BUTTON).first + 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() @@ -93,17 +78,17 @@ class NavigationPanelComponent(BaseComponent): # Проверяем лист это или начало поддерева if "v-treeview-node--leaf" not in node_class_attr: # Проверяем, является ли узел раскрытым - class_attr = node.\ - locator(NavigationPanelLocators.NODE_ROOT). \ - locator(NavigationPanelLocators.TOGGLE_BUTTON).first.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: is_expanded = True # Если узел закрыт можем его раскрыть if is_expanded is False: - toggle_button = node.\ - locator(NavigationPanelLocators.NODE_ROOT). \ - locator(NavigationPanelLocators.TOGGLE_BUTTON).first + toggle_button = node.locator( + NavigationPanelLocators.NODE_ROOT + ).locator(NavigationPanelLocators.TOGGLE_BUTTON).first toggle_button.click() # Ждем, пока дочерние элементы прогрузятся/появятся page.wait_for_timeout(1000) @@ -118,21 +103,27 @@ class NavigationPanelComponent(BaseComponent): # Рекурсивный вызов для дочерних элементов # Ищем дочерние элементы *внутри* текущего узла if has_children and is_expanded: - child_nodes_locator = root_locator.locator(f">div:nth-child({index + 1})").locator('>div.v-treeview-node__children') - found_loc = find_and_click_item(page, child_nodes_locator, item_name, parent=None) + child_nodes_locator = root_locator.locator( + f">div:nth-child({index + 1})" + ).locator('>div.v-treeview-node__children') + found_loc = find_and_click_item( + page, child_nodes_locator, item_name, parent=None + ) if found_loc: if parent is None: return found_loc 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: return found_loc # закрываем узел, если в нем ничего не нашли if is_expanded: - toggle_button = node.\ - locator(NavigationPanelLocators.NODE_ROOT). \ - locator(NavigationPanelLocators.TOGGLE_BUTTON).first + toggle_button = node.locator( + NavigationPanelLocators.NODE_ROOT + ).locator(NavigationPanelLocators.TOGGLE_BUTTON).first toggle_button.click() page.wait_for_timeout(1000) @@ -142,17 +133,33 @@ class NavigationPanelComponent(BaseComponent): root_locator = self.get_locator(node_root_locator) 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) + 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" - def traverse_panel_tree(self, node_root_locator: str | Locator, level=0, debug=False): - """ - Рекурсивно обходит дерево v-treeview и выводит информацию об элементах в режиме отладки (debug=True). + def get_item_names(self, locator: str | Locator) -> list[str]: + """Возвращает тексты всех элементов по указанному локатору. Args: - node_root_locator: Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath). + locator: Локатор элементов или строка с CSS/XPath. + + Returns: + Список текстов элементов. + """ + + loc = self.get_locator(locator) + return loc.all_inner_texts() + + def traverse_panel_tree(self, node_root_locator: str | Locator, level=0, debug=False): + """ + Рекурсивно обходит дерево v-treeview и выводит информацию об элементах. + + Args: + node_root_locator: Локатор для поиска корневых элементов дерева. """ def traverse_tree(page, root_locator, level=0, debug=False): # Находим все локаторы корневых узлов на текущем уровне @@ -171,7 +178,8 @@ class NavigationPanelComponent(BaseComponent): # Проверяем лист это или начало поддерева if "v-treeview-node--leaf" in node_class_attr: if debug: - print(f'[{level}][{index}] {node_text} (LEAF, Expanded: {is_expanded}, Has Children: {has_children})') + leaf_msg = f'[{level}][{index}] {node_text} (LEAF, Expanded: {is_expanded}' + print(f"{leaf_msg}, Has Children: {has_children})") print("-----------------------------------------") else: # Проверяем, является ли узел раскрытым @@ -198,13 +206,16 @@ class NavigationPanelComponent(BaseComponent): if debug: # Выводим информацию об узле - print(f'[{level}][{index}] {edited_node_text} (NODE, Expanded: {is_expanded}, Has Children: {has_children})') + node_msg = f'[{level}][{index}] {edited_node_text} (NODE, Expanded: {is_expanded}' + print(f"{node_msg}, Has Children: {has_children})") print("-----------------------------------------") # Рекурсивный вызов для дочерних элементов # Ищем дочерние элементы *внутри* текущего узла 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') traverse_tree(page, child_nodes_locator, level+1, debug) root_locator = self.get_locator(node_root_locator) @@ -235,3 +246,22 @@ class NavigationPanelComponent(BaseComponent): else: loc = loc.get_by_text(item_name) self.check_visibility(loc, msg) + + def is_item_visible(self, locator: str | Locator, item_name: str) -> bool: + """ + Проверяет видимость элемента с указанным текстом без выбрасывания исключения. + + Args: + locator: Локатор элемента или строка с CSS/XPath. + item_name: Текст элемента для проверки. + + Returns: + bool: True если элемент видим, False если нет. + """ + element_locator = self.page.locator(locator).filter(has_text=item_name) + + # Сначала проверяем что элемент вообще существует + if element_locator.count() == 0: + return False + + return element_locator.is_visible()