ui-engine-xin 0.0.1__tar.gz
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.
- ui_engine_xin-0.0.1/LICENSE +21 -0
- ui_engine_xin-0.0.1/MANIFEST.in +3 -0
- ui_engine_xin-0.0.1/PKG-INFO +239 -0
- ui_engine_xin-0.0.1/README.md +215 -0
- ui_engine_xin-0.0.1/UIEngine/__init__.py +9 -0
- ui_engine_xin-0.0.1/UIEngine/basecase.py +60 -0
- ui_engine_xin-0.0.1/UIEngine/browser/__init__.py +2 -0
- ui_engine_xin-0.0.1/UIEngine/browser/base_browser.py +158 -0
- ui_engine_xin-0.0.1/UIEngine/caseLog.py +145 -0
- ui_engine_xin-0.0.1/UIEngine/config/__init__.py +1 -0
- ui_engine_xin-0.0.1/UIEngine/config/default.yaml +6 -0
- ui_engine_xin-0.0.1/UIEngine/core/__init__.py +4 -0
- ui_engine_xin-0.0.1/UIEngine/core/exceptions.py +9 -0
- ui_engine_xin-0.0.1/UIEngine/core/keyword_manager.py +109 -0
- ui_engine_xin-0.0.1/UIEngine/core/variable_resolver.py +74 -0
- ui_engine_xin-0.0.1/UIEngine/keywords/__init__.py +7 -0
- ui_engine_xin-0.0.1/UIEngine/keywords/assert_keywords.py +172 -0
- ui_engine_xin-0.0.1/UIEngine/keywords/iframe_keywords.py +124 -0
- ui_engine_xin-0.0.1/UIEngine/keywords/locator_keywords.py +268 -0
- ui_engine_xin-0.0.1/UIEngine/keywords/mouse_keywords.py +74 -0
- ui_engine_xin-0.0.1/UIEngine/keywords/page_keywords.py +144 -0
- ui_engine_xin-0.0.1/UIEngine/keywords/wait_keywords.py +68 -0
- ui_engine_xin-0.0.1/UIEngine/reporting/__init__.py +2 -0
- ui_engine_xin-0.0.1/UIEngine/reporting/result.py +128 -0
- ui_engine_xin-0.0.1/UIEngine/runner/__init__.py +3 -0
- ui_engine_xin-0.0.1/UIEngine/runner/runner.py +140 -0
- ui_engine_xin-0.0.1/UIEngine/runner/screenshot_manager.py +67 -0
- ui_engine_xin-0.0.1/pyproject.toml +3 -0
- ui_engine_xin-0.0.1/setup.cfg +4 -0
- ui_engine_xin-0.0.1/setup.py +47 -0
- ui_engine_xin-0.0.1/ui_engine_xin.egg-info/PKG-INFO +239 -0
- ui_engine_xin-0.0.1/ui_engine_xin.egg-info/SOURCES.txt +33 -0
- ui_engine_xin-0.0.1/ui_engine_xin.egg-info/dependency_links.txt +1 -0
- ui_engine_xin-0.0.1/ui_engine_xin.egg-info/requires.txt +6 -0
- ui_engine_xin-0.0.1/ui_engine_xin.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 UIEngine Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ui_engine_xin
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: 基于 Playwright 的关键字驱动 UI 自动化测试引擎
|
|
5
|
+
Home-page: https://pypi.org/project/ui_engine_xin/
|
|
6
|
+
Author: Shawn
|
|
7
|
+
Author-email: xiaoh0525@xiaoh.com
|
|
8
|
+
Keywords: python,playwright,ui-automation,keyword-driven,testing,uiEngine
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Topic :: Software Development :: Testing
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# UIEngine
|
|
26
|
+
|
|
27
|
+
基于 Playwright 的关键字驱动 UI 自动化测试引擎。
|
|
28
|
+
|
|
29
|
+
## 特性
|
|
30
|
+
|
|
31
|
+
- **关键字驱动**:通过中文/英文关键字编写测试用例,降低使用门槛
|
|
32
|
+
- **中英文双注册**:每个关键字同时支持中英文名称,大小写兼容
|
|
33
|
+
- **丰富的内置关键字**:覆盖页面操作、元素交互、等待策略、断言、iframe 等场景
|
|
34
|
+
- **变量替换**:支持 `${variable}` 语法引用全局变量
|
|
35
|
+
- **截图管理**:按套件自动创建截图目录,引擎内最多保留 10 个
|
|
36
|
+
- **灵活配置**:支持 dict 和 YAML 两种配置方式
|
|
37
|
+
|
|
38
|
+
## 安装
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install ui-engine
|
|
42
|
+
playwright install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 快速开始
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from UIEngine import Runner
|
|
49
|
+
|
|
50
|
+
config = {
|
|
51
|
+
"is_debug": True, # True=显示浏览器,False=无头模式
|
|
52
|
+
"browser_type": "chromium",
|
|
53
|
+
"host": "http://localhost:8080",
|
|
54
|
+
"global_variable": {
|
|
55
|
+
"username": "admin",
|
|
56
|
+
"password": "123456"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
suite = {
|
|
61
|
+
"id": "suite_001",
|
|
62
|
+
"name": "登录功能测试",
|
|
63
|
+
"setup_step": [
|
|
64
|
+
{
|
|
65
|
+
"desc": "打开浏览器",
|
|
66
|
+
"keyword": "open_browser",
|
|
67
|
+
"params": {"browser_type": "chromium"}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"desc": "打开登录页",
|
|
71
|
+
"keyword": "打开页面", # 中文关键字同样支持
|
|
72
|
+
"params": {"url": "/login"}
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
"cases": [
|
|
76
|
+
{
|
|
77
|
+
"id": "case_001",
|
|
78
|
+
"name": "正确密码登录",
|
|
79
|
+
"skip": False,
|
|
80
|
+
"steps": [
|
|
81
|
+
{
|
|
82
|
+
"desc": "输入用户名",
|
|
83
|
+
"keyword": "fill_value",
|
|
84
|
+
"params": {"locator": "#username", "value": "${username}"}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"desc": "输入密码",
|
|
88
|
+
"keyword": "输入值", # 中文关键字
|
|
89
|
+
"params": {"locator": "#password", "value": "${password}"}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"desc": "点击登录",
|
|
93
|
+
"keyword": "click_element",
|
|
94
|
+
"params": {"locator": "#login-btn"}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"desc": "验证登录成功",
|
|
98
|
+
"keyword": "except_to_have_text",
|
|
99
|
+
"params": {"locator": ".welcome", "expect_results": "admin"}
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
result = Runner(config).run(suite)
|
|
107
|
+
print(result)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 关键字列表
|
|
111
|
+
|
|
112
|
+
### 页面操作
|
|
113
|
+
|
|
114
|
+
| 英文 | 中文 | 说明 |
|
|
115
|
+
|------|------|------|
|
|
116
|
+
| `open_url` | `打开页面` | 打开 URL |
|
|
117
|
+
| `refresh` | `刷新页面` | 刷新当前页面 |
|
|
118
|
+
| `go_back` | `返回上一页` | 浏览器后退 |
|
|
119
|
+
| `go_forward` | `前进下一页` | 浏览器前进 |
|
|
120
|
+
| `scroll_to_height` | `滚动到高度` | 滚动到指定高度 |
|
|
121
|
+
| `execute_script` | `执行脚本` | 执行 JavaScript |
|
|
122
|
+
| `download_file` | `下载文件` | 触发并等待文件下载 |
|
|
123
|
+
| `accept_dialog` | `接受弹窗` | 接受浏览器弹窗 |
|
|
124
|
+
| `dismiss_dialog` | `关闭弹窗` | 关闭浏览器弹窗 |
|
|
125
|
+
| `get_page_title` | `获取页面标题` | 获取当前页面标题 |
|
|
126
|
+
| `get_page_url` | `获取页面URL` | 获取当前页面 URL |
|
|
127
|
+
| `set_viewport_size` | `设置窗口大小` | 设置浏览器视口大小 |
|
|
128
|
+
|
|
129
|
+
### 元素操作
|
|
130
|
+
|
|
131
|
+
| 英文 | 中文 | 说明 |
|
|
132
|
+
|------|------|------|
|
|
133
|
+
| `click_element` | `点击元素` | 单击元素 |
|
|
134
|
+
| `double_click` | `双击` | 双击元素 |
|
|
135
|
+
| `fill_value` | `输入值` | 输入框填值 |
|
|
136
|
+
| `type_text` | `输入文本` | 模拟逐字符输入 |
|
|
137
|
+
| `clear` | `清空输入框` | 清空输入框 |
|
|
138
|
+
| `hover` | `悬停` | 鼠标悬停 |
|
|
139
|
+
| `focus_element` | `聚焦元素` | 聚焦元素 |
|
|
140
|
+
| `check` | `勾选` | 勾选复选框 |
|
|
141
|
+
| `uncheck` | `取消勾选` | 取消勾选 |
|
|
142
|
+
| `select_option` | `选择选项` | 下拉框选择 |
|
|
143
|
+
| `select_multiple_options` | `多选下拉` | 下拉框多选 |
|
|
144
|
+
| `drag_and_drop` | `拖拽` | 拖拽元素 |
|
|
145
|
+
| `upload_file` | `上传文件` | 上传文件 |
|
|
146
|
+
| `scroll_to_element` | `滚动到元素` | 滚动至元素可见 |
|
|
147
|
+
| `highlight_element` | `高亮元素` | 高亮元素(调试用) |
|
|
148
|
+
| `get_text` | `获取文本` | 获取元素文本 |
|
|
149
|
+
| `get_attribute` | `获取属性` | 获取元素属性 |
|
|
150
|
+
| `get_input_value` | `获取输入值` | 获取输入框值 |
|
|
151
|
+
| `get_element_count` | `获取元素数量` | 获取匹配元素数量 |
|
|
152
|
+
| `is_visible` | `是否可见` | 查询元素可见性 |
|
|
153
|
+
| `is_hidden` | `是否隐藏` | 查询元素隐藏 |
|
|
154
|
+
| `is_enabled` | `是否可用` | 查询元素可用性 |
|
|
155
|
+
| `is_checked` | `是否选中` | 查询元素选中状态 |
|
|
156
|
+
|
|
157
|
+
### 鼠标键盘
|
|
158
|
+
|
|
159
|
+
| 英文 | 中文 | 说明 |
|
|
160
|
+
|------|------|------|
|
|
161
|
+
| `mouse_click` | `鼠标点击` | 坐标点击 |
|
|
162
|
+
| `move_mouse` | `移动鼠标` | 坐标移动 |
|
|
163
|
+
| `long_click` | `长按` | 长按元素 |
|
|
164
|
+
| `right_click` | `右键点击` | 右键点击元素 |
|
|
165
|
+
| `press_key` | `按键` | 键盘按键 |
|
|
166
|
+
| `press_type` | `键盘输入` | 键盘输入文本 |
|
|
167
|
+
|
|
168
|
+
### 等待
|
|
169
|
+
|
|
170
|
+
| 英文 | 中文 | 说明 |
|
|
171
|
+
|------|------|------|
|
|
172
|
+
| `wait_for_time` | `强制等待` | 固定等待 |
|
|
173
|
+
| `wait_for_load` | `等待加载` | 等待页面加载 |
|
|
174
|
+
| `wait_for_network` | `等待网络` | 等待网络空闲 |
|
|
175
|
+
| `wait_for_element` | `等待元素` | 等待元素可见 |
|
|
176
|
+
| `wait_for_element_hidden` | `等待元素消失` | 等待元素不可见 |
|
|
177
|
+
| `wait_for_url` | `等待URL` | 等待 URL 匹配 |
|
|
178
|
+
|
|
179
|
+
### 断言
|
|
180
|
+
|
|
181
|
+
| 英文 | 中文 | 说明 |
|
|
182
|
+
|------|------|------|
|
|
183
|
+
| `assert_page_title` | `断言标题` | 断言页面标题 |
|
|
184
|
+
| `assert_page_url` | `断言URL` | 断言页面 URL |
|
|
185
|
+
| `except_to_have_text` | `断言有文本` | 断言元素文本 |
|
|
186
|
+
| `except_to_have_value` | `断言有值` | 断言元素值 |
|
|
187
|
+
| `except_to_be_visible` | `断言可见` | 断言元素可见 |
|
|
188
|
+
| `except_to_be_hidden` | `断言隐藏` | 断言元素隐藏 |
|
|
189
|
+
| `except_to_be_enabled` | `断言可用` | 断言元素可用 |
|
|
190
|
+
| `except_to_be_checked` | `断言选中` | 断言元素选中 |
|
|
191
|
+
|
|
192
|
+
### iframe
|
|
193
|
+
|
|
194
|
+
| 英文 | 中文 | 说明 |
|
|
195
|
+
|------|------|------|
|
|
196
|
+
| `frame_click_element` | `框架点击` | iframe 内点击 |
|
|
197
|
+
| `frame_fill_value` | `框架输入` | iframe 内输入 |
|
|
198
|
+
| `switch_to_frame` | `切换iframe` | 切换到 iframe |
|
|
199
|
+
| `switch_to_main_frame` | `切回主页面` | 切回主页面 |
|
|
200
|
+
|
|
201
|
+
## 动态注册关键字
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from UIEngine import KeyWordManager
|
|
205
|
+
|
|
206
|
+
# 注册中英文关键字
|
|
207
|
+
KeyWordManager.register_keyword(
|
|
208
|
+
["custom_login", "自定义登录"],
|
|
209
|
+
'''
|
|
210
|
+
def custom_login(self, username, password):
|
|
211
|
+
self.page.locator("#user").fill(username)
|
|
212
|
+
self.page.locator("#pass").fill(password)
|
|
213
|
+
self.page.locator("#submit").click()
|
|
214
|
+
'''
|
|
215
|
+
)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## 配置
|
|
219
|
+
|
|
220
|
+
支持 dict 和 YAML 两种方式:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
# dict 方式
|
|
224
|
+
config = {
|
|
225
|
+
"browser_type": "chromium",
|
|
226
|
+
"is_debug": True,
|
|
227
|
+
"host": "http://localhost:8080",
|
|
228
|
+
"global_variable": {"username": "admin"}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
# YAML 文件方式
|
|
232
|
+
config = "config.yaml"
|
|
233
|
+
|
|
234
|
+
result = Runner(config).run(suite)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
239
|
+
MIT
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# UIEngine
|
|
2
|
+
|
|
3
|
+
基于 Playwright 的关键字驱动 UI 自动化测试引擎。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- **关键字驱动**:通过中文/英文关键字编写测试用例,降低使用门槛
|
|
8
|
+
- **中英文双注册**:每个关键字同时支持中英文名称,大小写兼容
|
|
9
|
+
- **丰富的内置关键字**:覆盖页面操作、元素交互、等待策略、断言、iframe 等场景
|
|
10
|
+
- **变量替换**:支持 `${variable}` 语法引用全局变量
|
|
11
|
+
- **截图管理**:按套件自动创建截图目录,引擎内最多保留 10 个
|
|
12
|
+
- **灵活配置**:支持 dict 和 YAML 两种配置方式
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install ui-engine
|
|
18
|
+
playwright install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 快速开始
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from UIEngine import Runner
|
|
25
|
+
|
|
26
|
+
config = {
|
|
27
|
+
"is_debug": True, # True=显示浏览器,False=无头模式
|
|
28
|
+
"browser_type": "chromium",
|
|
29
|
+
"host": "http://localhost:8080",
|
|
30
|
+
"global_variable": {
|
|
31
|
+
"username": "admin",
|
|
32
|
+
"password": "123456"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
suite = {
|
|
37
|
+
"id": "suite_001",
|
|
38
|
+
"name": "登录功能测试",
|
|
39
|
+
"setup_step": [
|
|
40
|
+
{
|
|
41
|
+
"desc": "打开浏览器",
|
|
42
|
+
"keyword": "open_browser",
|
|
43
|
+
"params": {"browser_type": "chromium"}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"desc": "打开登录页",
|
|
47
|
+
"keyword": "打开页面", # 中文关键字同样支持
|
|
48
|
+
"params": {"url": "/login"}
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
"cases": [
|
|
52
|
+
{
|
|
53
|
+
"id": "case_001",
|
|
54
|
+
"name": "正确密码登录",
|
|
55
|
+
"skip": False,
|
|
56
|
+
"steps": [
|
|
57
|
+
{
|
|
58
|
+
"desc": "输入用户名",
|
|
59
|
+
"keyword": "fill_value",
|
|
60
|
+
"params": {"locator": "#username", "value": "${username}"}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"desc": "输入密码",
|
|
64
|
+
"keyword": "输入值", # 中文关键字
|
|
65
|
+
"params": {"locator": "#password", "value": "${password}"}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"desc": "点击登录",
|
|
69
|
+
"keyword": "click_element",
|
|
70
|
+
"params": {"locator": "#login-btn"}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"desc": "验证登录成功",
|
|
74
|
+
"keyword": "except_to_have_text",
|
|
75
|
+
"params": {"locator": ".welcome", "expect_results": "admin"}
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
result = Runner(config).run(suite)
|
|
83
|
+
print(result)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 关键字列表
|
|
87
|
+
|
|
88
|
+
### 页面操作
|
|
89
|
+
|
|
90
|
+
| 英文 | 中文 | 说明 |
|
|
91
|
+
|------|------|------|
|
|
92
|
+
| `open_url` | `打开页面` | 打开 URL |
|
|
93
|
+
| `refresh` | `刷新页面` | 刷新当前页面 |
|
|
94
|
+
| `go_back` | `返回上一页` | 浏览器后退 |
|
|
95
|
+
| `go_forward` | `前进下一页` | 浏览器前进 |
|
|
96
|
+
| `scroll_to_height` | `滚动到高度` | 滚动到指定高度 |
|
|
97
|
+
| `execute_script` | `执行脚本` | 执行 JavaScript |
|
|
98
|
+
| `download_file` | `下载文件` | 触发并等待文件下载 |
|
|
99
|
+
| `accept_dialog` | `接受弹窗` | 接受浏览器弹窗 |
|
|
100
|
+
| `dismiss_dialog` | `关闭弹窗` | 关闭浏览器弹窗 |
|
|
101
|
+
| `get_page_title` | `获取页面标题` | 获取当前页面标题 |
|
|
102
|
+
| `get_page_url` | `获取页面URL` | 获取当前页面 URL |
|
|
103
|
+
| `set_viewport_size` | `设置窗口大小` | 设置浏览器视口大小 |
|
|
104
|
+
|
|
105
|
+
### 元素操作
|
|
106
|
+
|
|
107
|
+
| 英文 | 中文 | 说明 |
|
|
108
|
+
|------|------|------|
|
|
109
|
+
| `click_element` | `点击元素` | 单击元素 |
|
|
110
|
+
| `double_click` | `双击` | 双击元素 |
|
|
111
|
+
| `fill_value` | `输入值` | 输入框填值 |
|
|
112
|
+
| `type_text` | `输入文本` | 模拟逐字符输入 |
|
|
113
|
+
| `clear` | `清空输入框` | 清空输入框 |
|
|
114
|
+
| `hover` | `悬停` | 鼠标悬停 |
|
|
115
|
+
| `focus_element` | `聚焦元素` | 聚焦元素 |
|
|
116
|
+
| `check` | `勾选` | 勾选复选框 |
|
|
117
|
+
| `uncheck` | `取消勾选` | 取消勾选 |
|
|
118
|
+
| `select_option` | `选择选项` | 下拉框选择 |
|
|
119
|
+
| `select_multiple_options` | `多选下拉` | 下拉框多选 |
|
|
120
|
+
| `drag_and_drop` | `拖拽` | 拖拽元素 |
|
|
121
|
+
| `upload_file` | `上传文件` | 上传文件 |
|
|
122
|
+
| `scroll_to_element` | `滚动到元素` | 滚动至元素可见 |
|
|
123
|
+
| `highlight_element` | `高亮元素` | 高亮元素(调试用) |
|
|
124
|
+
| `get_text` | `获取文本` | 获取元素文本 |
|
|
125
|
+
| `get_attribute` | `获取属性` | 获取元素属性 |
|
|
126
|
+
| `get_input_value` | `获取输入值` | 获取输入框值 |
|
|
127
|
+
| `get_element_count` | `获取元素数量` | 获取匹配元素数量 |
|
|
128
|
+
| `is_visible` | `是否可见` | 查询元素可见性 |
|
|
129
|
+
| `is_hidden` | `是否隐藏` | 查询元素隐藏 |
|
|
130
|
+
| `is_enabled` | `是否可用` | 查询元素可用性 |
|
|
131
|
+
| `is_checked` | `是否选中` | 查询元素选中状态 |
|
|
132
|
+
|
|
133
|
+
### 鼠标键盘
|
|
134
|
+
|
|
135
|
+
| 英文 | 中文 | 说明 |
|
|
136
|
+
|------|------|------|
|
|
137
|
+
| `mouse_click` | `鼠标点击` | 坐标点击 |
|
|
138
|
+
| `move_mouse` | `移动鼠标` | 坐标移动 |
|
|
139
|
+
| `long_click` | `长按` | 长按元素 |
|
|
140
|
+
| `right_click` | `右键点击` | 右键点击元素 |
|
|
141
|
+
| `press_key` | `按键` | 键盘按键 |
|
|
142
|
+
| `press_type` | `键盘输入` | 键盘输入文本 |
|
|
143
|
+
|
|
144
|
+
### 等待
|
|
145
|
+
|
|
146
|
+
| 英文 | 中文 | 说明 |
|
|
147
|
+
|------|------|------|
|
|
148
|
+
| `wait_for_time` | `强制等待` | 固定等待 |
|
|
149
|
+
| `wait_for_load` | `等待加载` | 等待页面加载 |
|
|
150
|
+
| `wait_for_network` | `等待网络` | 等待网络空闲 |
|
|
151
|
+
| `wait_for_element` | `等待元素` | 等待元素可见 |
|
|
152
|
+
| `wait_for_element_hidden` | `等待元素消失` | 等待元素不可见 |
|
|
153
|
+
| `wait_for_url` | `等待URL` | 等待 URL 匹配 |
|
|
154
|
+
|
|
155
|
+
### 断言
|
|
156
|
+
|
|
157
|
+
| 英文 | 中文 | 说明 |
|
|
158
|
+
|------|------|------|
|
|
159
|
+
| `assert_page_title` | `断言标题` | 断言页面标题 |
|
|
160
|
+
| `assert_page_url` | `断言URL` | 断言页面 URL |
|
|
161
|
+
| `except_to_have_text` | `断言有文本` | 断言元素文本 |
|
|
162
|
+
| `except_to_have_value` | `断言有值` | 断言元素值 |
|
|
163
|
+
| `except_to_be_visible` | `断言可见` | 断言元素可见 |
|
|
164
|
+
| `except_to_be_hidden` | `断言隐藏` | 断言元素隐藏 |
|
|
165
|
+
| `except_to_be_enabled` | `断言可用` | 断言元素可用 |
|
|
166
|
+
| `except_to_be_checked` | `断言选中` | 断言元素选中 |
|
|
167
|
+
|
|
168
|
+
### iframe
|
|
169
|
+
|
|
170
|
+
| 英文 | 中文 | 说明 |
|
|
171
|
+
|------|------|------|
|
|
172
|
+
| `frame_click_element` | `框架点击` | iframe 内点击 |
|
|
173
|
+
| `frame_fill_value` | `框架输入` | iframe 内输入 |
|
|
174
|
+
| `switch_to_frame` | `切换iframe` | 切换到 iframe |
|
|
175
|
+
| `switch_to_main_frame` | `切回主页面` | 切回主页面 |
|
|
176
|
+
|
|
177
|
+
## 动态注册关键字
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from UIEngine import KeyWordManager
|
|
181
|
+
|
|
182
|
+
# 注册中英文关键字
|
|
183
|
+
KeyWordManager.register_keyword(
|
|
184
|
+
["custom_login", "自定义登录"],
|
|
185
|
+
'''
|
|
186
|
+
def custom_login(self, username, password):
|
|
187
|
+
self.page.locator("#user").fill(username)
|
|
188
|
+
self.page.locator("#pass").fill(password)
|
|
189
|
+
self.page.locator("#submit").click()
|
|
190
|
+
'''
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 配置
|
|
195
|
+
|
|
196
|
+
支持 dict 和 YAML 两种方式:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
# dict 方式
|
|
200
|
+
config = {
|
|
201
|
+
"browser_type": "chromium",
|
|
202
|
+
"is_debug": True,
|
|
203
|
+
"host": "http://localhost:8080",
|
|
204
|
+
"global_variable": {"username": "admin"}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# YAML 文件方式
|
|
208
|
+
config = "config.yaml"
|
|
209
|
+
|
|
210
|
+
result = Runner(config).run(suite)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""UIEngine - 基于 Playwright 的关键字驱动 UI 自动化测试引擎"""
|
|
2
|
+
__version__ = "0.0.1"
|
|
3
|
+
|
|
4
|
+
from UIEngine.basecase import BaseCase
|
|
5
|
+
from UIEngine.core.keyword_manager import KeyWordManager
|
|
6
|
+
from UIEngine.core.variable_resolver import VariableResolver
|
|
7
|
+
from UIEngine.runner.runner import Runner
|
|
8
|
+
from UIEngine.reporting.result import TestResult
|
|
9
|
+
from UIEngine.caseLog import CaseLogHandler
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""BaseCase 组合类
|
|
2
|
+
|
|
3
|
+
将所有 Mixin 组合为统一的测试用例基类。
|
|
4
|
+
包含关键字调度(perform)和变量替换功能。
|
|
5
|
+
所有 Mixin 方法在类定义后自动注册到 KeyWordManager。
|
|
6
|
+
"""
|
|
7
|
+
from UIEngine.browser.base_browser import BaseBrowser
|
|
8
|
+
from UIEngine.keywords.page_keywords import PageMixin
|
|
9
|
+
from UIEngine.keywords.locator_keywords import LocatorMixin
|
|
10
|
+
from UIEngine.keywords.mouse_keywords import MouseMixin
|
|
11
|
+
from UIEngine.keywords.wait_keywords import WaitMixin
|
|
12
|
+
from UIEngine.keywords.iframe_keywords import IFrameMixin
|
|
13
|
+
from UIEngine.keywords.assert_keywords import AssertMixin
|
|
14
|
+
from UIEngine.core.keyword_manager import KeyWordManager
|
|
15
|
+
from UIEngine.core.variable_resolver import VariableResolver
|
|
16
|
+
from UIEngine.core.exceptions import KeywordNotFoundError
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BaseCase(PageMixin, LocatorMixin, MouseMixin, WaitMixin, IFrameMixin, AssertMixin):
|
|
20
|
+
"""测试用例基类 - 组合所有关键字 Mixin
|
|
21
|
+
|
|
22
|
+
继承链(MRO):
|
|
23
|
+
BaseCase → PageMixin → LocatorMixin → MouseMixin → WaitMixin
|
|
24
|
+
→ IFrameMixin → AssertMixin → BaseBrowser
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, config, log, **kwargs):
|
|
28
|
+
super().__init__(config, log, **kwargs)
|
|
29
|
+
self.variable_resolver = VariableResolver(config, log)
|
|
30
|
+
|
|
31
|
+
def perform(self, step):
|
|
32
|
+
"""执行测试步骤
|
|
33
|
+
|
|
34
|
+
支持两种执行模式:
|
|
35
|
+
1. 关键字模式:通过 KeyWordManager.maps 查表调用(step 中使用 "keyword" 或 "method")
|
|
36
|
+
2. 直接调用模式:关键字未注册时,回退到 getattr(self, method) 直接调用
|
|
37
|
+
|
|
38
|
+
模式 2 允许调用未注册为关键字的实例方法(如 open_browser, close, reset_browser_context 等)。
|
|
39
|
+
|
|
40
|
+
:param step: 测试步骤字典,包含 keyword/method、params、desc 等字段
|
|
41
|
+
"""
|
|
42
|
+
keyword = step.get("keyword") or step.get("method")
|
|
43
|
+
# 优先通过关键字注册表查找
|
|
44
|
+
method = KeyWordManager.get_keyword_maps(keyword)
|
|
45
|
+
if method:
|
|
46
|
+
params = step.get("params", {})
|
|
47
|
+
params = self.variable_resolver.resolve(params)
|
|
48
|
+
method(self, **params)
|
|
49
|
+
elif hasattr(self, keyword):
|
|
50
|
+
# 回退:直接调用实例方法(兼容未注册为关键字的方法)
|
|
51
|
+
params = step.get("params", {})
|
|
52
|
+
params = self.variable_resolver.resolve(params)
|
|
53
|
+
getattr(self, keyword)(**params)
|
|
54
|
+
else:
|
|
55
|
+
raise KeywordNotFoundError(f"{step.get('desc', '')}执行的关键字 '{keyword}' 不存在")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# 自动注册:将 BaseCase 的所有公共方法注册到关键字映射表
|
|
59
|
+
# 已通过 @register 装饰器注册的方法不会被覆盖
|
|
60
|
+
KeyWordManager.auto_register_methods(BaseCase)
|