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