kdtest-pw 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. kdtest_pw/__init__.py +50 -0
  2. kdtest_pw/action/__init__.py +7 -0
  3. kdtest_pw/action/base_keyword.py +292 -0
  4. kdtest_pw/action/element_plus/__init__.py +23 -0
  5. kdtest_pw/action/element_plus/el_cascader.py +263 -0
  6. kdtest_pw/action/element_plus/el_datepicker.py +324 -0
  7. kdtest_pw/action/element_plus/el_dialog.py +317 -0
  8. kdtest_pw/action/element_plus/el_form.py +443 -0
  9. kdtest_pw/action/element_plus/el_menu.py +456 -0
  10. kdtest_pw/action/element_plus/el_select.py +268 -0
  11. kdtest_pw/action/element_plus/el_table.py +442 -0
  12. kdtest_pw/action/element_plus/el_tree.py +364 -0
  13. kdtest_pw/action/element_plus/el_upload.py +313 -0
  14. kdtest_pw/action/key_retrieval.py +311 -0
  15. kdtest_pw/action/page_action.py +1129 -0
  16. kdtest_pw/api/__init__.py +6 -0
  17. kdtest_pw/api/api_keyword.py +251 -0
  18. kdtest_pw/api/request_handler.py +232 -0
  19. kdtest_pw/cases/__init__.py +6 -0
  20. kdtest_pw/cases/case_collector.py +182 -0
  21. kdtest_pw/cases/case_executor.py +359 -0
  22. kdtest_pw/cases/read/__init__.py +6 -0
  23. kdtest_pw/cases/read/cell_handler.py +305 -0
  24. kdtest_pw/cases/read/excel_reader.py +223 -0
  25. kdtest_pw/cli/__init__.py +5 -0
  26. kdtest_pw/cli/run.py +318 -0
  27. kdtest_pw/common.py +106 -0
  28. kdtest_pw/core/__init__.py +7 -0
  29. kdtest_pw/core/browser_manager.py +196 -0
  30. kdtest_pw/core/config_loader.py +235 -0
  31. kdtest_pw/core/page_context.py +228 -0
  32. kdtest_pw/data/__init__.py +5 -0
  33. kdtest_pw/data/init_data.py +105 -0
  34. kdtest_pw/data/static/elementData.yaml +59 -0
  35. kdtest_pw/data/static/parameters.json +24 -0
  36. kdtest_pw/plugins/__init__.py +6 -0
  37. kdtest_pw/plugins/element_plus_plugin/__init__.py +5 -0
  38. kdtest_pw/plugins/element_plus_plugin/elementData/elementData.yaml +144 -0
  39. kdtest_pw/plugins/element_plus_plugin/element_plus_plugin.py +237 -0
  40. kdtest_pw/plugins/element_plus_plugin/my.ini +23 -0
  41. kdtest_pw/plugins/plugin_base.py +180 -0
  42. kdtest_pw/plugins/plugin_loader.py +260 -0
  43. kdtest_pw/product.py +5 -0
  44. kdtest_pw/reference.py +99 -0
  45. kdtest_pw/utils/__init__.py +13 -0
  46. kdtest_pw/utils/built_in_function.py +376 -0
  47. kdtest_pw/utils/decorator.py +211 -0
  48. kdtest_pw/utils/log/__init__.py +6 -0
  49. kdtest_pw/utils/log/html_report.py +336 -0
  50. kdtest_pw/utils/log/logger.py +123 -0
  51. kdtest_pw/utils/public_script.py +366 -0
  52. kdtest_pw-2.0.0.dist-info/METADATA +169 -0
  53. kdtest_pw-2.0.0.dist-info/RECORD +57 -0
  54. kdtest_pw-2.0.0.dist-info/WHEEL +5 -0
  55. kdtest_pw-2.0.0.dist-info/entry_points.txt +2 -0
  56. kdtest_pw-2.0.0.dist-info/licenses/LICENSE +21 -0
  57. kdtest_pw-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,105 @@
1
+ """参数初始化模块"""
2
+
3
+ from typing import Dict, Any, Optional
4
+ from pathlib import Path
5
+
6
+ from ..reference import GSDSTORE, MODULEDATA, INFO
7
+
8
+
9
+ class InitData:
10
+ """参数初始化类
11
+
12
+ 负责初始化测试所需的各类数据。
13
+ """
14
+
15
+ def __init__(self, work_path: str = None):
16
+ """初始化
17
+
18
+ Args:
19
+ work_path: 工作目录路径
20
+ """
21
+ self._work_path = Path(work_path) if work_path else Path.cwd()
22
+ self._element_data: Dict[str, Any] = {}
23
+ self._custom_params: Dict[str, Any] = {}
24
+
25
+ def load_element_data(self, file_path: str = None) -> Dict[str, Any]:
26
+ """加载元素数据
27
+
28
+ Args:
29
+ file_path: elementData.yaml 文件路径
30
+
31
+ Returns:
32
+ Dict: 元素数据
33
+ """
34
+ if not file_path:
35
+ # 默认路径
36
+ file_path = self._work_path / 'data' / 'elementData' / 'elementData.yaml'
37
+
38
+ path = Path(file_path)
39
+ if not path.exists():
40
+ INFO(f"元素数据文件不存在: {file_path}", "WARNING")
41
+ return {}
42
+
43
+ try:
44
+ import yaml
45
+ with open(path, 'r', encoding='utf-8') as f:
46
+ self._element_data = yaml.safe_load(f) or {}
47
+
48
+ MODULEDATA['elementData'] = self._element_data
49
+ INFO(f"加载元素数据: {len(self._element_data)} 个模块")
50
+
51
+ except ImportError:
52
+ INFO("PyYAML 未安装,无法加载元素数据", "WARNING")
53
+ except Exception as e:
54
+ INFO(f"加载元素数据失败: {e}", "ERROR")
55
+
56
+ return self._element_data
57
+
58
+ def load_custom_params(self, params: Dict[str, Any] = None) -> Dict[str, Any]:
59
+ """加载自定义参数
60
+
61
+ Args:
62
+ params: 自定义参数字典
63
+
64
+ Returns:
65
+ Dict: 自定义参数
66
+ """
67
+ if params:
68
+ self._custom_params.update(params)
69
+ GSDSTORE['START']['selfDefinedParameter'] = self._custom_params
70
+ INFO(f"加载自定义参数: {list(params.keys())}")
71
+
72
+ return self._custom_params
73
+
74
+ def setup_work_path(self) -> None:
75
+ """设置工作路径"""
76
+ GSDSTORE['WORKPATH'] = {
77
+ 'root': str(self._work_path),
78
+ 'data': str(self._work_path / 'data'),
79
+ 'result': str(self._work_path / 'result'),
80
+ 'plugins': str(self._work_path / 'plugins'),
81
+ }
82
+
83
+ # 确保目录存在
84
+ (self._work_path / 'result' / 'report').mkdir(parents=True, exist_ok=True)
85
+ (self._work_path / 'result' / 'log').mkdir(parents=True, exist_ok=True)
86
+ (self._work_path / 'result' / 'screenshot').mkdir(parents=True, exist_ok=True)
87
+ (self._work_path / 'result' / 'trace').mkdir(parents=True, exist_ok=True)
88
+ (self._work_path / 'result' / 'video').mkdir(parents=True, exist_ok=True)
89
+
90
+ INFO(f"工作目录: {self._work_path}")
91
+
92
+ @property
93
+ def element_data(self) -> Dict[str, Any]:
94
+ """获取元素数据"""
95
+ return self._element_data
96
+
97
+ @property
98
+ def custom_params(self) -> Dict[str, Any]:
99
+ """获取自定义参数"""
100
+ return self._custom_params
101
+
102
+ @property
103
+ def work_path(self) -> Path:
104
+ """获取工作路径"""
105
+ return self._work_path
@@ -0,0 +1,59 @@
1
+ # KDTest Playwright 元素数据模板
2
+ # 格式: element_name: [定位类型, 定位表达式]
3
+
4
+ # 示例:登录模块
5
+ login:
6
+ # 用户名输入框
7
+ userName:
8
+ - xpath
9
+ - //input[@placeholder='请输入账号']
10
+ # 密码输入框
11
+ password:
12
+ - xpath
13
+ - //input[@placeholder='请输入密码']
14
+ # 登录按钮
15
+ submitBtn:
16
+ - css
17
+ - .el-button--primary
18
+ # 记住我复选框
19
+ rememberMe:
20
+ - css
21
+ - .el-checkbox
22
+
23
+ # 示例:首页模块
24
+ home:
25
+ # 欢迎文字
26
+ welcomeText:
27
+ - css
28
+ - .welcome-text
29
+ # 菜单列表
30
+ menuList:
31
+ - css
32
+ - .el-menu
33
+ # 退出按钮
34
+ logoutBtn:
35
+ - xpath
36
+ - //span[text()='退出']
37
+
38
+ # 示例:用户管理模块
39
+ userManage:
40
+ # 搜索输入框
41
+ searchInput:
42
+ - css
43
+ - .el-input__inner
44
+ # 搜索按钮
45
+ searchBtn:
46
+ - xpath
47
+ - //button[contains(.,'搜索')]
48
+ # 新增按钮
49
+ addBtn:
50
+ - xpath
51
+ - //button[contains(.,'新增')]
52
+ # 用户表格
53
+ userTable:
54
+ - css
55
+ - .el-table
56
+ # 状态下拉框
57
+ statusSelect:
58
+ - xpath
59
+ - //div[contains(@class,'el-select')]
@@ -0,0 +1,24 @@
1
+ {
2
+ "testCaseFile": [
3
+ {
4
+ "caseFilePath": "data/static/testCases.xlsx",
5
+ "caseItem": ["Sheet1"],
6
+ "interfaceSwitch": false
7
+ }
8
+ ],
9
+ "browser": "chromium",
10
+ "url": "http://localhost:8080",
11
+ "headless": false,
12
+ "slowMo": 0,
13
+ "timeout": 30000,
14
+ "trace": false,
15
+ "video": false,
16
+ "retrySwitch": false,
17
+ "retryCount": 1,
18
+ "parallel": false,
19
+ "selfDefinedParameter": {
20
+ "env": "test",
21
+ "username": "admin",
22
+ "password": "123456"
23
+ }
24
+ }
@@ -0,0 +1,6 @@
1
+ """插件模块"""
2
+
3
+ from .plugin_base import PluginBase
4
+ from .plugin_loader import PluginLoader
5
+
6
+ __all__ = ['PluginBase', 'PluginLoader']
@@ -0,0 +1,5 @@
1
+ """Element Plus 内置插件"""
2
+
3
+ from .element_plus_plugin import ElementPlusPlugin
4
+
5
+ __all__ = ['ElementPlusPlugin']
@@ -0,0 +1,144 @@
1
+ # Element Plus 通用元素定义模板
2
+ # 格式: element_name: [定位类型, 定位表达式]
3
+
4
+ # 登录模块示例
5
+ login:
6
+ userName:
7
+ - xpath
8
+ - //input[@placeholder='请输入账号']
9
+ password:
10
+ - xpath
11
+ - //input[@placeholder='请输入密码']
12
+ submitBtn:
13
+ - css
14
+ - .el-button--primary
15
+ rememberMe:
16
+ - css
17
+ - .el-checkbox
18
+
19
+ # 通用组件
20
+ common:
21
+ # Loading 遮罩
22
+ loadingMask:
23
+ - css
24
+ - .el-loading-mask
25
+ # 消息提示
26
+ message:
27
+ - css
28
+ - .el-message
29
+ messageContent:
30
+ - css
31
+ - .el-message__content
32
+ # 确认对话框
33
+ messageBox:
34
+ - css
35
+ - .el-message-box
36
+ messageBoxConfirm:
37
+ - css
38
+ - .el-message-box__btns .el-button--primary
39
+ messageBoxCancel:
40
+ - css
41
+ - .el-message-box__btns .el-button:not(.el-button--primary)
42
+ # 对话框
43
+ dialog:
44
+ - css
45
+ - .el-dialog
46
+ dialogClose:
47
+ - css
48
+ - .el-dialog__headerbtn
49
+ dialogConfirm:
50
+ - css
51
+ - .el-dialog__footer .el-button--primary
52
+ dialogCancel:
53
+ - css
54
+ - .el-dialog__footer .el-button:not(.el-button--primary)
55
+
56
+ # 表单组件
57
+ form:
58
+ input:
59
+ - css
60
+ - .el-input__inner
61
+ textarea:
62
+ - css
63
+ - .el-textarea__inner
64
+ select:
65
+ - css
66
+ - .el-select
67
+ selectDropdown:
68
+ - css
69
+ - .el-select-dropdown:visible
70
+ selectOption:
71
+ - css
72
+ - .el-select-dropdown__item
73
+ datepicker:
74
+ - css
75
+ - .el-date-editor
76
+ checkbox:
77
+ - css
78
+ - .el-checkbox
79
+ radio:
80
+ - css
81
+ - .el-radio
82
+ switch:
83
+ - css
84
+ - .el-switch
85
+
86
+ # 表格组件
87
+ table:
88
+ table:
89
+ - css
90
+ - .el-table
91
+ tableRow:
92
+ - css
93
+ - .el-table__row
94
+ tableCell:
95
+ - css
96
+ - .el-table__cell
97
+ tableHeader:
98
+ - css
99
+ - .el-table__header-wrapper th
100
+ tableCheckbox:
101
+ - css
102
+ - .el-table__row .el-checkbox
103
+ tableHeaderCheckbox:
104
+ - css
105
+ - .el-table__header-wrapper .el-checkbox
106
+
107
+ # 树形控件
108
+ tree:
109
+ tree:
110
+ - css
111
+ - .el-tree
112
+ treeNode:
113
+ - css
114
+ - .el-tree-node
115
+ treeLabel:
116
+ - css
117
+ - .el-tree-node__label
118
+ treeExpand:
119
+ - css
120
+ - .el-tree-node__expand-icon
121
+ treeCheckbox:
122
+ - css
123
+ - .el-tree-node .el-checkbox
124
+
125
+ # 分页组件
126
+ pagination:
127
+ pagination:
128
+ - css
129
+ - .el-pagination
130
+ prevBtn:
131
+ - css
132
+ - .el-pagination .btn-prev
133
+ nextBtn:
134
+ - css
135
+ - .el-pagination .btn-next
136
+ pageNumber:
137
+ - css
138
+ - .el-pagination .number
139
+ pageSizeSelect:
140
+ - css
141
+ - .el-pagination .el-select
142
+ jumper:
143
+ - css
144
+ - .el-pagination__jump .el-input__inner
@@ -0,0 +1,237 @@
1
+ """Element Plus 内置插件"""
2
+
3
+ from pathlib import Path
4
+ from playwright.sync_api import Page
5
+
6
+ from ..plugin_base import PluginBase
7
+ from ...action.element_plus import (
8
+ ElSelectKeyword,
9
+ ElDatePickerKeyword,
10
+ ElDialogKeyword,
11
+ ElTableKeyword,
12
+ ElCascaderKeyword,
13
+ ElTreeKeyword,
14
+ ElUploadKeyword,
15
+ ElFormKeyword,
16
+ ElMenuKeyword,
17
+ )
18
+
19
+
20
+ class ElementPlusPlugin(PluginBase):
21
+ """Element Plus 组件关键字插件
22
+
23
+ 提供 Element Plus UI 组件的操作关键字。
24
+ """
25
+
26
+ name = "element_plus"
27
+ version = "2.0.0"
28
+ description = "Element Plus UI 组件关键字"
29
+ author = "KDTest Team"
30
+
31
+ def __init__(self, page: Page = None):
32
+ super().__init__(page)
33
+ self._el_select: ElSelectKeyword = None
34
+ self._el_datepicker: ElDatePickerKeyword = None
35
+ self._el_dialog: ElDialogKeyword = None
36
+ self._el_table: ElTableKeyword = None
37
+ self._el_cascader: ElCascaderKeyword = None
38
+ self._el_tree: ElTreeKeyword = None
39
+ self._el_upload: ElUploadKeyword = None
40
+ self._el_form: ElFormKeyword = None
41
+ self._el_menu: ElMenuKeyword = None
42
+
43
+ def setup(self) -> None:
44
+ """初始化插件"""
45
+ # 加载配置
46
+ config_path = Path(__file__).parent / "my.ini"
47
+ if config_path.exists():
48
+ self.load_config_from_file(str(config_path))
49
+
50
+ # 加载元素数据
51
+ element_data_path = Path(__file__).parent / "elementData" / "elementData.yaml"
52
+ if element_data_path.exists():
53
+ self.load_element_data_from_file(str(element_data_path))
54
+
55
+ # 初始化关键字类
56
+ if self._page:
57
+ self._init_keyword_classes()
58
+
59
+ # 注册关键字
60
+ self._register_keywords()
61
+
62
+ def _init_keyword_classes(self) -> None:
63
+ """初始化关键字类实例"""
64
+ self._el_select = ElSelectKeyword(self._page)
65
+ self._el_datepicker = ElDatePickerKeyword(self._page)
66
+ self._el_dialog = ElDialogKeyword(self._page)
67
+ self._el_table = ElTableKeyword(self._page)
68
+ self._el_cascader = ElCascaderKeyword(self._page)
69
+ self._el_tree = ElTreeKeyword(self._page)
70
+ self._el_upload = ElUploadKeyword(self._page)
71
+ self._el_form = ElFormKeyword(self._page)
72
+ self._el_menu = ElMenuKeyword(self._page)
73
+
74
+ def _register_keywords(self) -> None:
75
+ """注册所有关键字"""
76
+ # Select 关键字
77
+ self.register_keywords({
78
+ 'el_select': self._wrap('_el_select', 'el_select'),
79
+ 'el_select_multiple': self._wrap('_el_select', 'el_select_multiple'),
80
+ 'el_select_clear': self._wrap('_el_select', 'el_select_clear'),
81
+ 'el_select_search': self._wrap('_el_select', 'el_select_search'),
82
+ 'el_select_get_value': self._wrap('_el_select', 'el_select_get_value'),
83
+ 'el_select_assert': self._wrap('_el_select', 'el_select_assert'),
84
+ })
85
+
86
+ # DatePicker 关键字
87
+ self.register_keywords({
88
+ 'el_datepicker': self._wrap('_el_datepicker', 'el_datepicker'),
89
+ 'el_datepicker_panel': self._wrap('_el_datepicker', 'el_datepicker_panel'),
90
+ 'el_datepicker_today': self._wrap('_el_datepicker', 'el_datepicker_today'),
91
+ 'el_datetimepicker': self._wrap('_el_datepicker', 'el_datetimepicker'),
92
+ 'el_daterange': self._wrap('_el_datepicker', 'el_daterange'),
93
+ 'el_datepicker_clear': self._wrap('_el_datepicker', 'el_datepicker_clear'),
94
+ 'el_datepicker_get_value': self._wrap('_el_datepicker', 'el_datepicker_get_value'),
95
+ })
96
+
97
+ # Dialog 关键字
98
+ self.register_keywords({
99
+ 'el_dialog_wait': self._wrap('_el_dialog', 'el_dialog_wait'),
100
+ 'el_dialog_close': self._wrap('_el_dialog', 'el_dialog_close'),
101
+ 'el_dialog_confirm': self._wrap('_el_dialog', 'el_dialog_confirm'),
102
+ 'el_dialog_cancel': self._wrap('_el_dialog', 'el_dialog_cancel'),
103
+ 'el_dialog_input': self._wrap('_el_dialog', 'el_dialog_input'),
104
+ 'el_message_box_wait': self._wrap('_el_dialog', 'el_message_box_wait'),
105
+ 'el_message_box_confirm': self._wrap('_el_dialog', 'el_message_box_confirm'),
106
+ 'el_message_box_input': self._wrap('_el_dialog', 'el_message_box_input'),
107
+ 'el_message_wait': self._wrap('_el_dialog', 'el_message_wait'),
108
+ 'el_message_get_text': self._wrap('_el_dialog', 'el_message_get_text'),
109
+ 'el_message_assert': self._wrap('_el_dialog', 'el_message_assert'),
110
+ 'el_notification_wait': self._wrap('_el_dialog', 'el_notification_wait'),
111
+ 'el_notification_close': self._wrap('_el_dialog', 'el_notification_close'),
112
+ 'el_drawer_wait': self._wrap('_el_dialog', 'el_drawer_wait'),
113
+ 'el_drawer_close': self._wrap('_el_dialog', 'el_drawer_close'),
114
+ })
115
+
116
+ # Table 关键字
117
+ self.register_keywords({
118
+ 'el_table_click_row': self._wrap('_el_table', 'el_table_click_row'),
119
+ 'el_table_click_cell': self._wrap('_el_table', 'el_table_click_cell'),
120
+ 'el_table_get_cell_text': self._wrap('_el_table', 'el_table_get_cell_text'),
121
+ 'el_table_get_row_count': self._wrap('_el_table', 'el_table_get_row_count'),
122
+ 'el_table_select_row': self._wrap('_el_table', 'el_table_select_row'),
123
+ 'el_table_select_rows': self._wrap('_el_table', 'el_table_select_rows'),
124
+ 'el_table_sort': self._wrap('_el_table', 'el_table_sort'),
125
+ 'el_table_expand_row': self._wrap('_el_table', 'el_table_expand_row'),
126
+ 'el_table_click_button': self._wrap('_el_table', 'el_table_click_button'),
127
+ 'el_table_search_row': self._wrap('_el_table', 'el_table_search_row'),
128
+ 'el_table_assert_cell': self._wrap('_el_table', 'el_table_assert_cell'),
129
+ })
130
+
131
+ # Cascader 关键字
132
+ self.register_keywords({
133
+ 'el_cascader': self._wrap('_el_cascader', 'el_cascader'),
134
+ 'el_cascader_search': self._wrap('_el_cascader', 'el_cascader_search'),
135
+ 'el_cascader_clear': self._wrap('_el_cascader', 'el_cascader_clear'),
136
+ 'el_cascader_get_value': self._wrap('_el_cascader', 'el_cascader_get_value'),
137
+ 'el_cascader_assert': self._wrap('_el_cascader', 'el_cascader_assert'),
138
+ })
139
+
140
+ # Tree 关键字
141
+ self.register_keywords({
142
+ 'el_tree_click_node': self._wrap('_el_tree', 'el_tree_click_node'),
143
+ 'el_tree_expand_node': self._wrap('_el_tree', 'el_tree_expand_node'),
144
+ 'el_tree_collapse_node': self._wrap('_el_tree', 'el_tree_collapse_node'),
145
+ 'el_tree_check_node': self._wrap('_el_tree', 'el_tree_check_node'),
146
+ 'el_tree_check_nodes': self._wrap('_el_tree', 'el_tree_check_nodes'),
147
+ 'el_tree_expand_all': self._wrap('_el_tree', 'el_tree_expand_all'),
148
+ 'el_tree_collapse_all': self._wrap('_el_tree', 'el_tree_collapse_all'),
149
+ 'el_tree_search': self._wrap('_el_tree', 'el_tree_search'),
150
+ 'el_tree_assert_node_exists': self._wrap('_el_tree', 'el_tree_assert_node_exists'),
151
+ })
152
+
153
+ # Upload 关键字
154
+ self.register_keywords({
155
+ 'el_upload': self._wrap('_el_upload', 'el_upload'),
156
+ 'el_upload_drag': self._wrap('_el_upload', 'el_upload_drag'),
157
+ 'el_upload_remove': self._wrap('_el_upload', 'el_upload_remove'),
158
+ 'el_upload_clear': self._wrap('_el_upload', 'el_upload_clear'),
159
+ 'el_upload_preview': self._wrap('_el_upload', 'el_upload_preview'),
160
+ 'el_upload_get_file_count': self._wrap('_el_upload', 'el_upload_get_file_count'),
161
+ 'el_upload_assert_count': self._wrap('_el_upload', 'el_upload_assert_count'),
162
+ 'el_upload_wait_success': self._wrap('_el_upload', 'el_upload_wait_success'),
163
+ })
164
+
165
+ # Form 关键字
166
+ self.register_keywords({
167
+ 'el_form_input': self._wrap('_el_form', 'el_form_input'),
168
+ 'el_form_select': self._wrap('_el_form', 'el_form_select'),
169
+ 'el_form_date': self._wrap('_el_form', 'el_form_date'),
170
+ 'el_form_checkbox': self._wrap('_el_form', 'el_form_checkbox'),
171
+ 'el_form_radio': self._wrap('_el_form', 'el_form_radio'),
172
+ 'el_form_switch': self._wrap('_el_form', 'el_form_switch'),
173
+ 'el_form_submit': self._wrap('_el_form', 'el_form_submit'),
174
+ 'el_form_reset': self._wrap('_el_form', 'el_form_reset'),
175
+ 'el_form_get_error': self._wrap('_el_form', 'el_form_get_error'),
176
+ 'el_form_assert_error': self._wrap('_el_form', 'el_form_assert_error'),
177
+ 'el_form_fill': self._wrap('_el_form', 'el_form_fill'),
178
+ })
179
+
180
+ # Menu 菜单导航关键字
181
+ self.register_keywords({
182
+ 'menu_load_data': self._wrap('_el_menu', 'load_menu_data'),
183
+ 'menu_navigate': self._wrap('_el_menu', 'menu_navigate'),
184
+ 'menu_click_first': self._wrap('_el_menu', 'menu_click_first'),
185
+ 'menu_click_second': self._wrap('_el_menu', 'menu_click_second'),
186
+ 'menu_click_third': self._wrap('_el_menu', 'menu_click_third'),
187
+ 'menu_click_tag': self._wrap('_el_menu', 'menu_click_tag'),
188
+ 'menu_switch_iframe': self._wrap('_el_menu', 'menu_switch_iframe'),
189
+ 'menu_exit_iframe': self._wrap('_el_menu', 'menu_exit_iframe'),
190
+ 'menu_get_first_menus': self._wrap('_el_menu', 'menu_get_first_menus'),
191
+ 'menu_get_second_menus': self._wrap('_el_menu', 'menu_get_second_menus'),
192
+ 'menu_get_tag_count': self._wrap('_el_menu', 'menu_get_tag_count'),
193
+ 'menu_has_iframe': self._wrap('_el_menu', 'menu_has_iframe'),
194
+ 'menu_get_iframe_name': self._wrap('_el_menu', 'menu_get_iframe_name'),
195
+ })
196
+
197
+ def _wrap(self, instance_name: str, method_name: str):
198
+ """包装方法调用
199
+
200
+ Args:
201
+ instance_name: 实例属性名
202
+ method_name: 方法名
203
+
204
+ Returns:
205
+ 包装后的函数
206
+ """
207
+ def wrapper(*args, **kwargs):
208
+ instance = getattr(self, instance_name)
209
+ if instance is None:
210
+ if self._page:
211
+ self._init_keyword_classes()
212
+ instance = getattr(self, instance_name)
213
+ else:
214
+ raise RuntimeError("Page 实例未设置")
215
+
216
+ method = getattr(instance, method_name)
217
+ return method(*args, **kwargs)
218
+
219
+ return wrapper
220
+
221
+ def set_page(self, page: Page) -> None:
222
+ """设置 Page 实例"""
223
+ super().set_page(page)
224
+ if page:
225
+ self._init_keyword_classes()
226
+
227
+ def load_menu_data(self, file_path: str) -> None:
228
+ """加载菜单配置文件
229
+
230
+ Args:
231
+ file_path: modularInformation.json 文件路径
232
+ """
233
+ if self._el_menu:
234
+ self._el_menu.load_menu_data(file_path)
235
+ elif self._page:
236
+ self._init_keyword_classes()
237
+ self._el_menu.load_menu_data(file_path)
@@ -0,0 +1,23 @@
1
+ [element_plus]
2
+ # Element Plus 插件配置
3
+
4
+ # 默认等待超时 (毫秒)
5
+ default_timeout = 5000
6
+
7
+ # 下拉面板选择器
8
+ dropdown_selector = .el-select-dropdown:visible, .el-popper:visible
9
+
10
+ # 日期面板选择器
11
+ datepicker_panel_selector = .el-date-picker:visible, .el-picker-panel:visible
12
+
13
+ # 对话框选择器
14
+ dialog_selector = .el-dialog:visible
15
+
16
+ # Message 选择器
17
+ message_selector = .el-message:visible
18
+
19
+ # 是否等待 loading 消失
20
+ wait_loading = true
21
+
22
+ # loading 选择器
23
+ loading_selector = .el-loading-mask