11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
-42
-43
-44
-45
-46
-47
-48
-49
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64
-65
-66
-67
-68
-69
-70
-71
-72
-73
-74
-75
-76
-77
-78
-79
-80
-81
-82
-83
-84
-85
-86
-87
-88
-89
-90
-91
-92
-93
-94
-95
-96 | class NavigationPanelComponent(BaseComponent):
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210 | class NavigationPanelComponent(BaseComponent):
"""Компонент панели навигации. Предоставляет методы для взаимодействия с ней."""
def __init__(self, page: Page):
@@ -2002,6 +2365,7 @@
loc = self.get_locator(locator)
return loc.all_inner_texts()
+
def click_item(self, locator: str | Locator, item_name: str) -> None:
"""Кликает по элементу с указанным текстом.
@@ -2013,29 +2377,142 @@
loc = self.get_locator(locator)
loc.get_by_text(item_name).click()
- def click_sub_item(self, locator: str | Locator, sublevel_number: int, item_name: str) -> None:
+ def click_sub_item(self, node_root_locator: str | Locator, item_name: str) -> None:
"""Кликает по вложенному элементу с указанным текстом.
Args:
- locator: Локатор родительского элемента.
- sublevel_number: Уровень вложенности (1 или 2).
+ node_root_locator: Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath).
item_name: Текст элемента для клика.
-
- Raises:
- ValueError: Если уровень вложенности не 1 или 2.
"""
- root_locator = self.get_locator(NavigationPanelLocators.NODE_ROOT)
- children_locator = self.get_locator(NavigationPanelLocators.NODE_CHILDREN)
+ def find_and_click_item(page, root_locator, item_name: str) -> bool:
+ # Находим все локаторы корневых узлов на текущем уровне
+ root_node = root_locator.locator('>div.v-treeview-node')
+ # Получаем список текстов
+ root_node_texts = root_node.all_inner_texts()
- loc = self.get_locator(locator)
+ # Если искомый элемент находится на данном уровне, вычисляем локатор и делаем клик
+ 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 sublevel_number == 1:
- loc.locator(root_locator).get_by_text(item_name).click()
- elif sublevel_number == 2:
- loc.locator(children_locator).locator(root_locator).get_by_text(item_name).click()
- else:
- raise ValueError("the navigation panel has two levels of nesting only")
+ # Если элемента нет, рекурсивно ищем дальше
+ 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
+
+ # Извлекаем аттрибуты из корневого узла
+ node_class_attr = node.get_attribute('class')
+
+ is_expanded = False
+ has_children = False
+
+ # Проверяем лист это или начало поддерева
+ 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 is_expanded is False:
+ toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON)
+ toggle_button.click()
+ # Ждем, пока дочерние элементы прогрузятся/появятся
+ page.wait_for_timeout(300)
+ is_expanded = True
+
+ # Проверяем, имеет ли узел дочерние элементы
+ 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
+
+ # Рекурсивный вызов для дочерних элементов
+ # Ищем дочерние элементы *внутри* текущего узла
+ 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)
+ if is_found:
+ return True
+
+ # закрываем узел, если в нем ничего не нашли
+ if is_expanded:
+ toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON)
+ toggle_button.click()
+
+ # элемент с заданным именем не найден
+ return False
+
+ root_locator = self.get_locator(node_root_locator)
+ found = find_and_click_item(self.page, root_locator, item_name)
+ 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).
+
+ Args:
+ node_root_locator: Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath).
+ """
+ def traverse_tree(page, root_locator, level=0, debug=False):
+ # Находим все локаторы корневых узлов на текущем уровне
+ 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
+
+ # Извлекаем текст и аттрибуты из корневого узла
+ node_text = node.inner_text()
+ node_class_attr = node.get_attribute('class')
+
+ is_expanded = False
+ has_children = False
+
+ # Проверяем лист это или начало поддерева
+ 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})')
+ print("-----------------------------------------")
+ else:
+ # Проверяем, является ли узел раскрытым
+ class_attr = node.locator(NavigationPanelLocators.TOGGLE_BUTTON).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.TOGGLE_BUTTON)
+ toggle_button.click()
+ # Ждем, пока дочерние элементы прогрузятся/появятся
+ page.wait_for_timeout(300)
+ is_expanded = True
+
+ # Проверяем, имеет ли узел дочерние элементы
+ 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
+
+ edited_node_text = node_text.replace("expand_more\n", "")
+
+ if debug:
+ # Выводим информацию об узле
+ print(f'[{level}][{index}] {edited_node_text} (NODE, Expanded: {is_expanded}, 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')
+ traverse_tree(page, child_nodes_locator, level+1, debug)
+
+ root_locator = self.get_locator(node_root_locator)
+ traverse_tree(self.page, root_locator, level=level, debug=debug)
# Проверки:
def check_item_visibility(self, locator: str | Locator, item_name: str) -> None:
@@ -2213,30 +2690,30 @@
Source code in components\navbar_component.py
- 73
-74
-75
-76
-77
-78
-79
-80
-81
-82
-83
-84
-85
-86
-87
-88
-89
-90
-91
-92
-93
-94
-95
-96 | def check_item_visibility(self, locator: str | Locator, item_name: str) -> None:
+ 187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210 | def check_item_visibility(self, locator: str | Locator, item_name: str) -> None:
"""Проверяет видимость элемента с указанным текстом.
Args:
@@ -2329,8 +2806,7 @@
Source code in components\navbar_component.py
- 37
-38
+ 38
39
40
41
@@ -2338,7 +2814,8 @@
43
44
45
-46 | def click_item(self, locator: str | Locator, item_name: str) -> None:
+46
+47
| def click_item(self, locator: str | Locator, item_name: str) -> None:
"""Кликает по элементу с указанным текстом.
Args:
@@ -2358,7 +2835,7 @@
- click_sub_item(locator, sublevel_number, item_name)
+ click_sub_item(node_root_locator, item_name)
@@ -2381,30 +2858,14 @@
- locator
+ node_root_locator
|
str | Locator
|
- Локатор родительского элемента.
-
- |
-
- required
- |
-
-
-
- sublevel_number
- |
-
- int
- |
-
-
- Уровень вложенности (1 или 2).
+ Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath).
|
@@ -2431,76 +2892,153 @@
|
|
- Raises:
-
-
-
- | Type |
- Description |
-
-
-
-
-
- ValueError
- |
-
-
- Если уровень вложенности не 1 или 2.
-
- |
-
-
-
-
-
Source code in components\navbar_component.py
- 48
-49
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64
-65
-66
-67
-68
-69
-70 | def click_sub_item(self, locator: str | Locator, sublevel_number: int, item_name: str) -> None:
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121 | def click_sub_item(self, node_root_locator: str | Locator, item_name: str) -> None:
"""Кликает по вложенному элементу с указанным текстом.
Args:
- locator: Локатор родительского элемента.
- sublevel_number: Уровень вложенности (1 или 2).
+ node_root_locator: Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath).
item_name: Текст элемента для клика.
-
- Raises:
- ValueError: Если уровень вложенности не 1 или 2.
"""
- root_locator = self.get_locator(NavigationPanelLocators.NODE_ROOT)
- children_locator = self.get_locator(NavigationPanelLocators.NODE_CHILDREN)
+ def find_and_click_item(page, root_locator, item_name: str) -> bool:
+ # Находим все локаторы корневых узлов на текущем уровне
+ root_node = root_locator.locator('>div.v-treeview-node')
+ # Получаем список текстов
+ root_node_texts = root_node.all_inner_texts()
- loc = self.get_locator(locator)
+ # Если искомый элемент находится на данном уровне, вычисляем локатор и делаем клик
+ 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 sublevel_number == 1:
- loc.locator(root_locator).get_by_text(item_name).click()
- elif sublevel_number == 2:
- loc.locator(children_locator).locator(root_locator).get_by_text(item_name).click()
- else:
- raise ValueError("the navigation panel has two levels of nesting only")
+ # Если элемента нет, рекурсивно ищем дальше
+ 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
+
+ # Извлекаем аттрибуты из корневого узла
+ node_class_attr = node.get_attribute('class')
+
+ is_expanded = False
+ has_children = False
+
+ # Проверяем лист это или начало поддерева
+ 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 is_expanded is False:
+ toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON)
+ toggle_button.click()
+ # Ждем, пока дочерние элементы прогрузятся/появятся
+ page.wait_for_timeout(300)
+ is_expanded = True
+
+ # Проверяем, имеет ли узел дочерние элементы
+ 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
+
+ # Рекурсивный вызов для дочерних элементов
+ # Ищем дочерние элементы *внутри* текущего узла
+ 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)
+ if is_found:
+ return True
+
+ # закрываем узел, если в нем ничего не нашли
+ if is_expanded:
+ toggle_button = node.locator(NavigationPanelLocators.TOGGLE_BUTTON)
+ toggle_button.click()
+
+ # элемент с заданным именем не найден
+ return False
+
+ root_locator = self.get_locator(node_root_locator)
+ found = find_and_click_item(self.page, root_locator, item_name)
+ assert found, f"Navigation panel item {item_name} is missing"
|
@@ -2606,6 +3144,182 @@
+
+
+
+
+ traverse_panel_tree(node_root_locator, level=0, debug=False)
+
+
+
+
+
+
+ Рекурсивно обходит дерево v-treeview и выводит информацию об элементах в режиме отладки (debug=True).
+
+
+ Parameters:
+
+
+
+ | Name |
+ Type |
+ Description |
+ Default |
+
+
+
+
+
+ node_root_locator
+ |
+
+ str | Locator
+ |
+
+
+ Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath).
+
+ |
+
+ required
+ |
+
+
+
+
+
+
+ Source code in components\navbar_component.py
+ 123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184 | def traverse_panel_tree(self, node_root_locator: str | Locator, level=0, debug=False):
+ """
+ Рекурсивно обходит дерево v-treeview и выводит информацию об элементах в режиме отладки (debug=True).
+
+ Args:
+ node_root_locator: Локатор для поиска корневых элементов дерева (Локатор элемента или строка с CSS/XPath).
+ """
+ def traverse_tree(page, root_locator, level=0, debug=False):
+ # Находим все локаторы корневых узлов на текущем уровне
+ 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
+
+ # Извлекаем текст и аттрибуты из корневого узла
+ node_text = node.inner_text()
+ node_class_attr = node.get_attribute('class')
+
+ is_expanded = False
+ has_children = False
+
+ # Проверяем лист это или начало поддерева
+ 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})')
+ print("-----------------------------------------")
+ else:
+ # Проверяем, является ли узел раскрытым
+ class_attr = node.locator(NavigationPanelLocators.TOGGLE_BUTTON).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.TOGGLE_BUTTON)
+ toggle_button.click()
+ # Ждем, пока дочерние элементы прогрузятся/появятся
+ page.wait_for_timeout(300)
+ is_expanded = True
+
+ # Проверяем, имеет ли узел дочерние элементы
+ 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
+
+ edited_node_text = node_text.replace("expand_more\n", "")
+
+ if debug:
+ # Выводим информацию об узле
+ print(f'[{level}][{index}] {edited_node_text} (NODE, Expanded: {is_expanded}, 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')
+ traverse_tree(page, child_nodes_locator, level+1, debug)
+
+ root_locator = self.get_locator(node_root_locator)
+ traverse_tree(self.page, root_locator, level=level, debug=debug)
+
|
+
+
+
+
+
diff --git a/site/components/table_component/index.html b/site/components/table_component/index.html
index 441feab..c71b11b 100644
--- a/site/components/table_component/index.html
+++ b/site/components/table_component/index.html
@@ -501,6 +501,27 @@
+
+
+
+
+
+ JsonContainerComponent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -934,6 +955,27 @@
+
+
+
+
+
+ ButtonLocators
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -976,6 +1018,48 @@
+
+
+
+
+
+ InputLocators
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JsonContainerLocators
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1039,6 +1123,27 @@
+
+
+
+
+
+ TextLocators
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1082,7 +1187,7 @@
- Страницы приложения
+ Модальные окна
@@ -1091,6 +1196,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
|
|
|
|
|