mangoautomation 1.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.

Potentially problematic release.


This version of mangoautomation might be problematic. Click here for more details.

Files changed (55) hide show
  1. mangoautomation/__init__.py +5 -0
  2. mangoautomation/enums/__init__.py +19 -0
  3. mangoautomation/enums/_base_enum.py +38 -0
  4. mangoautomation/enums/_ui_enum.py +110 -0
  5. mangoautomation/exceptions/__init__.py +14 -0
  6. mangoautomation/exceptions/_error_msg.py +73 -0
  7. mangoautomation/exceptions/_exceptions.py +14 -0
  8. mangoautomation/models/__init__.py +15 -0
  9. mangoautomation/models/_ui_model.py +61 -0
  10. mangoautomation/tools/__init__.py +13 -0
  11. mangoautomation/tools/_mate.py +12 -0
  12. mangoautomation/uidrive/__init__.py +20 -0
  13. mangoautomation/uidrive/_async_element.py +286 -0
  14. mangoautomation/uidrive/_base_data.py +103 -0
  15. mangoautomation/uidrive/_driver_object.py +63 -0
  16. mangoautomation/uidrive/_sync_element.py +286 -0
  17. mangoautomation/uidrive/android/__init__.py +127 -0
  18. mangoautomation/uidrive/android/_application.py +69 -0
  19. mangoautomation/uidrive/android/_assertion.py +84 -0
  20. mangoautomation/uidrive/android/_customization.py +15 -0
  21. mangoautomation/uidrive/android/_element.py +168 -0
  22. mangoautomation/uidrive/android/_equipment.py +150 -0
  23. mangoautomation/uidrive/android/_new_android.py +54 -0
  24. mangoautomation/uidrive/android/_page.py +116 -0
  25. mangoautomation/uidrive/pc/__init__.py +80 -0
  26. mangoautomation/uidrive/pc/assertion.py +5 -0
  27. mangoautomation/uidrive/pc/customization.py +10 -0
  28. mangoautomation/uidrive/pc/element.py +21 -0
  29. mangoautomation/uidrive/pc/input_device.py +14 -0
  30. mangoautomation/uidrive/pc/new_windows.py +79 -0
  31. mangoautomation/uidrive/web/__init__.py +5 -0
  32. mangoautomation/uidrive/web/async_web/__init__.py +174 -0
  33. mangoautomation/uidrive/web/async_web/_assertion.py +290 -0
  34. mangoautomation/uidrive/web/async_web/_browser.py +97 -0
  35. mangoautomation/uidrive/web/async_web/_customization.py +14 -0
  36. mangoautomation/uidrive/web/async_web/_element.py +199 -0
  37. mangoautomation/uidrive/web/async_web/_input_device.py +83 -0
  38. mangoautomation/uidrive/web/async_web/_new_browser.py +151 -0
  39. mangoautomation/uidrive/web/async_web/_page.py +62 -0
  40. mangoautomation/uidrive/web/sync_web/__init__.py +174 -0
  41. mangoautomation/uidrive/web/sync_web/_assertion.py +282 -0
  42. mangoautomation/uidrive/web/sync_web/_browser.py +96 -0
  43. mangoautomation/uidrive/web/sync_web/_customization.py +14 -0
  44. mangoautomation/uidrive/web/sync_web/_element.py +198 -0
  45. mangoautomation/uidrive/web/sync_web/_input_device.py +79 -0
  46. mangoautomation/uidrive/web/sync_web/_new_browser.py +146 -0
  47. mangoautomation/uidrive/web/sync_web/_page.py +61 -0
  48. mangoautomation-1.0.0.dist-info/LICENSE +21 -0
  49. mangoautomation-1.0.0.dist-info/METADATA +30 -0
  50. mangoautomation-1.0.0.dist-info/RECORD +55 -0
  51. mangoautomation-1.0.0.dist-info/WHEEL +5 -0
  52. mangoautomation-1.0.0.dist-info/top_level.txt +2 -0
  53. tests/__init__.py +5 -0
  54. tests/test_ui_and.py +29 -0
  55. tests/test_ui_web.py +77 -0
@@ -0,0 +1,286 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description:
4
+ # @Time : 2025-04-12 15:55
5
+ # @Author : 毛鹏
6
+ import os
7
+ import traceback
8
+
9
+ import time
10
+ from playwright._impl._errors import TargetClosedError, Error, TimeoutError
11
+
12
+ from mangotools.assertion import PublicAssertion
13
+ from mangotools.decorator import sync_retry
14
+ from mangotools.enums import StatusEnum
15
+ from ..enums import ElementOperationEnum, DriveTypeEnum
16
+ from ..exceptions import MangoAutomationError
17
+ from ..exceptions._error_msg import *
18
+ from ..models import ElementResultModel, ElementModel
19
+ from ..uidrive.android import AndroidDriver
20
+ from ..uidrive.web.sync_web import SyncWebDevice, SyncWebAssertion
21
+
22
+
23
+ class SyncElement(SyncWebDevice, AndroidDriver):
24
+
25
+ def __init__(self, base_data, element_model: ElementModel, drive_type: int, element_data: dict | None = None):
26
+ super().__init__(base_data)
27
+ self.element_data = element_data
28
+ self.element_model = element_model
29
+ self.drive_type = drive_type
30
+ self.ope_name = element_model.name if element_model.name else element_model.ope_key
31
+ self.element_result_model = ElementResultModel(
32
+ id=self.element_model.id,
33
+ name=self.element_model.name,
34
+ loc=self.element_model.loc,
35
+ exp=self.element_model.exp,
36
+ sub=self.element_model.sub,
37
+ sleep=self.element_model.sleep,
38
+
39
+ type=self.element_model.type,
40
+ ope_key=self.element_model.ope_key,
41
+ sql=self.element_model.sql,
42
+ key_list=self.element_model.key_list,
43
+ key=self.element_model.key,
44
+ value=self.element_model.value,
45
+
46
+ status=StatusEnum.FAIL.value,
47
+ )
48
+
49
+ def open_device(self, is_open: bool = False):
50
+ if self.drive_type == DriveTypeEnum.WEB.value:
51
+ self.open_url(is_open)
52
+ elif self.drive_type == DriveTypeEnum.ANDROID.value:
53
+ self.open_app()
54
+ elif self.drive_type == DriveTypeEnum.DESKTOP.value:
55
+ pass
56
+ else:
57
+ self.base_data.log.error(f'不存在这个类型,如果是非管理员看到这种提示,请联系管理员')
58
+ raise Exception('不存在的设备类型')
59
+
60
+ def clean_data(self):
61
+ try:
62
+ for field_name, field_value in self.element_model:
63
+ if field_value is None:
64
+ continue
65
+ if field_name == "ope_value":
66
+ for method_model in field_value:
67
+ for method_field, method_val in method_model:
68
+ if isinstance(method_val, str):
69
+ setattr(method_model, method_field, self.base_data.test_data.replace(method_val))
70
+ elif isinstance(field_value, str):
71
+ setattr(self.element_model, field_name, self.base_data.test_data.replace(field_value))
72
+ except MangoAutomationError as error:
73
+ self.base_data.log.debug(f'操作元素解析数据失败,类型:{type(error)}, 详情:{error}')
74
+ raise MangoAutomationError(error.code, error.msg)
75
+
76
+ def element_main(self) -> ElementResultModel:
77
+ try:
78
+ self.__main()
79
+ if self.element_model.sleep:
80
+ time.sleep(self.element_model.sleep)
81
+ self.element_result_model.status = StatusEnum.SUCCESS.value
82
+ self.element_result_model.error_message = None
83
+ except TargetClosedError as error:
84
+ self.base_data.setup()
85
+ self.base_data.log.debug(
86
+ f'浏览器关闭异常,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
87
+ self.element_result_model.status = StatusEnum.FAIL.value
88
+ self.element_result_model.error_message = '浏览器被关闭,请不要认关闭浏览器,非认为管理请联系管理员解决!'
89
+ except MangoAutomationError as error:
90
+ self.__error(error.msg)
91
+ self.base_data.log.debug(f'已知异常,类型:{type(error)},失败详情:{error}')
92
+ except Error as error:
93
+ self.__error(f'未知错误失败,请检查测试数据,如果需要明确的提示请联系管理员,提示:{error.message}')
94
+ self.base_data.log.error(
95
+ f'未知错误捕获-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
96
+ except Exception as error:
97
+ error_msg = f'未知错误失败,请检查测试数据,如果需要明确的提示请联系管理员,提示:{error.args}'
98
+ if hasattr(error, 'msg'):
99
+ error_msg = error.msg
100
+ self.__error(error_msg)
101
+ self.base_data.log.error(
102
+ f'未知错误捕获-2,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
103
+ return self.element_result_model
104
+
105
+ @sync_retry()
106
+ def __main(self):
107
+ self.clean_data()
108
+ if self.element_model.type == ElementOperationEnum.OPE.value:
109
+ self.__ope()
110
+ elif self.element_model.type == ElementOperationEnum.ASS.value:
111
+ self.__ass()
112
+ elif self.element_model.type == ElementOperationEnum.SQL.value:
113
+ self.__sql()
114
+ elif self.element_model.type == ElementOperationEnum.CUSTOM.value:
115
+ self.__custom()
116
+ else:
117
+ raise MangoAutomationError(*ERROR_MSG_0015)
118
+
119
+ def __ope(self):
120
+ method_name = getattr(self.element_model, 'ope_key', None)
121
+ if not method_name:
122
+ self.base_data.log.debug('操作失败-1,ope_key 不存在或为空')
123
+ raise MangoAutomationError(*ERROR_MSG_0048)
124
+ if not hasattr(self, method_name):
125
+ self.base_data.log.debug(f'操作失败-2,方法不存在: {method_name}')
126
+ raise MangoAutomationError(*ERROR_MSG_0048)
127
+ if not callable(getattr(self, method_name)):
128
+ self.base_data.log.debug(f'操作失败-3,属性不可调用: {method_name}')
129
+ raise MangoAutomationError(*ERROR_MSG_0048)
130
+ if self.element_model.ope_value is None:
131
+ raise MangoAutomationError(*ERROR_MSG_0054)
132
+
133
+ self.__ope_value()
134
+ if self.drive_type == DriveTypeEnum.WEB.value:
135
+ self.web_action_element(
136
+ self.element_model.name,
137
+ self.element_model.ope_key,
138
+ {i.f: i.v for i in self.element_model.ope_value}
139
+ )
140
+ elif self.drive_type == DriveTypeEnum.ANDROID.value:
141
+ self.a_action_element(
142
+ self.element_model.name,
143
+ self.element_model.ope_key,
144
+ {i.f: i.v for i in self.element_model.ope_value}
145
+ )
146
+ else:
147
+ pass
148
+ for i in self.element_model.ope_value:
149
+ if i.d:
150
+ self.element_result_model.ope_value[i.f] = i.v
151
+
152
+ def __ass(self):
153
+ if self.element_model.ope_value is None:
154
+ raise MangoAutomationError(*ERROR_MSG_0053)
155
+ self.__ope_value(True)
156
+ if self.drive_type == DriveTypeEnum.WEB.value:
157
+ self.web_assertion_element(
158
+ self.element_model.name,
159
+ self.element_model.ope_key,
160
+ {i.f: i.v for i in self.element_model.ope_value}
161
+ )
162
+ elif self.drive_type == DriveTypeEnum.ANDROID.value:
163
+ self.a_assertion_element(
164
+ self.element_model.name,
165
+ self.element_model.ope_key,
166
+ {i.f: i.v for i in self.element_model.ope_value}
167
+ )
168
+ else:
169
+ pass
170
+ for i in self.element_model.ope_value:
171
+ if i.d:
172
+ self.element_result_model.ope_value[i.f] = i.v
173
+
174
+ def __sql(self):
175
+ if not self.element_data:
176
+ sql = self.base_data.test_data.replace(self.element_model.sql)
177
+ key_list = self.element_model.key_list
178
+ else:
179
+ sql = self.base_data.test_data.replace(self.element_data.get('sql'))
180
+ key_list = self.element_data.get('key_list')
181
+ if self.base_data.mysql_connect:
182
+ result_list: list[dict] = self.base_data.mysql_connect.condition_execute(sql)
183
+ if isinstance(result_list, list):
184
+ for result in result_list:
185
+ try:
186
+ for value, key in zip(result, key_list):
187
+ self.base_data.test_data.set_cache(key, result.get(value))
188
+ except SyntaxError as error:
189
+ self.base_data.log.debug(
190
+ f'SQL执行失败-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
191
+ raise MangoAutomationError(*ERROR_MSG_0038)
192
+
193
+ if not result_list:
194
+ raise MangoAutomationError(*ERROR_MSG_0036, value=(self.element_model.sql,))
195
+
196
+ def __custom(self):
197
+ if not self.element_data:
198
+ key = self.element_model.key
199
+ value = self.element_model.value
200
+ else:
201
+ key = self.element_data.get('key')
202
+ value = self.element_data.get('value')
203
+ self.base_data.test_data.set_cache(key, self.base_data.test_data.replace(value))
204
+
205
+ def __ope_value(self, is_ass: bool = False):
206
+ try:
207
+ ope_key = 'actual' if is_ass else 'locating'
208
+ for i in self.element_model.ope_value:
209
+ if i.f == ope_key and self.element_model.loc:
210
+ find_params = {
211
+ 'name': self.element_model.name,
212
+ '_type': self.element_model.type,
213
+ 'exp': self.element_model.exp,
214
+ 'loc': self.element_model.loc,
215
+ 'sub': self.element_model.sub
216
+ }
217
+ if self.drive_type == DriveTypeEnum.WEB.value:
218
+ loc, \
219
+ self.element_result_model.ele_quantity, \
220
+ self.element_result_model.element_text \
221
+ = self.web_find_ele(**find_params, is_iframe=self.element_model.is_iframe)
222
+ elif self.drive_type == DriveTypeEnum.ANDROID.value:
223
+ loc, \
224
+ self.element_result_model.ele_quantity, \
225
+ self.element_result_model.element_text \
226
+ = self.a_find_ele(**find_params)
227
+ else:
228
+ loc, \
229
+ self.element_result_model.ele_quantity, \
230
+ self.element_result_model.element_text \
231
+ = None, 0, None
232
+
233
+ if is_ass:
234
+ if callable(getattr(SyncWebAssertion, self.element_model.ope_key, None)):
235
+ i.v = loc
236
+ elif callable(getattr(PublicAssertion, self.element_model.ope_key, None)):
237
+ i.v = self.element_result_model.element_text
238
+ else:
239
+ i.v = loc
240
+ else:
241
+ if self.element_data:
242
+ for ele_name, case_data in self.element_data.items():
243
+ if ele_name == i.f:
244
+ value = case_data
245
+ i.v = self.base_data.test_data.replace(value)
246
+
247
+ except AttributeError as error:
248
+ self.base_data.log.debug(
249
+ f'获取操作值失败-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
250
+ raise MangoAutomationError(*ERROR_MSG_0027)
251
+
252
+ def __error(self, msg: str):
253
+ self.element_result_model.status = StatusEnum.FAIL.value
254
+ self.element_result_model.error_message = msg
255
+ self.base_data.log.debug(
256
+ f"""
257
+ 元素操作失败----->
258
+ 元 素 对 象:{self.element_model.model_dump() if self.element_model else self.element_model}
259
+ 元素测试结果:{
260
+ self.element_result_model.model_dump() if self.element_result_model else self.element_result_model}
261
+ """
262
+ )
263
+ file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.get_time_for_min()}.jpg'
264
+ file_path = os.path.join(self.base_data.screenshot_path, file_name)
265
+ self.element_result_model.picture_path = file_path
266
+ self.element_result_model.picture_name = file_name
267
+ self.__error_screenshot(file_path)
268
+
269
+ def __error_screenshot(self, file_path):
270
+ if self.drive_type == DriveTypeEnum.WEB.value:
271
+ try:
272
+ self.w_screenshot(file_path)
273
+ except (TargetClosedError, TimeoutError) as error:
274
+ self.base_data.log.debug(
275
+ f'截图出现异常失败-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
276
+ self.base_data.setup()
277
+ raise MangoAutomationError(*ERROR_MSG_0010)
278
+ except AttributeError as error:
279
+ self.base_data.log.debug(
280
+ f'截图出现异常失败-2,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
281
+ self.base_data.setup()
282
+ raise MangoAutomationError(*ERROR_MSG_0010)
283
+ elif self.drive_type == DriveTypeEnum.ANDROID.value:
284
+ self.a_screenshot(file_path)
285
+ else:
286
+ pass
@@ -0,0 +1,127 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台# @Description:
3
+ # @Time : 2023-09-09 23:17
4
+ # @Author : 毛鹏
5
+
6
+ from uiautomator2 import UiObject, UiObjectNotFoundError
7
+ from uiautomator2.exceptions import XPathElementNotFoundError
8
+ from uiautomator2.xpath import XPathSelector
9
+
10
+ from mangotools.assertion import PublicAssertion
11
+ from mangotools.assertion import SqlAssertion
12
+ from ..android._application import AndroidApplication
13
+ from ..android._assertion import AndroidAssertion
14
+ from ..android._customization import AndroidCustomization
15
+ from ..android._element import AndroidElement
16
+ from ..android._equipment import AndroidEquipment
17
+ from ..android._page import AndroidPage
18
+ from ...enums import ElementExpEnum
19
+ from ...exceptions import MangoAutomationError
20
+ from ...exceptions._error_msg import *
21
+
22
+ __all__ = [
23
+ 'AndroidApplication',
24
+ 'AndroidAssertion',
25
+ 'AndroidElement',
26
+ 'AndroidCustomization',
27
+ 'AndroidEquipment',
28
+ 'AndroidPage',
29
+ 'AndroidDriver',
30
+ ]
31
+
32
+ from mangotools.mangos import Mango
33
+
34
+
35
+ class AndroidDriver(AndroidPage,
36
+ AndroidElement,
37
+ AndroidEquipment,
38
+ AndroidCustomization,
39
+ AndroidApplication):
40
+
41
+ def __init__(self, base_data):
42
+ super().__init__(base_data)
43
+
44
+ def open_app(self):
45
+ if not self.base_data.is_open_app:
46
+ self.base_data.is_open_app = True
47
+ self.a_press_home()
48
+ self.a_app_stop_all()
49
+ if self.base_data.android and self.base_data.package_name:
50
+ self.a_start_app(self.base_data.package_name)
51
+
52
+ def a_action_element(self, name, ope_key, ope_value):
53
+ self.base_data.log.debug(f'操作元素,名称:{name},key:{ope_key},value:{ope_value}')
54
+ try:
55
+ Mango.s_e(self, ope_key, ope_value)
56
+ except ValueError as error:
57
+ self.base_data.log.error(f'安卓自动化失败-1,类型:{type(error)},失败详情:{error}')
58
+ raise MangoAutomationError(*ERROR_MSG_0012)
59
+ except UiObjectNotFoundError as error:
60
+ self.base_data.log.error(f'安卓自动化失败-2,类型:{type(error)},失败详情:{error}')
61
+ raise MangoAutomationError(*ERROR_MSG_0032, value=(name,))
62
+ except XPathElementNotFoundError as error:
63
+ self.base_data.log.error(f'安卓自动化失败-3,类型:{type(error)},失败详情:{error}')
64
+ raise MangoAutomationError(*ERROR_MSG_0050, value=(name,))
65
+
66
+ def a_assertion_element(self, name, ope_key, ope_value):
67
+ self.base_data.log.debug(f'断言元素,名称:{name},key:{ope_key},value:{ope_value}')
68
+
69
+ is_method = callable(getattr(AndroidAssertion(self.base_data), ope_key, None))
70
+ is_method_public = callable(getattr(PublicAssertion, ope_key, None))
71
+
72
+ if is_method or is_method_public:
73
+ if ope_value['value'] is None:
74
+ raise MangoAutomationError(*ERROR_MSG_0031, value=(name,))
75
+
76
+ try:
77
+ if is_method:
78
+ self.base_data.log.debug(f'开始断言-1,方法:{ope_key},断言值:{ope_value}')
79
+ Mango.s_e(AndroidAssertion(self.base_data), ope_key, ope_value)
80
+ elif is_method_public:
81
+ self.base_data.log.debug(f'开始断言-2,方法:{ope_key},断言值:{ope_value}')
82
+ Mango.s_e(PublicAssertion, ope_key, ope_value)
83
+ else:
84
+ if self.base_data.mysql_connect is not None:
85
+ SqlAssertion.mysql_obj = self.base_data.mysql_connect
86
+ self.base_data.log.debug(f'开始断言-3,方法:sql相等端游,实际值:{ope_value}')
87
+ SqlAssertion.sql_is_equal(**ope_value)
88
+ else:
89
+ raise MangoAutomationError(*ERROR_MSG_0019)
90
+ except AssertionError as error:
91
+ self.base_data.log.error(f'安卓自动化失败-1,类型:{type(error)},失败详情:{error}')
92
+ raise MangoAutomationError(*ERROR_MSG_0017, value=error.args)
93
+ except AttributeError as error:
94
+ self.base_data.log.error(f'安卓自动化失败-2,类型:{type(error)},失败详情:{error}')
95
+ raise MangoAutomationError(*ERROR_MSG_0030, )
96
+ except ValueError as error:
97
+ self.base_data.log.error(f'安卓自动化失败-3,类型:{type(error)},失败详情:{error}')
98
+ raise MangoAutomationError(*ERROR_MSG_0005, )
99
+
100
+ def a_find_ele(self, name, _type, exp, loc, sub) -> tuple[UiObject, int, str] | tuple[XPathSelector, int, str]:
101
+ self.base_data.log.debug(
102
+ f'查找元素,名称:{name},_type:{_type},exp:{exp},loc:{loc},sub:{sub}')
103
+ match exp:
104
+ case ElementExpEnum.LOCATOR.value:
105
+ try:
106
+ if loc[:5] == 'xpath':
107
+ loc = eval(f"self.android.{loc}")
108
+ else:
109
+ loc = eval(f"self.android{loc}")
110
+ except SyntaxError:
111
+ raise MangoAutomationError(*ERROR_MSG_0022)
112
+ case ElementExpEnum.XPATH.value:
113
+ loc = self.base_data.android.xpath(loc)
114
+ case ElementExpEnum.BOUNDS.value:
115
+ loc = self.base_data.android(text=loc)
116
+ case ElementExpEnum.DESCRIPTION.value:
117
+ loc = self.base_data.android(description=loc)
118
+ case ElementExpEnum.RESOURCE_ID.value:
119
+ loc = self.base_data.android(resourceId=loc)
120
+ case _:
121
+ raise MangoAutomationError(*ERROR_MSG_0020)
122
+ text = None
123
+ try:
124
+ text = self.a_get_text(loc)
125
+ except Exception:
126
+ pass
127
+ return loc, loc.count, text
@@ -0,0 +1,69 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台# @Description:
3
+ # @Time : 2023-09-09 23:17
4
+ # @Author : 毛鹏
5
+ import time
6
+
7
+ from mangotools.decorator import sync_method_callback
8
+ from mangotools.models import MethodModel
9
+ from ...exceptions import MangoAutomationError
10
+ from ...exceptions._error_msg import ERROR_MSG_0046
11
+ from ...tools import Meta
12
+ from ...uidrive._base_data import BaseData
13
+
14
+
15
+ class AndroidApplication(metaclass=Meta):
16
+ """应用操作"""
17
+
18
+ def __init__(self, base_data: BaseData):
19
+ self.base_data = base_data
20
+
21
+ def is_app_installed(self, package_name: str) -> bool:
22
+ return any(package_name in str(i) for i in self.base_data.android.shell("pm list packages"))
23
+
24
+ @sync_method_callback('android', '应用操作', [
25
+ MethodModel(f='package_name', p='请输入应用名称', d=True)])
26
+ def a_start_app(self, package_name: str):
27
+ """启动应用"""
28
+ if not package_name:
29
+ raise MangoAutomationError(*ERROR_MSG_0046)
30
+ if not self.is_app_installed(package_name):
31
+ raise MangoAutomationError(*ERROR_MSG_0046)
32
+ self.base_data.android.app_start(package_name)
33
+ time.sleep(4)
34
+
35
+ @sync_method_callback('android', '应用操作', [
36
+ MethodModel(f='package_name', p='请输入应用名称', d=True)])
37
+ def a_close_app(self, package_name: str):
38
+ """关闭应用"""
39
+ if not package_name:
40
+ raise MangoAutomationError(*ERROR_MSG_0046)
41
+ if not self.is_app_installed(package_name):
42
+ raise MangoAutomationError(*ERROR_MSG_0046)
43
+
44
+ self.base_data.android.app_stop(package_name)
45
+
46
+ @sync_method_callback('android', '应用操作', [
47
+ MethodModel(f='package_name', p='请输入应用名称', d=True)])
48
+ def a_clear_app(self, package_name: str):
49
+ """清除app数据"""
50
+ if not package_name:
51
+ raise MangoAutomationError(*ERROR_MSG_0046)
52
+ if not self.is_app_installed(package_name):
53
+ raise MangoAutomationError(*ERROR_MSG_0046)
54
+
55
+ self.base_data.android.app_clear(package_name)
56
+
57
+ @sync_method_callback('android', '应用操作', )
58
+ def a_app_stop_all(self):
59
+ """停止所有app"""
60
+ self.base_data.android.app_stop_all()
61
+
62
+ @sync_method_callback('android', '应用操作', [
63
+ MethodModel(f='package_name', p='请输入应用名称列表', d=True)])
64
+ def a_app_stop_appoint(self, package_name_list: list):
65
+ """停止除指定app外所有app"""
66
+ for i in package_name_list:
67
+ if not self.is_app_installed(i):
68
+ raise MangoAutomationError(*ERROR_MSG_0046)
69
+ self.base_data.android.app_stop_all(excludes=package_name_list)
@@ -0,0 +1,84 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台# @Description:
3
+ # @Time : 2023-09-09 23:17
4
+ # @Author : 毛鹏
5
+ from uiautomator2 import UiObject
6
+
7
+ from mangoautomation.tools import Meta
8
+ from mangoautomation.uidrive._base_data import BaseData
9
+ from mangotools.decorator import sync_method_callback
10
+ from mangotools.models import MethodModel
11
+
12
+
13
+ class AndroidAssertion(metaclass=Meta):
14
+ """元素断言"""
15
+
16
+ def __init__(self, base_data: BaseData):
17
+ self.base_data = base_data
18
+
19
+ @sync_method_callback('ass_android', '元素断言', [
20
+ MethodModel(f='actual')])
21
+ def a_assert_ele_exists(self, actual: UiObject):
22
+ """元素存在"""
23
+ assert actual.count
24
+
25
+ @sync_method_callback('ass_android', '元素断言', [
26
+ MethodModel(f='actual'),
27
+ MethodModel(f='expect', p='请输入预期内容', d=True)])
28
+ def a_assert_ele_count(self, actual: UiObject, expect):
29
+ """元素计数"""
30
+ assert int(actual.count) == int(expect)
31
+
32
+ @sync_method_callback('ass_android', '元素断言', [
33
+ MethodModel(f='actual'),
34
+ MethodModel(f='expect', p='请输入预期文本', d=True)])
35
+ def a_assert_ele_text(self, actual: UiObject, expect: str):
36
+ """元素文本内容"""
37
+ assert actual.get_text() == expect, \
38
+ f"实际='{actual.get_text()}', 预期='{expect}'"
39
+
40
+ @sync_method_callback('ass_android', '元素断言', [
41
+ MethodModel(f='actual')])
42
+ def a_assert_ele_clickable_true(self, actual: UiObject):
43
+ """元素可点击"""
44
+ assert actual.info['clickable'], \
45
+ f"实际={actual.info['clickable']}, 预期=可点击"
46
+
47
+ @sync_method_callback('ass_android', '元素断言', [
48
+ MethodModel(f='actual')])
49
+ def a_assert_ele_clickable_false(self, actual: UiObject):
50
+ """元素不可点击"""
51
+ assert not actual.info['clickable'], \
52
+ f"实际={actual.info['clickable']}, 预期=元素不可点击"
53
+
54
+ @sync_method_callback('ass_android', '元素断言', [
55
+ MethodModel(f='actual')])
56
+ def a_assert_ele_visible_true(self, actual: UiObject):
57
+ """元素可见"""
58
+ assert actual.exists and actual.info['visible'], \
59
+ f"实际={actual.info['visible']}, 预期=元素可见"
60
+
61
+ @sync_method_callback('ass_android', '元素断言', [
62
+ MethodModel(f='actual')])
63
+ def a_assert_ele_visible_false(self, actual: UiObject):
64
+ """元素不可见"""
65
+ assert actual.exists and not actual.info['visible'], \
66
+ f"实际={actual.info['visible']}, 预期=元素不可见"
67
+
68
+ @sync_method_callback('ass_android', '元素断言', [
69
+ MethodModel(f='expect', p='请输入弹窗标题文本', d=False)])
70
+ def a_assert_dialog_exists(self, expect: str):
71
+ """弹窗存在"""
72
+ dialog = self.base_data.android(text=expect) if expect else self.base_data.android(
73
+ className="android.app.AlertDialog")
74
+ assert dialog.exists, "未找到预期弹窗"
75
+
76
+ @sync_method_callback('ass_android', '元素断言', [
77
+ MethodModel(f='actual'),
78
+ MethodModel(f='expect', p='请输入断言目标文本', d=True)])
79
+ def a_assert_ele_in_list(self, actual: UiObject, expect: str):
80
+ """列表滑动后目标元素存在"""
81
+ if not actual.exists:
82
+ raise AssertionError("传入的元素不是可滑动的列表")
83
+ actual.scroll.vert.to(text=expect)
84
+ assert self.base_data.android(text=expect).exists, f"列表中未找到文本: {expect}"
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description: # @Time : 2023-04-26 22:22
4
+ # @Author : 毛鹏
5
+
6
+
7
+ from mangoautomation.tools import Meta
8
+ from mangoautomation.uidrive._base_data import BaseData
9
+
10
+
11
+ class AndroidCustomization(metaclass=Meta):
12
+ """定制开发"""
13
+
14
+ def __init__(self, base_data: BaseData):
15
+ self.base_data = base_data