mangoautomation 1.1.23__py3-none-any.whl → 1.1.25__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.
Potentially problematic release.
This version of mangoautomation might be problematic. Click here for more details.
- mangoautomation/mangos/__pycache__/__init__.cpython-310.pyc +0 -0
- mangoautomation/mangos/mangos.cp310-win_amd64.pyd +0 -0
- mangoautomation/mangos/mangos.cp312-win_amd64.pyd +0 -0
- mangoautomation/mangos/mangos.cpython-310-darwin.so +0 -0
- mangoautomation/mangos/mangos.cpython-310-x86_64-linux-gnu.so +0 -0
- mangoautomation/mangos/mangos.cpython-312-darwin.so +0 -0
- mangoautomation/mangos/mangos.cpython-312-x86_64-linux-gnu.so +0 -0
- mangoautomation/uidrives/_driver_object.py +5 -36
- mangoautomation-1.1.25.dist-info/METADATA +42 -0
- mangoautomation-1.1.25.dist-info/RECORD +48 -0
- {mangoautomation-1.1.23.dist-info → mangoautomation-1.1.25.dist-info}/WHEEL +1 -1
- tests/demo1.py +94 -21
- tests/get_ope.py +12 -3
- mangoautomation/uidrives/android/_application.py +0 -70
- mangoautomation/uidrives/android/_assertion.py +0 -90
- mangoautomation/uidrives/android/_customization.py +0 -15
- mangoautomation/uidrives/android/_element.py +0 -169
- mangoautomation/uidrives/android/_equipment.py +0 -151
- mangoautomation/uidrives/android/_new_android.py +0 -54
- mangoautomation/uidrives/android/_page.py +0 -116
- mangoautomation/uidrives/web/async_web/__init__.py +0 -165
- mangoautomation/uidrives/web/async_web/_assertion.py +0 -303
- mangoautomation/uidrives/web/async_web/_browser.py +0 -112
- mangoautomation/uidrives/web/async_web/_customization.py +0 -14
- mangoautomation/uidrives/web/async_web/_element.py +0 -240
- mangoautomation/uidrives/web/async_web/_input_device.py +0 -82
- mangoautomation/uidrives/web/async_web/_new_browser.py +0 -153
- mangoautomation/uidrives/web/async_web/_page.py +0 -63
- mangoautomation/uidrives/web/sync_web/__init__.py +0 -160
- mangoautomation/uidrives/web/sync_web/_assertion.py +0 -304
- mangoautomation/uidrives/web/sync_web/_browser.py +0 -112
- mangoautomation/uidrives/web/sync_web/_customization.py +0 -14
- mangoautomation/uidrives/web/sync_web/_element.py +0 -240
- mangoautomation/uidrives/web/sync_web/_input_device.py +0 -80
- mangoautomation/uidrives/web/sync_web/_new_browser.py +0 -153
- mangoautomation/uidrives/web/sync_web/_page.py +0 -61
- mangoautomation-1.1.23.dist-info/METADATA +0 -34
- mangoautomation-1.1.23.dist-info/RECORD +0 -71
- {mangoautomation-1.1.23.dist-info → mangoautomation-1.1.25.dist-info/licenses}/LICENSE +0 -0
- {mangoautomation-1.1.23.dist-info → mangoautomation-1.1.25.dist-info}/top_level.txt +0 -0
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# @Project: 芒果测试平台
|
|
3
|
-
# @Description: # @Time : 2023-04-26 22:25
|
|
4
|
-
# @Author : 毛鹏
|
|
5
|
-
|
|
6
|
-
from playwright.async_api import Locator, expect as exp
|
|
7
|
-
|
|
8
|
-
from mangotools.decorator import async_method_callback
|
|
9
|
-
from mangotools.models import MethodModel
|
|
10
|
-
from ....exceptions import MangoAutomationError
|
|
11
|
-
from ....exceptions.error_msg import ERROR_MSG_0021
|
|
12
|
-
from ....tools import Meta
|
|
13
|
-
from ....uidrives._base_data import BaseData
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class AsyncWebAssertion(metaclass=Meta):
|
|
17
|
-
"""元素断言"""
|
|
18
|
-
|
|
19
|
-
def __init__(self, base_data: BaseData):
|
|
20
|
-
self.base_data = base_data
|
|
21
|
-
|
|
22
|
-
@async_method_callback('ass_web', '元素断言', 0, [
|
|
23
|
-
MethodModel(f='actual'),
|
|
24
|
-
MethodModel(n='预期值', f='expect', p='请输入元素个数', d=True)])
|
|
25
|
-
async def w_to_have_count(self, actual: Locator, expect: str):
|
|
26
|
-
"""元素是几个"""
|
|
27
|
-
try:
|
|
28
|
-
await exp(actual).to_have_count(int(expect))
|
|
29
|
-
except AssertionError as e:
|
|
30
|
-
raise AssertionError(f'实际={await actual.count()}, 预期={expect}') from e
|
|
31
|
-
return f'实际={await actual.count()}, 预期={expect}'
|
|
32
|
-
|
|
33
|
-
@async_method_callback('ass_web', '元素断言', 1, [MethodModel(f='actual')])
|
|
34
|
-
async def w_all_not_to_be_empty(self, actual: Locator):
|
|
35
|
-
"""元素存在"""
|
|
36
|
-
count = await actual.count()
|
|
37
|
-
if count == 0:
|
|
38
|
-
assert False, f'实际={count}, 预期>0'
|
|
39
|
-
return f'实际={count}, 预期>0'
|
|
40
|
-
|
|
41
|
-
@async_method_callback('ass_web', '元素断言', 1, [
|
|
42
|
-
MethodModel(f='actual'),
|
|
43
|
-
MethodModel(n='预期值', f='expect', p='请输入元素存输入1,不存输入0', d=True)])
|
|
44
|
-
async def w_to_element_count(self, actual: Locator, expect: int):
|
|
45
|
-
"""元素是否存在"""
|
|
46
|
-
if int(expect) == 0:
|
|
47
|
-
assert actual is None, f'实际={actual}, 预期={expect}'
|
|
48
|
-
return f'实际={actual}, 预期={expect}'
|
|
49
|
-
|
|
50
|
-
else:
|
|
51
|
-
if actual:
|
|
52
|
-
try:
|
|
53
|
-
await exp(actual).to_have_count(int(expect))
|
|
54
|
-
return f'实际={actual.count()}, 预期={expect}'
|
|
55
|
-
except AssertionError as e:
|
|
56
|
-
raise AssertionError(f'实际={actual.count()}, 预期={expect}') from e
|
|
57
|
-
else:
|
|
58
|
-
raise MangoAutomationError(*ERROR_MSG_0021)
|
|
59
|
-
|
|
60
|
-
@async_method_callback('ass_web', '元素断言', 2, [
|
|
61
|
-
MethodModel(f='actual'),
|
|
62
|
-
MethodModel(n='预期值', f='expect', p='请输入不包含的文本', d=True)])
|
|
63
|
-
async def w_not_to_contain_text(self, actual: Locator, expect: str):
|
|
64
|
-
"""元素不包含文本"""
|
|
65
|
-
try:
|
|
66
|
-
await exp(actual).not_to_contain_text(expect)
|
|
67
|
-
except AssertionError as e:
|
|
68
|
-
raise AssertionError(f'实际={actual}, 预期={expect}') from e
|
|
69
|
-
return f'实际={actual}, 预期={expect}'
|
|
70
|
-
|
|
71
|
-
@async_method_callback('ass_web', '元素断言', 3, [MethodModel(f='actual')])
|
|
72
|
-
async def w_not_to_be_empty(self, actual: Locator):
|
|
73
|
-
"""元素不为空"""
|
|
74
|
-
try:
|
|
75
|
-
await exp(actual).not_to_be_empty()
|
|
76
|
-
except AssertionError as e:
|
|
77
|
-
raise AssertionError(f'实际={actual}, 预期=不为空') from e
|
|
78
|
-
return f'实际={actual}, 预期=不为空'
|
|
79
|
-
|
|
80
|
-
@async_method_callback('ass_web', '元素断言', 4, [MethodModel(f='actual')])
|
|
81
|
-
async def w_not_to_be_enabled(self, actual: Locator):
|
|
82
|
-
"""元素不启用"""
|
|
83
|
-
try:
|
|
84
|
-
await exp(actual).not_to_be_enabled()
|
|
85
|
-
except AssertionError as e:
|
|
86
|
-
raise AssertionError(f'实际={actual}, 预期=不启用') from e
|
|
87
|
-
return f'实际={actual}, 预期=不启用'
|
|
88
|
-
|
|
89
|
-
@async_method_callback('ass_web', '元素断言', 5, [MethodModel(f='actual')])
|
|
90
|
-
async def w_not_to_be_focused(self, actual: Locator):
|
|
91
|
-
"""元素不聚焦"""
|
|
92
|
-
try:
|
|
93
|
-
await exp(actual).not_to_be_focused()
|
|
94
|
-
except AssertionError as e:
|
|
95
|
-
raise AssertionError(f'实际={actual}, 预期=不聚焦') from e
|
|
96
|
-
return f'实际={actual}, 预期=不聚焦'
|
|
97
|
-
|
|
98
|
-
@async_method_callback('ass_web', '元素断言', 6, [MethodModel(f='actual')])
|
|
99
|
-
async def w_not_to_be_hidden(self, actual: Locator):
|
|
100
|
-
"""元素不可隐藏"""
|
|
101
|
-
try:
|
|
102
|
-
await exp(actual).not_to_be_hidden()
|
|
103
|
-
except AssertionError as e:
|
|
104
|
-
raise AssertionError(f'实际={actual}, 预期=不可隐藏') from e
|
|
105
|
-
return f'实际={actual}, 预期=不可隐藏'
|
|
106
|
-
|
|
107
|
-
@async_method_callback('ass_web', '元素断言', 7, [MethodModel(f='actual')])
|
|
108
|
-
async def w_not_to_be_in_viewport(self, actual: Locator):
|
|
109
|
-
"""元素不在视窗中"""
|
|
110
|
-
try:
|
|
111
|
-
await exp(actual).not_to_be_in_viewport()
|
|
112
|
-
except AssertionError as e:
|
|
113
|
-
raise AssertionError(f'实际={actual}, 预期=不在视窗中') from e
|
|
114
|
-
return f'实际={actual}, 预期=不在视窗中'
|
|
115
|
-
|
|
116
|
-
@async_method_callback('ass_web', '元素断言', 8, [MethodModel(f='actual')])
|
|
117
|
-
async def w_not_to_be_visible(self, actual: Locator):
|
|
118
|
-
"""元素不可见"""
|
|
119
|
-
try:
|
|
120
|
-
await exp(actual).not_to_be_visible()
|
|
121
|
-
except AssertionError as e:
|
|
122
|
-
raise AssertionError(f'实际={actual}, 预期=不可见') from e
|
|
123
|
-
return f'实际={actual}, 预期=不可见'
|
|
124
|
-
|
|
125
|
-
@async_method_callback('ass_web', '元素断言', 9, [
|
|
126
|
-
MethodModel(f='actual'),
|
|
127
|
-
MethodModel(n='预期值', f='expect', p='请输入样式', d=True)])
|
|
128
|
-
async def w_not_to_have_class(self, actual: Locator, expect: str):
|
|
129
|
-
"""元素没有阶级"""
|
|
130
|
-
try:
|
|
131
|
-
await exp(actual).not_to_have_class(expect)
|
|
132
|
-
except AssertionError as e:
|
|
133
|
-
raise AssertionError(f'实际={actual}, 预期=没有阶级') from e
|
|
134
|
-
return f'实际={actual}, 预期=没有阶级'
|
|
135
|
-
|
|
136
|
-
@async_method_callback('ass_web', '元素断言', 10, [MethodModel(f='actual')])
|
|
137
|
-
async def w_to_be_checked(self, actual: Locator):
|
|
138
|
-
"""复选框已选中"""
|
|
139
|
-
try:
|
|
140
|
-
await exp(actual).to_be_checked()
|
|
141
|
-
except AssertionError as e:
|
|
142
|
-
raise AssertionError(f'实际={actual}, 预期=复选框已选中') from e
|
|
143
|
-
return f'实际={actual}, 预期=复选框已选中'
|
|
144
|
-
|
|
145
|
-
@async_method_callback('ass_web', '元素断言', 11, [MethodModel(f='actual')])
|
|
146
|
-
async def w_to_be_disabled(self, actual: Locator):
|
|
147
|
-
"""元素已禁用"""
|
|
148
|
-
try:
|
|
149
|
-
await exp(actual).to_be_disabled()
|
|
150
|
-
except AssertionError as e:
|
|
151
|
-
raise AssertionError(f'实际={actual}, 预期=已禁用') from e
|
|
152
|
-
return f'实际={actual}, 预期=已禁用'
|
|
153
|
-
|
|
154
|
-
@async_method_callback('ass_web', '元素断言', 12, [MethodModel(f='actual')])
|
|
155
|
-
async def w_not_to_be_editable(self, actual: Locator):
|
|
156
|
-
"""元素已启用"""
|
|
157
|
-
try:
|
|
158
|
-
await exp(actual).to_be_editable()
|
|
159
|
-
except AssertionError as e:
|
|
160
|
-
raise AssertionError(f'实际={actual}, 预期=已启用') from e
|
|
161
|
-
return f'实际={actual}, 预期=已启用'
|
|
162
|
-
|
|
163
|
-
@async_method_callback('ass_web', '元素断言', 13, [MethodModel(f='actual')])
|
|
164
|
-
async def w_to_be_empty(self, actual: Locator | list | None):
|
|
165
|
-
"""元素为空"""
|
|
166
|
-
if actual is None:
|
|
167
|
-
assert True, f'实际={actual}, 预期=为空'
|
|
168
|
-
return f'实际={actual}, 预期=为空'
|
|
169
|
-
else:
|
|
170
|
-
try:
|
|
171
|
-
await exp(actual).to_be_empty()
|
|
172
|
-
return f'实际={actual}, 预期=为空'
|
|
173
|
-
except AssertionError as e:
|
|
174
|
-
raise AssertionError(f'实际={actual}, 预期=为空') from e
|
|
175
|
-
|
|
176
|
-
@async_method_callback('ass_web', '元素断言', 14, [MethodModel(f='actual')])
|
|
177
|
-
async def w_to_be_visible(self, actual: Locator):
|
|
178
|
-
"""元素可见"""
|
|
179
|
-
try:
|
|
180
|
-
await exp(actual).to_be_visible()
|
|
181
|
-
except AssertionError as e:
|
|
182
|
-
raise AssertionError(f'实际={actual}, 预期=可见') from e
|
|
183
|
-
return f'实际={actual}, 预期=可见'
|
|
184
|
-
# @staticmethod
|
|
185
|
-
# async def w_not_to_have_actuals(actual: Locator, actuals: list):
|
|
186
|
-
# """选择已选择选项"""
|
|
187
|
-
# await exp(actual).to_have_actuals(actuals)
|
|
188
|
-
|
|
189
|
-
# @staticmethod
|
|
190
|
-
# def w_not_to_have_attribute(locating: Locator, name: str, actual: str):
|
|
191
|
-
# """元素不具有属性"""
|
|
192
|
-
# exp(locating).not_to_have_attribute(name, actual)
|
|
193
|
-
# @staticmethod
|
|
194
|
-
|
|
195
|
-
# @staticmethod
|
|
196
|
-
# def w_not_to_have_css(locating: Locator, name: str, actual: str):
|
|
197
|
-
# """元素不使用CSS"""
|
|
198
|
-
# exp(locating).not_to_have_css(name, actual)
|
|
199
|
-
|
|
200
|
-
# @staticmethod
|
|
201
|
-
# def w_not_to_have_id(locating: Locator, _id: str):
|
|
202
|
-
# """元素没有ID"""
|
|
203
|
-
# exp(locating).not_to_have_id(_id)
|
|
204
|
-
#
|
|
205
|
-
# @staticmethod
|
|
206
|
-
# def w_not_to_have_js_property(locating: Locator, name: str, actual):
|
|
207
|
-
# """元素不具有js属性"""
|
|
208
|
-
# exp(locating).not_to_have_js_property(name, actual)
|
|
209
|
-
#
|
|
210
|
-
# @staticmethod
|
|
211
|
-
# def w_not_to_have_text(locating: Locator, expected: str):
|
|
212
|
-
# """元素没有文本"""
|
|
213
|
-
# exp(locating).not_to_have_text(expected)
|
|
214
|
-
|
|
215
|
-
# @staticmethod
|
|
216
|
-
# def w_not_to_have_actual(locating: Locator, actual: str):
|
|
217
|
-
# """元素无价值"""
|
|
218
|
-
# exp(locating).not_to_have_actual(actual)
|
|
219
|
-
|
|
220
|
-
#
|
|
221
|
-
# def w_to_be_attached(self, hidden_text: str):
|
|
222
|
-
# """待连接"""
|
|
223
|
-
# exp(self.page.get_by_text(hidden_text)).to_be_attached()
|
|
224
|
-
|
|
225
|
-
#
|
|
226
|
-
# def w_to_be_editable(self, hidden_text: str):
|
|
227
|
-
# """可编辑"""
|
|
228
|
-
# locator = self.page.get_by_role("textbox")
|
|
229
|
-
# exp(locator).to_be_editable()
|
|
230
|
-
|
|
231
|
-
# def w_to_be_enabled(self, hidden_text: str):
|
|
232
|
-
# """为空"""
|
|
233
|
-
# locator = self.page.locator("button.submit")
|
|
234
|
-
# exp(locator).to_be_enabled()
|
|
235
|
-
|
|
236
|
-
# def w_to_be_focused(self, hidden_text: str):
|
|
237
|
-
# """聚焦"""
|
|
238
|
-
# locator = self.page.get_by_role("textbox")
|
|
239
|
-
# exp(locator).to_be_focused()
|
|
240
|
-
#
|
|
241
|
-
# def w_to_be_hidden(self, hidden_text: str):
|
|
242
|
-
# """隐藏"""
|
|
243
|
-
# locator = self.page.locator('.my-element')
|
|
244
|
-
# exp(locator).to_be_hidden()
|
|
245
|
-
#
|
|
246
|
-
# def w_to_be_in_viewport(self, hidden_text: str):
|
|
247
|
-
# """待在视口中"""
|
|
248
|
-
# locator = self.page.get_by_role("button")
|
|
249
|
-
# # Make sure at least some part of element intersects viewport.
|
|
250
|
-
# exp(locator).to_be_in_viewport()
|
|
251
|
-
# # Make sure element is fully outside of viewport.
|
|
252
|
-
# exp(locator).not_to_be_in_viewport()
|
|
253
|
-
# # Make sure that at least half of the element intersects viewport.
|
|
254
|
-
# exp(locator).to_be_in_viewport(ratio=0.5)
|
|
255
|
-
#
|
|
256
|
-
|
|
257
|
-
# def w_to_contain_text(self, hidden_text: str):
|
|
258
|
-
# """包含文本"""
|
|
259
|
-
# locator = self.page.locator('.title')
|
|
260
|
-
# exp(locator).to_contain_text("substring")
|
|
261
|
-
# exp(locator).to_contain_text(re.compile(r"\d messages"))
|
|
262
|
-
#
|
|
263
|
-
# def w_to_have_attribute(self, hidden_text: str):
|
|
264
|
-
# """具有属性"""
|
|
265
|
-
# locator = self.page.locator("input")
|
|
266
|
-
# exp(locator).to_have_attribute("type", "text")
|
|
267
|
-
#
|
|
268
|
-
# def w_to_have_class(self, hidden_text: str):
|
|
269
|
-
# """到保存类别"""
|
|
270
|
-
# locator = self.page.locator("#component")
|
|
271
|
-
# exp(locator).to_have_class(re.compile(r"selected"))
|
|
272
|
-
# exp(locator).to_have_class("selected row")
|
|
273
|
-
#
|
|
274
|
-
# def w_to_have_count(self, hidden_text: str):
|
|
275
|
-
# """有计数"""
|
|
276
|
-
# locator = self.page.locator("list > .component")
|
|
277
|
-
# exp(locator).to_have_count(3)
|
|
278
|
-
#
|
|
279
|
-
# def w_to_have_css(self, hidden_text: str):
|
|
280
|
-
# """使用CSS"""
|
|
281
|
-
# locator = self.page.get_by_role("button")
|
|
282
|
-
# exp(locator).to_have_css("display", "flex")
|
|
283
|
-
#
|
|
284
|
-
# def w_to_have_id(self, hidden_text: str):
|
|
285
|
-
# """到id"""
|
|
286
|
-
# locator = self.page.get_by_role("textbox")
|
|
287
|
-
# exp(locator).to_have_id("lastname")
|
|
288
|
-
#
|
|
289
|
-
# def w_to_have_js_property(self, hidden_text: str):
|
|
290
|
-
# """拥有js属性"""
|
|
291
|
-
# locator = self.page.locator(".component")
|
|
292
|
-
# exp(locator).to_have_js_property("loaded", True)
|
|
293
|
-
#
|
|
294
|
-
# def w_to_have_text(self, hidden_text: str):
|
|
295
|
-
# """有文本"""
|
|
296
|
-
# locator = self.page.locator(".title")
|
|
297
|
-
# exp(locator).to_have_text(re.compile(r"Welcome, Test User"))
|
|
298
|
-
# exp(locator).to_have_text(re.compile(r"Welcome, .*"))
|
|
299
|
-
#
|
|
300
|
-
# def w_to_have_actual(self, hidden_text: str):
|
|
301
|
-
# """有价值"""
|
|
302
|
-
# locator = self.page.locator("input[type=number]")
|
|
303
|
-
# exp(locator).to_have_actual(re.compile(r"[0-9]"))
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# @Project: 芒果测试平台
|
|
3
|
-
# @Description: # @Time : 2023-04-25 22:33
|
|
4
|
-
# @Author : 毛鹏
|
|
5
|
-
import asyncio
|
|
6
|
-
import json
|
|
7
|
-
import os.path
|
|
8
|
-
import traceback
|
|
9
|
-
from urllib.parse import urlparse
|
|
10
|
-
|
|
11
|
-
from playwright._impl._errors import TimeoutError, Error, TargetClosedError
|
|
12
|
-
|
|
13
|
-
from mangotools.decorator import async_method_callback
|
|
14
|
-
from mangotools.models import MethodModel
|
|
15
|
-
from ..._base_data import BaseData
|
|
16
|
-
from ....exceptions import MangoAutomationError
|
|
17
|
-
from ....exceptions.error_msg import ERROR_MSG_0049, ERROR_MSG_0013, ERROR_MSG_0058, ERROR_MSG_0059, ERROR_MSG_0010
|
|
18
|
-
from ....tools import Meta
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class AsyncWebBrowser(metaclass=Meta):
|
|
22
|
-
"""浏览器操作"""
|
|
23
|
-
|
|
24
|
-
def __init__(self, base_data: BaseData):
|
|
25
|
-
self.base_data = base_data
|
|
26
|
-
|
|
27
|
-
@async_method_callback('web', '浏览器操作', 0, [
|
|
28
|
-
MethodModel(n='等待时间', f='_time', p='请输入等待时间', d=True)])
|
|
29
|
-
async def w_wait_for_timeout(self, _time: int):
|
|
30
|
-
"""强制等待"""
|
|
31
|
-
await asyncio.sleep(int(_time))
|
|
32
|
-
|
|
33
|
-
@async_method_callback('web', '浏览器操作', 1, [
|
|
34
|
-
MethodModel(n='url地址', f='url', p='请输入URL', d=True)])
|
|
35
|
-
async def w_goto(self, url: str):
|
|
36
|
-
"""打开URL"""
|
|
37
|
-
try:
|
|
38
|
-
result = urlparse(url)
|
|
39
|
-
if not all([result.scheme, result.netloc]):
|
|
40
|
-
raise MangoAutomationError(*ERROR_MSG_0049)
|
|
41
|
-
await self.base_data.page.goto(url, timeout=60000)
|
|
42
|
-
await asyncio.sleep(2)
|
|
43
|
-
except TimeoutError as error:
|
|
44
|
-
self.base_data.log.debug(f'打开URL失败-1,类型:{type(error)},失败详情:{error}')
|
|
45
|
-
raise MangoAutomationError(*ERROR_MSG_0013, value=(url,))
|
|
46
|
-
except TargetClosedError as error:
|
|
47
|
-
self.base_data.setup()
|
|
48
|
-
self.base_data.log.debug(f'打开URL失败-2,类型:{type(error)},失败详情:{error}')
|
|
49
|
-
raise MangoAutomationError(*ERROR_MSG_0010, value=(url,))
|
|
50
|
-
except Error as error:
|
|
51
|
-
self.base_data.log.debug(
|
|
52
|
-
f'打开URL失败-2,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
|
|
53
|
-
raise MangoAutomationError(*ERROR_MSG_0058, value=(url,))
|
|
54
|
-
|
|
55
|
-
@async_method_callback('web', '浏览器操作', 2, [
|
|
56
|
-
MethodModel(n='存储路径', f='path', p='请输入截图名称', d=True)])
|
|
57
|
-
async def w_screenshot(self, path: str):
|
|
58
|
-
"""整个页面截图"""
|
|
59
|
-
try:
|
|
60
|
-
await self.base_data.page.screenshot(path=os.path.join(self.base_data.screenshot_path, path), full_page=True, timeout=10000)
|
|
61
|
-
except (TargetClosedError, TimeoutError) as error:
|
|
62
|
-
self.base_data.log.debug(
|
|
63
|
-
f'截图出现异常失败-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
|
|
64
|
-
self.base_data.setup()
|
|
65
|
-
raise MangoAutomationError(*ERROR_MSG_0010)
|
|
66
|
-
except AttributeError as error:
|
|
67
|
-
self.base_data.log.debug(
|
|
68
|
-
f'截图出现异常失败-2,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
|
|
69
|
-
self.base_data.setup()
|
|
70
|
-
raise MangoAutomationError(*ERROR_MSG_0010)
|
|
71
|
-
|
|
72
|
-
@async_method_callback('web', '浏览器操作', 3)
|
|
73
|
-
async def w_alert(self):
|
|
74
|
-
"""设置弹窗不予处理"""
|
|
75
|
-
self.base_data.page.on("dialog", lambda dialog: dialog.accept())
|
|
76
|
-
|
|
77
|
-
@async_method_callback('web', '浏览器操作', 4)
|
|
78
|
-
async def w_get_cookie(self):
|
|
79
|
-
"""获取cookie"""
|
|
80
|
-
with open(os.path.join(self.base_data.download_path, 'storage_state.json'), 'w') as file:
|
|
81
|
-
file.write(json.dumps(await self.base_data.context.storage_state()))
|
|
82
|
-
|
|
83
|
-
@async_method_callback('web', '浏览器操作', 5, [
|
|
84
|
-
MethodModel(n='获取cookie方法的值', f='storage_state', p='请输入获取cookie方法中获取的内容', d=True)])
|
|
85
|
-
async def w_set_cookie(self, storage_state: str):
|
|
86
|
-
"""设置cookie"""
|
|
87
|
-
if isinstance(storage_state, str):
|
|
88
|
-
storage_state = json.loads(storage_state)
|
|
89
|
-
else:
|
|
90
|
-
raise MangoAutomationError(*ERROR_MSG_0059)
|
|
91
|
-
await self.base_data.context.add_cookies(storage_state['cookies'])
|
|
92
|
-
for storage in storage_state['origins']:
|
|
93
|
-
local_storage = storage.get('localStorage', [])
|
|
94
|
-
session_storage = storage.get('sessionStorage', [])
|
|
95
|
-
for item in local_storage:
|
|
96
|
-
await self.base_data.context.add_init_script(
|
|
97
|
-
f"window.localStorage.setItem('{item['name']}', '{item['value']}');")
|
|
98
|
-
for item in session_storage:
|
|
99
|
-
await self.base_data.context.add_init_script(
|
|
100
|
-
f"window.sessionStorage.setItem('{item['name']}', '{item['value']}');")
|
|
101
|
-
await self.base_data.page.reload()
|
|
102
|
-
|
|
103
|
-
@async_method_callback('web', '浏览器操作', 6)
|
|
104
|
-
async def w_clear_cookies(self):
|
|
105
|
-
"""清除所有cookie"""
|
|
106
|
-
await self.base_data.context.clear_cookies()
|
|
107
|
-
|
|
108
|
-
@async_method_callback('web', '浏览器操作', 7)
|
|
109
|
-
async def w_clear_storage(self):
|
|
110
|
-
"""清除本地存储和会话存储"""
|
|
111
|
-
await self.base_data.page.evaluate("() => localStorage.clear()")
|
|
112
|
-
await self.base_data.page.evaluate("() => sessionStorage.clear()")
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# @Project: 芒果测试平台
|
|
3
|
-
# @Description: # @Time : 2023-04-26 22:22
|
|
4
|
-
# @Author : 毛鹏
|
|
5
|
-
|
|
6
|
-
from ..._base_data import BaseData
|
|
7
|
-
from ....tools import Meta
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class AsyncWebCustomization(metaclass=Meta):
|
|
11
|
-
"""定制开发"""
|
|
12
|
-
|
|
13
|
-
def __init__(self, base_data: BaseData):
|
|
14
|
-
self.base_data = base_data
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# @Project: 芒果测试平台
|
|
3
|
-
# @Description: # @Time : 2023-04-26 22:22
|
|
4
|
-
# @Author : 毛鹏
|
|
5
|
-
import asyncio
|
|
6
|
-
import os
|
|
7
|
-
|
|
8
|
-
import time
|
|
9
|
-
from playwright.async_api import Locator, Error, TimeoutError
|
|
10
|
-
|
|
11
|
-
from mangotools.decorator import async_method_callback
|
|
12
|
-
from mangotools.models import MethodModel
|
|
13
|
-
from ..._base_data import BaseData
|
|
14
|
-
from ....exceptions import MangoAutomationError
|
|
15
|
-
from ....exceptions.error_msg import ERROR_MSG_0024, ERROR_MSG_0056
|
|
16
|
-
from ....tools import Meta
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class AsyncWebElement(metaclass=Meta):
|
|
20
|
-
"""元素操作"""
|
|
21
|
-
|
|
22
|
-
def __init__(self, base_data: BaseData):
|
|
23
|
-
self.base_data = base_data
|
|
24
|
-
|
|
25
|
-
@async_method_callback('web', '元素操作', 0, [MethodModel(f='locating')])
|
|
26
|
-
async def w_click(self, locating: Locator):
|
|
27
|
-
"""元素单击"""
|
|
28
|
-
await locating.click()
|
|
29
|
-
|
|
30
|
-
@async_method_callback('web', '元素操作', 1, [MethodModel(f='locating')])
|
|
31
|
-
async def w_dblclick(self, locating: Locator):
|
|
32
|
-
"""元素双击"""
|
|
33
|
-
await locating.dblclick()
|
|
34
|
-
|
|
35
|
-
@async_method_callback('web', '元素操作', 2, [MethodModel(f='locating')])
|
|
36
|
-
async def w_force_click(self, locating: Locator):
|
|
37
|
-
"""强制单击"""
|
|
38
|
-
await locating.evaluate('element => element.click()')
|
|
39
|
-
|
|
40
|
-
@async_method_callback('web', '元素操作', 3, [
|
|
41
|
-
MethodModel(f='locating'),
|
|
42
|
-
MethodModel(n='输入内容', f='input_value', p='请输入输入内容', d=True)])
|
|
43
|
-
async def w_input(self, locating: Locator, input_value: str):
|
|
44
|
-
"""元素输入"""
|
|
45
|
-
await locating.fill(str(input_value))
|
|
46
|
-
|
|
47
|
-
@async_method_callback('web', '元素操作', 4, [MethodModel(f='locating')])
|
|
48
|
-
async def w_hover(self, locating: Locator):
|
|
49
|
-
"""鼠标悬停"""
|
|
50
|
-
await locating.hover()
|
|
51
|
-
await asyncio.sleep(1)
|
|
52
|
-
|
|
53
|
-
@async_method_callback('web', '元素操作', 5, [
|
|
54
|
-
MethodModel(f='locating'),
|
|
55
|
-
MethodModel(n='缓存的key', f='set_cache_key', p='请输入获取元素文本后存储的key', d=True)])
|
|
56
|
-
async def w_get_text(self, locating: Locator, set_cache_key=None):
|
|
57
|
-
"""获取元素文本"""
|
|
58
|
-
methods = [
|
|
59
|
-
("inner_text", locating.inner_text),
|
|
60
|
-
("text_content", locating.text_content),
|
|
61
|
-
("input_value", locating.input_value),
|
|
62
|
-
("get_attribute", lambda: locating.get_attribute("value")),
|
|
63
|
-
("evaluate", lambda: locating.evaluate("el => el.value")),
|
|
64
|
-
]
|
|
65
|
-
for method_name, method in methods:
|
|
66
|
-
try:
|
|
67
|
-
value = await method()
|
|
68
|
-
if value is not None and str(value).strip() and set_cache_key:
|
|
69
|
-
self.base_data.test_data.set_cache(key=set_cache_key, value=value)
|
|
70
|
-
return value
|
|
71
|
-
elif value is not None and str(value).strip():
|
|
72
|
-
return value
|
|
73
|
-
except Exception:
|
|
74
|
-
continue
|
|
75
|
-
return None
|
|
76
|
-
|
|
77
|
-
@async_method_callback('web', '元素操作', 5, [
|
|
78
|
-
MethodModel(f='locating'),
|
|
79
|
-
MethodModel(n='输入文本', f='input_value', p='请输入输入内容', d=True)])
|
|
80
|
-
async def w_clear_input(self, locating: Locator, input_value: str):
|
|
81
|
-
"""元素清空再输入"""
|
|
82
|
-
await locating.clear()
|
|
83
|
-
await locating.fill(str(input_value))
|
|
84
|
-
|
|
85
|
-
@async_method_callback('web', '元素操作', 6, [MethodModel(f='locating')])
|
|
86
|
-
async def w_many_click(self, locating: Locator):
|
|
87
|
-
"""多元素循环单击"""
|
|
88
|
-
await asyncio.sleep(1)
|
|
89
|
-
elements = await locating.all()
|
|
90
|
-
for element in elements:
|
|
91
|
-
await element.click()
|
|
92
|
-
await asyncio.sleep(0.2)
|
|
93
|
-
|
|
94
|
-
@async_method_callback('web', '元素操作', 6, [
|
|
95
|
-
MethodModel(f='locating'),
|
|
96
|
-
MethodModel(n='文件名称', f='file_path', p='请输入文件路径,参照帮助文档', d=True)])
|
|
97
|
-
async def w_upload_files(self, locating: Locator, file_path: str | list):
|
|
98
|
-
"""拖拽文件上传"""
|
|
99
|
-
try:
|
|
100
|
-
if isinstance(file_path, str):
|
|
101
|
-
await locating.set_input_files(file_path, timeout=30000)
|
|
102
|
-
else:
|
|
103
|
-
for file in file_path:
|
|
104
|
-
await locating.set_input_files(file, timeout=30000)
|
|
105
|
-
except Error:
|
|
106
|
-
raise MangoAutomationError(*ERROR_MSG_0024)
|
|
107
|
-
|
|
108
|
-
@async_method_callback('web', '元素操作', 7, [
|
|
109
|
-
MethodModel(f='locating'),
|
|
110
|
-
MethodModel(n='文件名称', f='file_path', p='请输入文件路径,参照帮助文档', d=True)])
|
|
111
|
-
async def w_click_upload_files(self, locating: Locator, file_path: str | list):
|
|
112
|
-
"""点击并选择文件上传"""
|
|
113
|
-
async with self.base_data.page.expect_file_chooser(timeout=30000) as fc_info:
|
|
114
|
-
await locating.click()
|
|
115
|
-
file_chooser = await fc_info.value
|
|
116
|
-
await file_chooser.set_files(file_path)
|
|
117
|
-
|
|
118
|
-
@async_method_callback('web', '元素操作', 8, [
|
|
119
|
-
MethodModel(f='locating'),
|
|
120
|
-
MethodModel(n='存储key值', f='file_key', p='请输入文件存储路径的key,后续通过key获取文件保存的绝对路径', d=True)])
|
|
121
|
-
async def w_download(self, locating: Locator, file_key: str):
|
|
122
|
-
"""下载文件"""
|
|
123
|
-
async with self.base_data.page.expect_download(timeout=30000) as download_info:
|
|
124
|
-
await locating.click()
|
|
125
|
-
download = await download_info.value
|
|
126
|
-
file_name = download.suggested_filename
|
|
127
|
-
save_path = os.path.join(self.base_data.download_path, file_name)
|
|
128
|
-
await download.save_as(save_path)
|
|
129
|
-
self.base_data.test_data.set_cache(file_key, file_name)
|
|
130
|
-
|
|
131
|
-
@async_method_callback('web', '元素操作', 9, [
|
|
132
|
-
MethodModel(f='locating')])
|
|
133
|
-
async def w_element_wheel(self, locating: Locator):
|
|
134
|
-
"""滚动到元素位置"""
|
|
135
|
-
await locating.scroll_into_view_if_needed()
|
|
136
|
-
|
|
137
|
-
@async_method_callback('web', '元素操作', 9, [MethodModel(f='locating')])
|
|
138
|
-
async def w_right_click(self, locating: Locator):
|
|
139
|
-
"""元素右键点击"""
|
|
140
|
-
await locating.click(button='right')
|
|
141
|
-
|
|
142
|
-
@async_method_callback('web', '元素操作', 10, [
|
|
143
|
-
MethodModel(f='locating'),
|
|
144
|
-
MethodModel(n='点击时间', f='n', p='请输入循环点击的时间', d=True)])
|
|
145
|
-
async def w_time_click(self, locating: Locator, n: int):
|
|
146
|
-
"""循环点击N秒"""
|
|
147
|
-
try:
|
|
148
|
-
n = int(n)
|
|
149
|
-
except ValueError:
|
|
150
|
-
raise MangoAutomationError(*ERROR_MSG_0056)
|
|
151
|
-
s = time.time()
|
|
152
|
-
while True:
|
|
153
|
-
await locating.click()
|
|
154
|
-
if time.time() - s > n:
|
|
155
|
-
return
|
|
156
|
-
|
|
157
|
-
@async_method_callback('web', '元素操作', 11, [
|
|
158
|
-
MethodModel(f='locating'),
|
|
159
|
-
MethodModel(n='像素大小', f='n', p='请输入向上像素', d=True)])
|
|
160
|
-
async def w_drag_up_pixel(self, locating: Locator, n: int):
|
|
161
|
-
"""往上拖动N个像素"""
|
|
162
|
-
try:
|
|
163
|
-
n = int(n)
|
|
164
|
-
except ValueError:
|
|
165
|
-
raise MangoAutomationError(*ERROR_MSG_0056)
|
|
166
|
-
|
|
167
|
-
box = await locating.bounding_box()
|
|
168
|
-
|
|
169
|
-
if box:
|
|
170
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2, box['y'] + box['height'] / 2)
|
|
171
|
-
await self.base_data.page.mouse.down()
|
|
172
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2, box['y'] + box['height'] / 2 - n)
|
|
173
|
-
await self.base_data.page.mouse.up()
|
|
174
|
-
|
|
175
|
-
@async_method_callback('web', '元素操作', 12, [
|
|
176
|
-
MethodModel(f='locating'),
|
|
177
|
-
MethodModel(n='像素大小', f='n', p='请输入向下像素', d=True)])
|
|
178
|
-
async def w_drag_down_pixel(self, locating: Locator, n: int):
|
|
179
|
-
"""往下拖动N个像素"""
|
|
180
|
-
try:
|
|
181
|
-
n = int(n)
|
|
182
|
-
except ValueError:
|
|
183
|
-
raise MangoAutomationError(*ERROR_MSG_0056)
|
|
184
|
-
|
|
185
|
-
box = await locating.bounding_box()
|
|
186
|
-
|
|
187
|
-
if box:
|
|
188
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2, box['y'] + box['height'] / 2)
|
|
189
|
-
await self.base_data.page.mouse.down()
|
|
190
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2, box['y'] + box['height'] / 2 + n)
|
|
191
|
-
await self.base_data.page.mouse.up()
|
|
192
|
-
|
|
193
|
-
@async_method_callback('web', '元素操作', 13, [
|
|
194
|
-
MethodModel(f='locating'),
|
|
195
|
-
MethodModel(n='像素大小', f='n', p='请输入向左像素', d=True)])
|
|
196
|
-
async def w_drag_left_pixel(self, locating: Locator, n: int):
|
|
197
|
-
"""往左拖动N个像素"""
|
|
198
|
-
try:
|
|
199
|
-
n = int(n)
|
|
200
|
-
except ValueError:
|
|
201
|
-
raise MangoAutomationError(*ERROR_MSG_0056)
|
|
202
|
-
|
|
203
|
-
box = await locating.bounding_box()
|
|
204
|
-
|
|
205
|
-
if box:
|
|
206
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2, box['y'] + box['height'] / 2)
|
|
207
|
-
await self.base_data.page.mouse.down()
|
|
208
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2 - n, box['y'] + box['height'] / 2)
|
|
209
|
-
await self.base_data.page.mouse.up()
|
|
210
|
-
|
|
211
|
-
@async_method_callback('web', '元素操作', 14, [
|
|
212
|
-
MethodModel(f='locating'),
|
|
213
|
-
MethodModel(n='像素大小', f='n', p='请输入向右像素', d=True)])
|
|
214
|
-
async def w_drag_right_pixel(self, locating: Locator, n: int):
|
|
215
|
-
"""往右拖动N个像素"""
|
|
216
|
-
try:
|
|
217
|
-
n = int(n)
|
|
218
|
-
except ValueError:
|
|
219
|
-
raise MangoAutomationError(*ERROR_MSG_0056)
|
|
220
|
-
box = await locating.bounding_box()
|
|
221
|
-
|
|
222
|
-
if box:
|
|
223
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2, box['y'] + box['height'] / 2)
|
|
224
|
-
await self.base_data.page.mouse.down()
|
|
225
|
-
await self.base_data.page.mouse.move(box['x'] + box['width'] / 2 + n, box['y'] + box['height'] / 2)
|
|
226
|
-
await self.base_data.page.mouse.up()
|
|
227
|
-
|
|
228
|
-
@async_method_callback('web', '元素操作', 15, [
|
|
229
|
-
MethodModel(f='locating'),
|
|
230
|
-
MethodModel(n='保存路径', f='path', p='请输入截图名称', d=True)])
|
|
231
|
-
async def w_ele_screenshot(self, locating: Locator, path: str):
|
|
232
|
-
"""元素截图"""
|
|
233
|
-
await locating.screenshot(path=os.path.join(self.base_data.download_path, path))
|
|
234
|
-
|
|
235
|
-
@async_method_callback('web', '元素操作', 20, [
|
|
236
|
-
MethodModel(f='locating1'),
|
|
237
|
-
MethodModel(f='locating2')])
|
|
238
|
-
async def w_drag_to(self, locating1: Locator, locating2: Locator):
|
|
239
|
-
"""拖动A元素到达B"""
|
|
240
|
-
await locating1.drag_to(locating2)
|