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
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -19,46 +19,15 @@ class DriverObject:
|
|
|
19
19
|
self.android: Optional[NewAndroid] = None
|
|
20
20
|
self.windows: Optional[NewWindows] = None
|
|
21
21
|
|
|
22
|
-
def set_web(self,
|
|
23
|
-
|
|
24
|
-
web_path: str | None = None,
|
|
25
|
-
web_max=False,
|
|
26
|
-
web_headers=False,
|
|
27
|
-
web_recording=False,
|
|
28
|
-
web_h5=None,
|
|
29
|
-
is_header_intercept=False,
|
|
30
|
-
web_is_default=False,
|
|
31
|
-
videos_path=None
|
|
32
|
-
):
|
|
22
|
+
def set_web(self, **kwargs):
|
|
23
|
+
kwargs['log'] = self.log
|
|
33
24
|
if self.is_async:
|
|
34
|
-
self.web = AsyncWebNewBrowser(
|
|
35
|
-
web_type,
|
|
36
|
-
web_path,
|
|
37
|
-
web_max,
|
|
38
|
-
web_headers,
|
|
39
|
-
web_recording,
|
|
40
|
-
web_h5,
|
|
41
|
-
is_header_intercept,
|
|
42
|
-
web_is_default,
|
|
43
|
-
videos_path,
|
|
44
|
-
log=self.log,
|
|
45
|
-
)
|
|
25
|
+
self.web = AsyncWebNewBrowser(**kwargs)
|
|
46
26
|
else:
|
|
47
|
-
self.web = SyncWebNewBrowser(
|
|
48
|
-
web_type,
|
|
49
|
-
web_path,
|
|
50
|
-
web_max,
|
|
51
|
-
web_headers,
|
|
52
|
-
web_recording,
|
|
53
|
-
web_h5,
|
|
54
|
-
is_header_intercept,
|
|
55
|
-
web_is_default,
|
|
56
|
-
videos_path,
|
|
57
|
-
log=self.log,
|
|
58
|
-
)
|
|
27
|
+
self.web = SyncWebNewBrowser(**kwargs)
|
|
59
28
|
|
|
60
29
|
def set_android(self, and_equipment: str):
|
|
61
30
|
self.android = NewAndroid(and_equipment)
|
|
62
31
|
|
|
63
32
|
def set_windows(self, win_path: str, win_title: str):
|
|
64
|
-
self.windows = NewWindows(win_path, win_title)
|
|
33
|
+
self.windows = NewWindows(win_path, win_title)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mangoautomation
|
|
3
|
+
Version: 1.1.25
|
|
4
|
+
Summary: 测试工具
|
|
5
|
+
Home-page: https://gitee.com/mao-peng/testkit
|
|
6
|
+
Author: 毛鹏
|
|
7
|
+
Author-email: 729164035@qq.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: setuptools==78.1.1
|
|
12
|
+
Requires-Dist: pydantic>=2.9.2
|
|
13
|
+
Requires-Dist: playwright==1.43.0
|
|
14
|
+
Requires-Dist: uiautomation>=2.0.20
|
|
15
|
+
Requires-Dist: uiautomator2>=3.2.5
|
|
16
|
+
Requires-Dist: mangotools>=1.1.42
|
|
17
|
+
Requires-Dist: adbutils~=2.8.9
|
|
18
|
+
Requires-Dist: uiautodev>=0.9.0
|
|
19
|
+
Requires-Dist: beautifulsoup4==4.14.2
|
|
20
|
+
Requires-Dist: openai==2.6.1
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: author-email
|
|
23
|
+
Dynamic: classifier
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# testkit
|
|
31
|
+
|
|
32
|
+
#### 介绍
|
|
33
|
+
|
|
34
|
+
测试工具
|
|
35
|
+
|
|
36
|
+
#### 安装教程
|
|
37
|
+
|
|
38
|
+
1. pip install mangokit
|
|
39
|
+
|
|
40
|
+
#### 使用说明
|
|
41
|
+
|
|
42
|
+
1.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
mangoautomation/__init__.py,sha256=JxPNVexFQvkBfh0awPNeHxQGU_gtVgYPwD5rYeuHWEk,125
|
|
2
|
+
mangoautomation/enums/__init__.py,sha256=PnOgNttAXT64elr_Fd1ZthuAddCkm7sh4xwm9Eutm_I,373
|
|
3
|
+
mangoautomation/enums/_base_enum.py,sha256=dpaXsdhWY08BhIzi1B1ksh_p18ZTmhWvTYhbd3n_ONQ,1176
|
|
4
|
+
mangoautomation/enums/_ui_enum.py,sha256=mT_MfQ7TEw-BgHIqH0wXTA_yVWsaWnd3iHSHi9E0pgA,4599
|
|
5
|
+
mangoautomation/exceptions/__init__.py,sha256=2j3ravPuzljR2Mbq8J2JLdXUzII7hzrjdVjmEc_NHJU,211
|
|
6
|
+
mangoautomation/exceptions/_exceptions.py,sha256=BiyST1QPivpfIOuKn1gKhpXOyBv6gfip_KvlQuu8ctw,385
|
|
7
|
+
mangoautomation/exceptions/error_msg.py,sha256=0unQ_tgrRJtVMAOXTzhQJkwO4_7lhMKAMMCfwmzQD58,5517
|
|
8
|
+
mangoautomation/mangos/__init__.py,sha256=gEu8lVHGXm8PDTBZ1XXWNUOAbCtHb37uKQLBRYQR4rs,644
|
|
9
|
+
mangoautomation/mangos/mangos.cp310-win_amd64.pyd,sha256=6s_XmeiYcz5lblKGMNH9f-tlyAV2gfR3A18J-VkdQ4Y,1743360
|
|
10
|
+
mangoautomation/mangos/mangos.cp312-win_amd64.pyd,sha256=Xlu2Yfm3E9zpwlKMLChbVyC1CiVFakjQfs3AzZ1zP0E,1878016
|
|
11
|
+
mangoautomation/mangos/mangos.cpython-310-darwin.so,sha256=Jp5zoaZLf3uGTGppI6r35dgcwCKbghWckC2sAYUZ_KI,3540144
|
|
12
|
+
mangoautomation/mangos/mangos.cpython-310-x86_64-linux-gnu.so,sha256=riKsG3xp6xDy8V5CrpsFcZbxCikcD0--nt_iyK-Adek,10528184
|
|
13
|
+
mangoautomation/mangos/mangos.cpython-312-darwin.so,sha256=RjzbB_3G4fO-i8wDrTVjKSMPXUL1nVpcQY5RCFmuAMI,3455344
|
|
14
|
+
mangoautomation/mangos/mangos.cpython-312-x86_64-linux-gnu.so,sha256=QDLPDGhoQwxn_qJZ1lgfToSXVKBi6Wd7BhIGScwfNBY,10765984
|
|
15
|
+
mangoautomation/mangos/__pycache__/__init__.cpython-310.pyc,sha256=mlbMT0_xx35rLFukbmGWBgelTH327kE0V5k_bJiOPH8,604
|
|
16
|
+
mangoautomation/models/__init__.py,sha256=wHACwBCrd9HCvmrAkTFUV3qmK9GnOa-FJFiL0kOQjME,309
|
|
17
|
+
mangoautomation/models/_ui_model.py,sha256=nfxh_4TpOLzKKWC7c-IgMLVZY5wkTPfyS_Oh-SvsYsk,1825
|
|
18
|
+
mangoautomation/tools/__init__.py,sha256=c3IXhoodknOukOyM6db2tXIdDRodgmUZorEAkkruQf0,282
|
|
19
|
+
mangoautomation/tools/_mate.py,sha256=9lk_EJnAX_OyXbe5WacyHkkcEr2ScBgasl6eUnlklWA,405
|
|
20
|
+
mangoautomation/tools/_uiautodev.py,sha256=KYYWOQ_sp91LN_zeKAuIvCqjabb2_1-VhgOg1K7cQrw,1372
|
|
21
|
+
mangoautomation/uidrive/__init__.py,sha256=9N2DTDyLcmgxAHctBjZOb8LwdDeKQnwEOWZ9kNcM4Uw,350
|
|
22
|
+
mangoautomation/uidrives/__init__.py,sha256=JEoWqpoDIch8JiQ7WcnuDh3Bjg0Yqo_xfkbqY5iHSa8,617
|
|
23
|
+
mangoautomation/uidrives/_async_element.py,sha256=87BhadK9BJtcv_VzJUM3kX5sdp8b8Kk-abkU9oE3T7M,16206
|
|
24
|
+
mangoautomation/uidrives/_base_data.py,sha256=gp9730Hd8uarRv8xARIddgMWGhaJ_RKDd_gjewwWr04,4436
|
|
25
|
+
mangoautomation/uidrives/_driver_object.py,sha256=o2egGOZfkRVS2PEors8t5TPqTLyRbO1EObH8dY87TUo,1033
|
|
26
|
+
mangoautomation/uidrives/_sync_element.py,sha256=TU2E7AKz0Ku4qXLEtxx-whJPJ4KLYLK_EuKgChpcedM,15906
|
|
27
|
+
mangoautomation/uidrives/android/__init__.py,sha256=i6WjXlNq6oUZ4y79Gih_XzI9tV7du-Jrm9IAuROgSzo,5180
|
|
28
|
+
mangoautomation/uidrives/ios/__init__.py,sha256=SdxI8e5AOoAb8JTaDoMkObezIluJ50nm2b6zeDHv1PI,125
|
|
29
|
+
mangoautomation/uidrives/pc/__init__.py,sha256=Jphhspu-3AHCyDX5ZM_-DWeC9ZerWy2Omb3MOck6CI4,2210
|
|
30
|
+
mangoautomation/uidrives/pc/assertion.py,sha256=mH25hZ2i4T8kA1F2loW_nuPJ-Hb0z1pwILTJqkwwpLA,125
|
|
31
|
+
mangoautomation/uidrives/pc/customization.py,sha256=UkpHWFSYsu_t-GmMRDmii1Bs_Y1eKD34oZfJBFHV2Ng,240
|
|
32
|
+
mangoautomation/uidrives/pc/element.py,sha256=OGbJHbgJPBjRjXqM-NIWUnScn7lIHoBxnrakog_s4l8,465
|
|
33
|
+
mangoautomation/uidrives/pc/input_device.py,sha256=k-v7tRW8NkJxzcezqSIfICGRBqEdsssBeRTmtupVTU8,299
|
|
34
|
+
mangoautomation/uidrives/pc/new_windows.py,sha256=lETHZa7cW8Z0iUShzgVTRxqivkYaOo8WIE58q_8KYfQ,2338
|
|
35
|
+
mangoautomation/uidrives/web/__init__.py,sha256=TJyYt6EUoRfWYrV193RHpopKfixipVUp4TrhB5DoEKA,434
|
|
36
|
+
mangoautomation/uidrives/web/_async_web.py,sha256=Uwta7cIYo-0Qe5RbaIvRSQ-IvOxCNtbH_RcIm1JNxEQ,8204
|
|
37
|
+
mangoautomation/uidrives/web/_sync_web.py,sha256=NCF97mYWQBLsOkcEXHKbAGLYGt4rK7NSjks6PubLe_k,8049
|
|
38
|
+
mangoautomation-1.1.25.dist-info/licenses/LICENSE,sha256=03WP-mgFmo8ofRYDe1HVDQUEUKQZ2q6P6Q-2A4c-46A,1085
|
|
39
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
tests/demo1.py,sha256=Wcz63WWXe48arwmCh23ejT66ZbJFV2I7J05AOEZ5aq8,3056
|
|
41
|
+
tests/get_ope.py,sha256=2m7gkOiVSIAzTwnoQwp2JaphM5rPClqvwf24x7R3Az4,476
|
|
42
|
+
tests/test_ai_element.py,sha256=k__iifxebvPPfGdRS-yzkEH80fBIlKJcZ-m3N6Xkz6Q,1437
|
|
43
|
+
tests/test_ui_and.py,sha256=A_0pqG6s5Ts02He7P3NwuDSK3g9Q3VP1Sb_P8wq6g0Q,125
|
|
44
|
+
tests/test_ui_web.py,sha256=RBACNYc7XdvENHzg4YElsSQlEmPVa_AyOKWTYTPXM14,2578
|
|
45
|
+
mangoautomation-1.1.25.dist-info/METADATA,sha256=fGMYvzrKvRmM0hYw29tMr-A5LMYQm3fVUB4VBFVfSss,941
|
|
46
|
+
mangoautomation-1.1.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
mangoautomation-1.1.25.dist-info/top_level.txt,sha256=g-uCmjvEODG8WFbmwbGM0-G0zHntHv8ZsS0PQRaMGtE,22
|
|
48
|
+
mangoautomation-1.1.25.dist-info/RECORD,,
|
tests/demo1.py
CHANGED
|
@@ -1,21 +1,94 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
from bs4 import BeautifulSoup
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_optimized_page_html(html_content) -> str:
|
|
5
|
+
soup = BeautifulSoup(html_content, 'html.parser')
|
|
6
|
+
|
|
7
|
+
# 配置化的清理规则
|
|
8
|
+
cleanup_rules = {
|
|
9
|
+
# 直接删除的标签
|
|
10
|
+
'remove_tags': [
|
|
11
|
+
'script', 'style', 'link', 'noscript', 'path',
|
|
12
|
+
'svg', 'head', 'symbol', 'doubao-ai-csui', 'template'
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
# 按class删除的元素
|
|
16
|
+
'remove_by_class': [
|
|
17
|
+
'watermark-box'
|
|
18
|
+
],
|
|
19
|
+
|
|
20
|
+
# 按属性删除的元素
|
|
21
|
+
'remove_by_attrs': {
|
|
22
|
+
# 'tag_name': {'attr': 'value'}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
# 清空内容但保留标签的条件
|
|
26
|
+
'empty_content_conditions': [
|
|
27
|
+
{
|
|
28
|
+
'tag': 'textarea',
|
|
29
|
+
'condition': lambda el: el.get('style') and 'display:none' in el.get('style')
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
|
|
33
|
+
# 要删除的属性
|
|
34
|
+
'remove_attributes': [
|
|
35
|
+
'style',
|
|
36
|
+
'ssr'
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
# 要删除的属性前缀(包含该前缀的属性都会被删除)
|
|
40
|
+
'remove_attribute_prefixes': [
|
|
41
|
+
'data-v-',
|
|
42
|
+
'data-testid'
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# 执行清理规则
|
|
47
|
+
# 1. 删除指定标签
|
|
48
|
+
for tag_name in cleanup_rules['remove_tags']:
|
|
49
|
+
for element in soup.find_all(tag_name):
|
|
50
|
+
element.decompose()
|
|
51
|
+
|
|
52
|
+
# 2. 按class删除元素
|
|
53
|
+
for class_name in cleanup_rules['remove_by_class']:
|
|
54
|
+
for element in soup.find_all(class_=class_name):
|
|
55
|
+
element.decompose()
|
|
56
|
+
|
|
57
|
+
# 3. 按属性删除元素
|
|
58
|
+
for tag_name, attrs in cleanup_rules['remove_by_attrs'].items():
|
|
59
|
+
for element in soup.find_all(tag_name, attrs=attrs):
|
|
60
|
+
element.decompose()
|
|
61
|
+
|
|
62
|
+
# 4. 清空特定元素内容
|
|
63
|
+
for condition_config in cleanup_rules['empty_content_conditions']:
|
|
64
|
+
tag = condition_config['tag']
|
|
65
|
+
condition_func = condition_config['condition']
|
|
66
|
+
for element in soup.find_all(tag):
|
|
67
|
+
if condition_func(element):
|
|
68
|
+
element.string = ''
|
|
69
|
+
|
|
70
|
+
# 5. 删除属性和属性前缀
|
|
71
|
+
for element in soup.find_all():
|
|
72
|
+
# 删除指定属性
|
|
73
|
+
for attr in cleanup_rules['remove_attributes']:
|
|
74
|
+
if element.has_attr(attr):
|
|
75
|
+
del element[attr]
|
|
76
|
+
|
|
77
|
+
# 删除包含特定前缀的属性
|
|
78
|
+
for attr_prefix in cleanup_rules['remove_attribute_prefixes']:
|
|
79
|
+
for attr in list(element.attrs.keys()):
|
|
80
|
+
if attr.startswith(attr_prefix):
|
|
81
|
+
del element[attr]
|
|
82
|
+
|
|
83
|
+
# 将BeautifulSoup对象转换为字符串
|
|
84
|
+
html_content_str = str(soup)
|
|
85
|
+
return html_content_str
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
with open('element.txt', 'r', encoding='utf-8') as f:
|
|
89
|
+
file_content = f.read()
|
|
90
|
+
optimize = get_optimized_page_html(file_content)
|
|
91
|
+
print(f'原始的html大小:{len(file_content)}')
|
|
92
|
+
print(f'优化之后的html大小:{len(optimize)}')
|
|
93
|
+
with open('optimized.html', 'w', encoding='utf-8') as f:
|
|
94
|
+
f.write(optimize)
|
tests/get_ope.py
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
# @Description:
|
|
4
4
|
# @Time : 2025-08-31 17:41
|
|
5
5
|
# @Author : 毛鹏
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
from mangoautomation.uidrive import DriverObject
|
|
7
|
+
|
|
8
|
+
d = DriverObject(1, )
|
|
9
|
+
d.set_web(web_type=2, # type: ignore
|
|
10
|
+
web_path=3, # type: ignore
|
|
11
|
+
web_max=1,
|
|
12
|
+
web_headers=4,
|
|
13
|
+
web_recording=5,
|
|
14
|
+
web_h5=1,
|
|
15
|
+
web_is_default=1, # type: ignore
|
|
16
|
+
videos_path=2,
|
|
17
|
+
user_cache_path=3)
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# @Project: 芒果测试平台
|
|
3
|
-
# @Description:
|
|
4
|
-
# @Time : 2023-09-09 23:17
|
|
5
|
-
# @Author : 毛鹏
|
|
6
|
-
import time
|
|
7
|
-
|
|
8
|
-
from mangotools.decorator import sync_method_callback
|
|
9
|
-
from mangotools.models import MethodModel
|
|
10
|
-
from ...exceptions import MangoAutomationError
|
|
11
|
-
from ...exceptions.error_msg import ERROR_MSG_0046
|
|
12
|
-
from ...tools import Meta
|
|
13
|
-
from ...uidrives._base_data import BaseData
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class AndroidApplication(metaclass=Meta):
|
|
17
|
-
"""应用操作"""
|
|
18
|
-
|
|
19
|
-
def __init__(self, base_data: BaseData):
|
|
20
|
-
self.base_data = base_data
|
|
21
|
-
|
|
22
|
-
def is_app_installed(self, package_name: str) -> bool:
|
|
23
|
-
return any(package_name in str(i) for i in self.base_data.android.shell("pm list packages"))
|
|
24
|
-
|
|
25
|
-
@sync_method_callback('android', '应用操作', 0,
|
|
26
|
-
[MethodModel(n='包名', f='package_name', p='请输入应用名称', d=True)])
|
|
27
|
-
def a_start_app(self, package_name: str):
|
|
28
|
-
"""启动应用"""
|
|
29
|
-
if not package_name:
|
|
30
|
-
raise MangoAutomationError(*ERROR_MSG_0046)
|
|
31
|
-
if not self.is_app_installed(package_name):
|
|
32
|
-
raise MangoAutomationError(*ERROR_MSG_0046)
|
|
33
|
-
self.base_data.android.app_start(package_name)
|
|
34
|
-
time.sleep(4)
|
|
35
|
-
|
|
36
|
-
@sync_method_callback('android', '应用操作', 1, [
|
|
37
|
-
MethodModel(n='包名', f='package_name', p='请输入应用名称', d=True)])
|
|
38
|
-
def a_close_app(self, package_name: str):
|
|
39
|
-
"""关闭应用"""
|
|
40
|
-
if not package_name:
|
|
41
|
-
raise MangoAutomationError(*ERROR_MSG_0046)
|
|
42
|
-
if not self.is_app_installed(package_name):
|
|
43
|
-
raise MangoAutomationError(*ERROR_MSG_0046)
|
|
44
|
-
|
|
45
|
-
self.base_data.android.app_stop(package_name)
|
|
46
|
-
|
|
47
|
-
@sync_method_callback('android', '应用操作', 2, [
|
|
48
|
-
MethodModel(n='包名', f='package_name', p='请输入应用名称', d=True)])
|
|
49
|
-
def a_clear_app(self, package_name: str):
|
|
50
|
-
"""清除app数据"""
|
|
51
|
-
if not package_name:
|
|
52
|
-
raise MangoAutomationError(*ERROR_MSG_0046)
|
|
53
|
-
if not self.is_app_installed(package_name):
|
|
54
|
-
raise MangoAutomationError(*ERROR_MSG_0046)
|
|
55
|
-
|
|
56
|
-
self.base_data.android.app_clear(package_name)
|
|
57
|
-
|
|
58
|
-
@sync_method_callback('android', '应用操作', 3)
|
|
59
|
-
def a_app_stop_all(self):
|
|
60
|
-
"""停止所有app"""
|
|
61
|
-
self.base_data.android.app_stop_all()
|
|
62
|
-
|
|
63
|
-
@sync_method_callback('android', '应用操作', 4, [
|
|
64
|
-
MethodModel(n='包名List', f='package_name', p='请输入应用名称列表', d=True)])
|
|
65
|
-
def a_app_stop_appoint(self, package_name_list: list):
|
|
66
|
-
"""停止除指定app外所有app"""
|
|
67
|
-
for i in package_name_list:
|
|
68
|
-
if not self.is_app_installed(i):
|
|
69
|
-
raise MangoAutomationError(*ERROR_MSG_0046)
|
|
70
|
-
self.base_data.android.app_stop_all(excludes=package_name_list)
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# @Project: 芒果测试平台
|
|
3
|
-
# @Description:
|
|
4
|
-
# @Time : 2023-09-09 23:17
|
|
5
|
-
# @Author : 毛鹏
|
|
6
|
-
from uiautomator2 import UiObject
|
|
7
|
-
|
|
8
|
-
from mangoautomation.tools import Meta
|
|
9
|
-
from mangoautomation.uidrives._base_data import BaseData
|
|
10
|
-
from mangotools.decorator import sync_method_callback
|
|
11
|
-
from mangotools.models import MethodModel
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class AndroidAssertion(metaclass=Meta):
|
|
15
|
-
"""元素断言"""
|
|
16
|
-
|
|
17
|
-
def __init__(self, base_data: BaseData):
|
|
18
|
-
self.base_data = base_data
|
|
19
|
-
|
|
20
|
-
@sync_method_callback('ass_android', '元素断言', 1, [
|
|
21
|
-
MethodModel(f='actual')])
|
|
22
|
-
def a_assert_ele_exists(self, actual: UiObject):
|
|
23
|
-
"""元素存在"""
|
|
24
|
-
assert actual.count, f'实际={actual.count}, 预期=元素存在'
|
|
25
|
-
return f'实际={actual.count}, 预期=元素存在'
|
|
26
|
-
|
|
27
|
-
@sync_method_callback('ass_android', '元素断言', 2, [
|
|
28
|
-
MethodModel(f='actual'),
|
|
29
|
-
MethodModel(n='预期值', f='expect', p='请输入预期内容', d=True)])
|
|
30
|
-
def a_assert_ele_count(self, actual: UiObject, expect):
|
|
31
|
-
"""元素计数"""
|
|
32
|
-
assert int(actual.count) == int(expect), f'实际={actual.count}, 预期={expect}'
|
|
33
|
-
return f'实际={actual.count}, 预期={expect}'
|
|
34
|
-
|
|
35
|
-
@sync_method_callback('ass_android', '元素断言', 3, [
|
|
36
|
-
MethodModel(f='actual'),
|
|
37
|
-
MethodModel(n='预期值', f='expect', p='请输入预期文本', d=True)])
|
|
38
|
-
def a_assert_ele_text(self, actual: UiObject, expect: str):
|
|
39
|
-
"""元素文本内容"""
|
|
40
|
-
assert actual.get_text() == expect, f"实际='{actual.get_text()}', 预期='{expect}'"
|
|
41
|
-
return f'实际={actual.get_text()}, 预期={expect}'
|
|
42
|
-
|
|
43
|
-
@sync_method_callback('ass_android', '元素断言', 4, [
|
|
44
|
-
MethodModel(f='actual')])
|
|
45
|
-
def a_assert_ele_clickable_true(self, actual: UiObject):
|
|
46
|
-
"""元素可点击"""
|
|
47
|
-
assert actual.info['clickable'], f"实际={actual.info['clickable']}, 预期=可点击"
|
|
48
|
-
return f"实际={actual.info['clickable']}, 预期=可点击"
|
|
49
|
-
|
|
50
|
-
@sync_method_callback('ass_android', '元素断言', 5, [
|
|
51
|
-
MethodModel(f='actual')])
|
|
52
|
-
def a_assert_ele_clickable_false(self, actual: UiObject):
|
|
53
|
-
"""元素不可点击"""
|
|
54
|
-
assert not actual.info['clickable'], f"实际={actual.info['clickable']}, 预期=元素不可点击"
|
|
55
|
-
return f"实际={actual.info['clickable']}, 预期=元素不可点击"
|
|
56
|
-
|
|
57
|
-
@sync_method_callback('ass_android', '元素断言', 6, [
|
|
58
|
-
MethodModel(f='actual')])
|
|
59
|
-
def a_assert_ele_visible_true(self, actual: UiObject):
|
|
60
|
-
"""元素可见"""
|
|
61
|
-
assert actual.exists and actual.info['visible'], f"实际={actual.info['visible']}, 预期=元素可见"
|
|
62
|
-
|
|
63
|
-
return f"实际={actual.info['visible']}, 预期=元素可见"
|
|
64
|
-
|
|
65
|
-
@sync_method_callback('ass_android', '元素断言', 7, [
|
|
66
|
-
MethodModel(f='actual')])
|
|
67
|
-
def a_assert_ele_visible_false(self, actual: UiObject):
|
|
68
|
-
"""元素不可见"""
|
|
69
|
-
assert actual.exists and not actual.info['visible'], f"实际={actual.info['visible']}, 预期=元素不可见"
|
|
70
|
-
return f"实际={actual.info['visible']}, 预期=元素不可见"
|
|
71
|
-
|
|
72
|
-
@sync_method_callback('ass_android', '元素断言', 8, [
|
|
73
|
-
MethodModel(n='预期值', f='expect', p='请输入弹窗标题文本', d=False)])
|
|
74
|
-
def a_assert_dialog_exists(self, expect: str):
|
|
75
|
-
"""弹窗存在"""
|
|
76
|
-
dialog = self.base_data.android(text=expect) if expect else self.base_data.android(
|
|
77
|
-
className="android.app.AlertDialog")
|
|
78
|
-
assert dialog.exists, "未找到预期弹窗"
|
|
79
|
-
return f"实际={dialog.exists}, 预期=弹窗存在"
|
|
80
|
-
|
|
81
|
-
@sync_method_callback('ass_android', '元素断言', 9, [
|
|
82
|
-
MethodModel(f='actual'),
|
|
83
|
-
MethodModel(n='预期值', f='expect', p='请输入断言目标文本', d=True)])
|
|
84
|
-
def a_assert_ele_in_list(self, actual: UiObject, expect: str):
|
|
85
|
-
"""列表滑动后目标元素存在"""
|
|
86
|
-
if not actual.exists:
|
|
87
|
-
raise AssertionError("传入的元素不是可滑动的列表")
|
|
88
|
-
actual.scroll.vert.to(text=expect)
|
|
89
|
-
assert self.base_data.android(text=expect).exists, f"列表中未找到文本: {expect}"
|
|
90
|
-
return f"实际={self.base_data.android(text=expect).exists}, 预期={expect}"
|
|
@@ -1,15 +0,0 @@
|
|
|
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.uidrives._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
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# @Project: 芒果测试平台
|
|
3
|
-
# @Description:
|
|
4
|
-
# @Time : 2023-09-09 23:17
|
|
5
|
-
# @Author : 毛鹏
|
|
6
|
-
import os.path
|
|
7
|
-
|
|
8
|
-
import time
|
|
9
|
-
from uiautomator2 import UiObject
|
|
10
|
-
from uiautomator2.xpath import XPathSelector
|
|
11
|
-
|
|
12
|
-
from mangotools.decorator import sync_method_callback
|
|
13
|
-
from mangotools.models import MethodModel
|
|
14
|
-
from ...exceptions import MangoAutomationError
|
|
15
|
-
from ...exceptions.error_msg import ERROR_MSG_0043, ERROR_MSG_0044
|
|
16
|
-
from ...tools import Meta
|
|
17
|
-
from ...uidrives._base_data import BaseData
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class AndroidElement(metaclass=Meta):
|
|
21
|
-
"""元素操作"""
|
|
22
|
-
|
|
23
|
-
def __init__(self, base_data: BaseData):
|
|
24
|
-
self.base_data = base_data
|
|
25
|
-
|
|
26
|
-
@sync_method_callback('android', '元素操作', 0, [
|
|
27
|
-
MethodModel(f='locating')])
|
|
28
|
-
def a_click(self, locating: UiObject | XPathSelector):
|
|
29
|
-
"""元素单击"""
|
|
30
|
-
locating.click()
|
|
31
|
-
|
|
32
|
-
@sync_method_callback('android', '元素操作', 1, [
|
|
33
|
-
MethodModel(f='locating')])
|
|
34
|
-
def a_double_click(self, locating: UiObject):
|
|
35
|
-
"""元素双击"""
|
|
36
|
-
locating.click()
|
|
37
|
-
|
|
38
|
-
@sync_method_callback('android', '元素操作', 2, [
|
|
39
|
-
MethodModel(n='输入文本', f='locating'), MethodModel(f='text', p='请输入内容', d=True)])
|
|
40
|
-
def a_input(self, locating: UiObject, text):
|
|
41
|
-
"""单击输入"""
|
|
42
|
-
locating.click()
|
|
43
|
-
self.base_data.android.set_fastinput_ime(True)
|
|
44
|
-
time.sleep(1)
|
|
45
|
-
self.base_data.android.send_keys(text)
|
|
46
|
-
|
|
47
|
-
@sync_method_callback('android', '元素操作', 3, [
|
|
48
|
-
MethodModel(f='locating'), MethodModel(n='设置文本', f='text', p='请输入内容', d=True)])
|
|
49
|
-
def a_set_text(self, locating: UiObject, text):
|
|
50
|
-
"""设置文本"""
|
|
51
|
-
locating.set_text(text)
|
|
52
|
-
|
|
53
|
-
@sync_method_callback('android', '元素操作', 4, [
|
|
54
|
-
MethodModel(f='locating'),
|
|
55
|
-
MethodModel(n='x坐标', f='x', p='请输入x坐标', d=True),
|
|
56
|
-
MethodModel(n='y坐标', f='y', p='请输入y坐标', d=True)])
|
|
57
|
-
def a_click_coord(self, x, y):
|
|
58
|
-
"""坐标单击"""
|
|
59
|
-
self.base_data.android.click(x, y)
|
|
60
|
-
|
|
61
|
-
@sync_method_callback('android', '元素操作', 5, [
|
|
62
|
-
MethodModel(n='x坐标', f='x', p='请输入x坐标', d=True),
|
|
63
|
-
MethodModel(n='y坐标', f='y', p='请输入y坐标', d=True)])
|
|
64
|
-
def a_double_click_coord(self, x, y):
|
|
65
|
-
"""坐标双击"""
|
|
66
|
-
self.base_data.android.double_click(x, y)
|
|
67
|
-
|
|
68
|
-
@sync_method_callback('android', '元素操作', 6, [
|
|
69
|
-
MethodModel(f='locating'),
|
|
70
|
-
MethodModel(n='长按时间', f='time_', p='请输入长按时间', d=True)])
|
|
71
|
-
def a_long_click(self, locating: UiObject, time_):
|
|
72
|
-
"""长按元素"""
|
|
73
|
-
locating.long_click(duration=float(time_))
|
|
74
|
-
|
|
75
|
-
@sync_method_callback('android', '元素操作', 7, [MethodModel(f='locating')])
|
|
76
|
-
def a_clear_text(self, locating: UiObject):
|
|
77
|
-
"""清空输入框"""
|
|
78
|
-
locating.clear_text()
|
|
79
|
-
|
|
80
|
-
@sync_method_callback('android', '元素操作', 8, [
|
|
81
|
-
MethodModel(f='locating'), MethodModel(n='缓存的key', f='set_cache_key', p='请输入元素文本存储的key', d=True)])
|
|
82
|
-
def a_get_text(self, locating: UiObject, set_cache_key=None):
|
|
83
|
-
"""获取元素文本"""
|
|
84
|
-
value = locating.get_text()
|
|
85
|
-
if set_cache_key:
|
|
86
|
-
self.base_data.test_data.set_cache(key=set_cache_key, value=value)
|
|
87
|
-
return value
|
|
88
|
-
|
|
89
|
-
@sync_method_callback('android', '元素操作', 9, [
|
|
90
|
-
MethodModel(f='locating'),
|
|
91
|
-
MethodModel(n='截图名称', f='file_name', p='请输入元素截图存储的名称,后续可以通过名称获取', d=True)])
|
|
92
|
-
def a_element_screenshot(self, locating: UiObject, file_name: str):
|
|
93
|
-
"""元素截图"""
|
|
94
|
-
im = locating.screenshot()
|
|
95
|
-
file_path = os.path.join(self.base_data.screenshot_path, file_name)
|
|
96
|
-
self.base_data.test_data.set_cache(file_name, file_path)
|
|
97
|
-
im.save(file_path)
|
|
98
|
-
|
|
99
|
-
@sync_method_callback('android', '元素操作', 10, [
|
|
100
|
-
MethodModel(f='locating')])
|
|
101
|
-
def a_pinch_in(self, locating: UiObject):
|
|
102
|
-
"""元素缩小"""
|
|
103
|
-
locating.pinch_in()
|
|
104
|
-
|
|
105
|
-
@sync_method_callback('android', '元素操作', 11, [
|
|
106
|
-
MethodModel(f='locating')])
|
|
107
|
-
def a_pinch_out(self, locating: UiObject):
|
|
108
|
-
"""元素放大"""
|
|
109
|
-
locating.pinch_out()
|
|
110
|
-
|
|
111
|
-
@sync_method_callback('android', '元素操作', 12, [
|
|
112
|
-
MethodModel(f='locating'), MethodModel(n='等待时间', f='time_', p='请输入等待元素出现的时间', d=True)])
|
|
113
|
-
def a_wait(self, locating: UiObject, time_):
|
|
114
|
-
"""等待元素出现"""
|
|
115
|
-
if not locating.wait(timeout=float(time_)):
|
|
116
|
-
raise MangoAutomationError(*ERROR_MSG_0043)
|
|
117
|
-
|
|
118
|
-
@sync_method_callback('android', '元素操作', 13, [
|
|
119
|
-
MethodModel(f='locating'), MethodModel(n='等待时间', f='time_', p='请输入等待元素消失的时间', d=True)])
|
|
120
|
-
def a_wait_gone(self, locating: UiObject, time_: str):
|
|
121
|
-
"""等待元素消失"""
|
|
122
|
-
if not locating.wait_gone(timeout=float(time_)):
|
|
123
|
-
raise MangoAutomationError(*ERROR_MSG_0044)
|
|
124
|
-
|
|
125
|
-
@sync_method_callback('android', '元素操作', 14, [
|
|
126
|
-
MethodModel(f='locating'), MethodModel(f='locating2')])
|
|
127
|
-
def a_drag_to_ele(self, locating: UiObject, locating2: UiObject):
|
|
128
|
-
"""拖动A元素到达B元素上"""
|
|
129
|
-
locating.drag_to(locating2)
|
|
130
|
-
|
|
131
|
-
@sync_method_callback('android', '元素操作', 15, [
|
|
132
|
-
MethodModel(f='locating'),
|
|
133
|
-
MethodModel(n='x坐标', f='x', p='请输入x坐标', d=True),
|
|
134
|
-
MethodModel(n='y坐标', f='y', p='请输入y坐标', d=True)])
|
|
135
|
-
def a_drag_to_coord(self, locating: UiObject, x, y):
|
|
136
|
-
"""拖动元素到坐标上"""
|
|
137
|
-
locating.drag_to(x, y)
|
|
138
|
-
|
|
139
|
-
@sync_method_callback('android', '元素操作', 16, [MethodModel(f='locating')])
|
|
140
|
-
def a_swipe_right(self, locating: UiObject):
|
|
141
|
-
"""元素内向右滑动"""
|
|
142
|
-
locating.swipe('right')
|
|
143
|
-
|
|
144
|
-
@sync_method_callback('android', '元素操作', 17, [MethodModel(f='locating')])
|
|
145
|
-
def a_swipe_left(self, locating: UiObject):
|
|
146
|
-
"""元素内向左滑动"""
|
|
147
|
-
locating.swipe('left')
|
|
148
|
-
|
|
149
|
-
@sync_method_callback('android', '元素操作', 18, [MethodModel(f='locating')])
|
|
150
|
-
def a_swipe_up(self, locating: UiObject):
|
|
151
|
-
"""元素内向上滑动"""
|
|
152
|
-
locating.swipe('up')
|
|
153
|
-
|
|
154
|
-
@sync_method_callback('android', '元素操作', 19, [MethodModel(f='locating')])
|
|
155
|
-
def a_swipe_ele(self, locating: UiObject):
|
|
156
|
-
"""元素内向下滑动"""
|
|
157
|
-
locating.swipe('down')
|
|
158
|
-
|
|
159
|
-
@sync_method_callback('android', '元素操作', 20, [
|
|
160
|
-
MethodModel(f='locating'),
|
|
161
|
-
MethodModel(n='x坐标', f='x_key', p='请输入x坐标', d=True),
|
|
162
|
-
MethodModel(n='y坐标', f='y_key', p='请输入y坐标', d=True)])
|
|
163
|
-
def a_get_center(self, locating: UiObject, x_key, y_key):
|
|
164
|
-
"""提取元素坐标"""
|
|
165
|
-
x, y = locating.center()
|
|
166
|
-
if x_key and y_key:
|
|
167
|
-
self.base_data.test_data.set_cache(key=x_key, value=x)
|
|
168
|
-
self.base_data.test_data.set_cache(key=y_key, value=y)
|
|
169
|
-
return x, y
|