mangoautomation 1.1.21__py3-none-any.whl → 1.1.23__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/__init__.py +1 -1
- mangoautomation/enums/__init__.py +0 -2
- mangoautomation/exceptions/__init__.py +0 -3
- mangoautomation/exceptions/error_msg.py +4 -4
- mangoautomation/mangos/__init__.py +14 -0
- 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/models/__init__.py +0 -2
- mangoautomation/models/_ui_model.py +2 -1
- mangoautomation/tools/__init__.py +0 -2
- mangoautomation/tools/_uiautodev.py +1 -3
- mangoautomation/uidrive/__init__.py +5 -7
- mangoautomation/uidrives/__init__.py +21 -0
- mangoautomation/{uidrive → uidrives}/_async_element.py +80 -52
- mangoautomation/{uidrive → uidrives}/_base_data.py +16 -4
- mangoautomation/{uidrive → uidrives}/_driver_object.py +2 -4
- mangoautomation/{uidrive → uidrives}/_sync_element.py +78 -50
- mangoautomation/{uidrive → uidrives}/android/__init__.py +2 -16
- mangoautomation/{uidrive → uidrives}/android/_application.py +1 -1
- mangoautomation/{uidrive → uidrives}/android/_assertion.py +1 -1
- mangoautomation/{uidrive → uidrives}/android/_customization.py +1 -1
- mangoautomation/{uidrive → uidrives}/android/_element.py +3 -3
- mangoautomation/{uidrive → uidrives}/android/_equipment.py +1 -1
- mangoautomation/{uidrive → uidrives}/android/_page.py +1 -1
- mangoautomation/{uidrive → uidrives}/pc/__init__.py +3 -4
- mangoautomation/{uidrive → uidrives}/pc/customization.py +1 -1
- mangoautomation/{uidrive → uidrives}/pc/element.py +1 -2
- mangoautomation/{uidrive → uidrives}/pc/input_device.py +1 -2
- mangoautomation/uidrives/web/__init__.py +10 -0
- mangoautomation/uidrives/web/_async_web.py +166 -0
- mangoautomation/uidrives/web/_sync_web.py +166 -0
- mangoautomation/{uidrive → uidrives}/web/async_web/__init__.py +8 -8
- mangoautomation/{uidrive → uidrives}/web/async_web/_assertion.py +1 -1
- mangoautomation/{uidrive → uidrives}/web/async_web/_browser.py +2 -2
- mangoautomation/{uidrive → uidrives}/web/async_web/_customization.py +1 -1
- mangoautomation/{uidrive → uidrives}/web/async_web/_element.py +3 -13
- mangoautomation/{uidrive → uidrives}/web/async_web/_input_device.py +1 -1
- mangoautomation/{uidrive → uidrives}/web/async_web/_page.py +1 -1
- mangoautomation/{uidrive → uidrives}/web/sync_web/__init__.py +8 -8
- mangoautomation/{uidrive → uidrives}/web/sync_web/_assertion.py +1 -1
- mangoautomation/{uidrive → uidrives}/web/sync_web/_browser.py +3 -3
- mangoautomation/{uidrive → uidrives}/web/sync_web/_customization.py +1 -1
- mangoautomation/{uidrive → uidrives}/web/sync_web/_element.py +3 -13
- mangoautomation/{uidrive → uidrives}/web/sync_web/_input_device.py +1 -1
- mangoautomation/{uidrive → uidrives}/web/sync_web/_page.py +2 -2
- {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/METADATA +4 -4
- mangoautomation-1.1.23.dist-info/RECORD +71 -0
- tests/__init__.py +0 -10
- tests/demo1.py +21 -0
- tests/test_ai_element.py +36 -0
- tests/test_ui_web.py +31 -31
- mangoautomation/uidrive/web/__init__.py +0 -5
- mangoautomation-1.1.21.dist-info/RECORD +0 -58
- /mangoautomation/{uidrive → uidrives}/android/_new_android.py +0 -0
- /mangoautomation/{uidrive → uidrives}/ios/__init__.py +0 -0
- /mangoautomation/{uidrive → uidrives}/pc/assertion.py +0 -0
- /mangoautomation/{uidrive → uidrives}/pc/new_windows.py +0 -0
- /mangoautomation/{uidrive → uidrives}/web/async_web/_new_browser.py +0 -0
- /mangoautomation/{uidrive → uidrives}/web/sync_web/_new_browser.py +0 -0
- {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/LICENSE +0 -0
- {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/WHEEL +0 -0
- {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/top_level.txt +0 -0
mangoautomation/__init__.py
CHANGED
|
@@ -14,7 +14,7 @@ ERROR_MSG_0007 = (4007, '安卓设备被关闭,请检查设备')
|
|
|
14
14
|
ERROR_MSG_0008 = (4008, '浏览器类型不正确,请联系管理员检查')
|
|
15
15
|
ERROR_MSG_0009 = (4009, '浏览器路径不正确,请手动设置一个正确的浏览器路径,现在的路径:{}')
|
|
16
16
|
ERROR_MSG_0010 = (4010, '浏览器被关闭,请不要手动关闭浏览器')
|
|
17
|
-
ERROR_MSG_0011 = (4011, '操作元素【{}
|
|
17
|
+
ERROR_MSG_0011 = (4011, '操作元素【{}】超时,请检查元素是否可见,或可以进行对应的操作')
|
|
18
18
|
ERROR_MSG_0012 = (4012, '操作失败,请检查输入的值是否有空字符串,null或不满足传参的值')
|
|
19
19
|
ERROR_MSG_0013 = (
|
|
20
20
|
313, '打开url时超时,分为2个问题:1.启用的浏览器过多,应当减少浏览器并发个数;2.自行查看为啥60秒还未打开:{}')
|
|
@@ -33,7 +33,7 @@ ERROR_MSG_0025 = (4025, '无法元素对应的下标,请检查通过下标获
|
|
|
33
33
|
ERROR_MSG_0026 = (4026, '')
|
|
34
34
|
ERROR_MSG_0027 = (4027,
|
|
35
35
|
'您元素的操作内容中没有任何的数据,请检查:1.页面步骤详情中字段->元素操作值是否是空,是空可能是你删除了,也可能是执行器的操作选项没有同步需要点击执行器的同步发送缓存数据;2.元素表达式错误导致查询不到元素;')
|
|
36
|
-
ERROR_MSG_0028 = (4028, '')
|
|
36
|
+
ERROR_MSG_0028 = (4028, 'AI查找元素出现顶级异常,请联系管理员检查!')
|
|
37
37
|
ERROR_MSG_0029 = (4029, '页面无元素【{}】,表达式:{}')
|
|
38
38
|
ERROR_MSG_0030 = (4030, '断言时没有找到元素')
|
|
39
39
|
ERROR_MSG_0031 = (4031, '元素未找到准备进行断言获取元素文本类容异常')
|
|
@@ -48,13 +48,13 @@ ERROR_MSG_0043 = (4043, '元素【{}】可能不存在,报错信息:{}')
|
|
|
48
48
|
ERROR_MSG_0044 = (4044, '元素【{}】可能无法消失,报错信息:{}')
|
|
49
49
|
ERROR_MSG_0045 = (4045, '设备启动超时!请检查设备是否已成功连接电脑,设备号:{}')
|
|
50
50
|
ERROR_MSG_0046 = (4046, '您要测试的设备中,没有您输入的包名,请检查包名是否正确,或者设备是否安装了这个软件包')
|
|
51
|
-
ERROR_MSG_0047 = (4047, '')
|
|
51
|
+
ERROR_MSG_0047 = (4047, 'AI定位元素超过最大次数')
|
|
52
52
|
ERROR_MSG_0048 = (4048, '选项发生错误,请在执行器点击发送缓存数据,然后重新修改步骤的操作!或联系管理员处理!')
|
|
53
53
|
ERROR_MSG_0049 = (4049, 'url格式错误,请检查url或者是选择的测试环境不正确')
|
|
54
54
|
ERROR_MSG_0050 = (4050, 'xpath定位未找到元素')
|
|
55
55
|
ERROR_MSG_0051 = (4051, '')
|
|
56
56
|
ERROR_MSG_0052 = (4052, '元素【{}】 进行断言时发生异常,请检查元素是否可以正常使用')
|
|
57
|
-
ERROR_MSG_0053 = (4053, '')
|
|
57
|
+
ERROR_MSG_0053 = (4053, '元素个数小于1,准备对元素的操作默认失败,请检查元素定位是否准确')
|
|
58
58
|
ERROR_MSG_0054 = (4054, '步骤是操作类型,但是你没有输入操作内容,请查看文档中对元素操作的介绍')
|
|
59
59
|
ERROR_MSG_0055 = (4055, '您的电脑未安装指定浏览器!')
|
|
60
60
|
ERROR_MSG_0056 = (4056, '输入的参数类型不正确,请检查操作输入框的类型是否正确')
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# @Project: 芒果测试平台
|
|
3
|
+
# @Description:
|
|
4
|
+
# @Time : 2025-10-27 17:09
|
|
5
|
+
# @Author : 毛鹏
|
|
6
|
+
from .mangos import *
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'ElementMain','mango_send',
|
|
10
|
+
'AsyncWebAssertion', 'AsyncWebBrowser', 'AsyncWebCustomization', 'AsyncWebElement', 'AsyncWebDeviceInput', 'AsyncWebNewBrowser', 'AsyncWebPage',
|
|
11
|
+
'SyncWebAssertion', 'SyncWebBrowser', 'SyncWebCustomization', 'SyncWebElement', 'SyncWebDeviceInput', 'SyncWebNewBrowser', 'SyncWebPage',
|
|
12
|
+
'AndroidApplication','AndroidAssertion', 'AndroidCustomization','AndroidElement','AndroidEquipment', 'NewAndroid', 'AndroidPage',
|
|
13
|
+
'WebAIFinder'
|
|
14
|
+
]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import subprocess
|
|
8
8
|
|
|
9
|
-
import time
|
|
10
|
-
|
|
11
9
|
uiautodev_process = None
|
|
12
10
|
|
|
13
11
|
|
|
@@ -39,7 +37,7 @@ def stop_uiautodev():
|
|
|
39
37
|
try:
|
|
40
38
|
uiautodev_process.terminate()
|
|
41
39
|
uiautodev_process.wait(timeout=5)
|
|
42
|
-
return
|
|
40
|
+
return "uiautodev 服务已关闭"
|
|
43
41
|
except subprocess.TimeoutExpired:
|
|
44
42
|
uiautodev_process.kill()
|
|
45
43
|
return "uiautodev 服务被强制终止"
|
|
@@ -2,17 +2,15 @@
|
|
|
2
2
|
# @Project: 芒果测试平台
|
|
3
3
|
# @Description: # @Time : 2023-07-15 11:57
|
|
4
4
|
# @Author : 毛鹏
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
from ..uidrive._async_element import AsyncElement
|
|
8
|
-
from ..uidrive._base_data import BaseData
|
|
9
|
-
from ..uidrive._driver_object import DriverObject
|
|
10
|
-
from ..uidrive._sync_element import SyncElement
|
|
11
|
-
|
|
5
|
+
from ..uidrives import *
|
|
12
6
|
|
|
13
7
|
__all__ = [
|
|
14
8
|
'AsyncElement',
|
|
15
9
|
'BaseData',
|
|
16
10
|
'DriverObject',
|
|
17
11
|
'SyncElement',
|
|
12
|
+
'AsyncWebDevice',
|
|
13
|
+
'SyncWebDevice',
|
|
14
|
+
'AsyncWebCustomization',
|
|
15
|
+
'SyncWebCustomization',
|
|
18
16
|
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# @Project: 芒果测试平台
|
|
3
|
+
# @Description: # @Time : 2023-07-15 11:57
|
|
4
|
+
# @Author : 毛鹏
|
|
5
|
+
|
|
6
|
+
from .web import AsyncWebDevice, AsyncWebCustomization, SyncWebDevice, SyncWebCustomization
|
|
7
|
+
from ..uidrives._async_element import AsyncElement
|
|
8
|
+
from ..uidrives._base_data import BaseData
|
|
9
|
+
from ..uidrives._driver_object import DriverObject
|
|
10
|
+
from ..uidrives._sync_element import SyncElement
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'BaseData',
|
|
14
|
+
'DriverObject',
|
|
15
|
+
'AsyncElement',
|
|
16
|
+
'SyncElement',
|
|
17
|
+
'AsyncWebDevice',
|
|
18
|
+
'SyncWebDevice',
|
|
19
|
+
'AsyncWebCustomization',
|
|
20
|
+
'SyncWebCustomization',
|
|
21
|
+
]
|
|
@@ -5,12 +5,15 @@
|
|
|
5
5
|
# @Author : 毛鹏
|
|
6
6
|
import asyncio
|
|
7
7
|
import os
|
|
8
|
-
import random
|
|
9
8
|
import traceback
|
|
10
9
|
from typing import Optional
|
|
11
10
|
|
|
11
|
+
import itertools
|
|
12
12
|
from playwright._impl._errors import TargetClosedError, Error
|
|
13
13
|
|
|
14
|
+
from mangoautomation.mangos import WebAIFinder
|
|
15
|
+
from mangoautomation.uidrives.android import AndroidDriver
|
|
16
|
+
from mangoautomation.uidrives.web import AsyncWebDevice, AsyncWebAssertion
|
|
14
17
|
from mangotools.assertion import MangoAssertion
|
|
15
18
|
from mangotools.decorator import async_retry
|
|
16
19
|
from mangotools.enums import StatusEnum
|
|
@@ -18,8 +21,6 @@ from ..enums import ElementOperationEnum, DriveTypeEnum
|
|
|
18
21
|
from ..exceptions import MangoAutomationError
|
|
19
22
|
from ..exceptions.error_msg import *
|
|
20
23
|
from ..models import ElementResultModel, ElementModel, ElementListResultModel
|
|
21
|
-
from ..uidrive.android import AndroidDriver
|
|
22
|
-
from ..uidrive.web.async_web import AsyncWebDevice, AsyncWebAssertion
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class AsyncElement(AsyncWebDevice, AndroidDriver):
|
|
@@ -31,6 +32,12 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
|
|
|
31
32
|
self.element_result_model: Optional[ElementResultModel | None] = None
|
|
32
33
|
self.element_list_model: list[ElementModel] = []
|
|
33
34
|
self.test_data = self.base_data.test_data
|
|
35
|
+
self.elements = itertools.cycle([])
|
|
36
|
+
self.elements_count = 0
|
|
37
|
+
self.failed_expression = []
|
|
38
|
+
if self.base_data.is_ai:
|
|
39
|
+
self.agent = WebAIFinder(self.base_data.log, self.base_data.api_key, self.base_data.base_url,
|
|
40
|
+
self.base_data.model)
|
|
34
41
|
|
|
35
42
|
async def open_device(self, is_open: bool = False):
|
|
36
43
|
if self.drive_type == DriveTypeEnum.WEB.value:
|
|
@@ -45,8 +52,10 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
|
|
|
45
52
|
|
|
46
53
|
async def element_main(self,
|
|
47
54
|
element_model: ElementModel,
|
|
48
|
-
element_list_model: list[ElementModel]) -> ElementResultModel:
|
|
55
|
+
element_list_model: list[ElementModel] | None = None) -> ElementResultModel:
|
|
49
56
|
self.element_model = element_model
|
|
57
|
+
if self.element_model and self.element_model.elements:
|
|
58
|
+
self.elements = itertools.cycle(self.element_model.elements)
|
|
50
59
|
self.element_list_model = element_list_model
|
|
51
60
|
self.element_result_model = ElementResultModel(
|
|
52
61
|
id=self.element_model.id,
|
|
@@ -195,7 +204,9 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
|
|
|
195
204
|
|
|
196
205
|
async def __custom(self):
|
|
197
206
|
for i in self.element_model.custom:
|
|
198
|
-
|
|
207
|
+
value = self.base_data.test_data.replace(i.get('value'))
|
|
208
|
+
self.base_data.log.debug(f'开始执行自定义-1:key: {i.get("key")}, value: {value}')
|
|
209
|
+
self.base_data.test_data.set_cache(i.get('key'), value)
|
|
199
210
|
|
|
200
211
|
async def __condition(self):
|
|
201
212
|
error_list = []
|
|
@@ -222,54 +233,72 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
|
|
|
222
233
|
ope_key = 'actual' if is_ass else 'locating'
|
|
223
234
|
for i in self.element_model.ope_value:
|
|
224
235
|
if i.f == ope_key and self.element_model.elements:
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
'_type': self.element_model.type,
|
|
229
|
-
'exp': self.element_model.elements[random_element].exp,
|
|
230
|
-
'loc': self.element_model.elements[random_element].loc,
|
|
231
|
-
'sub': self.element_model.elements[random_element].sub
|
|
232
|
-
}
|
|
233
|
-
if self.drive_type == DriveTypeEnum.WEB.value:
|
|
234
|
-
loc, ele_quantity, element_text = await self.web_find_ele(
|
|
235
|
-
**find_params, is_iframe=self.element_model.elements[random_element].is_iframe)
|
|
236
|
-
elif self.drive_type == DriveTypeEnum.ANDROID.value:
|
|
237
|
-
loc, ele_quantity, element_text = self.a_find_ele(**find_params)
|
|
238
|
-
else:
|
|
239
|
-
loc, ele_quantity, element_text = None, 0, None
|
|
240
|
-
new_element = ElementListResultModel(
|
|
241
|
-
exp=self.element_model.elements[random_element].exp,
|
|
242
|
-
loc=self.element_model.elements[random_element].loc,
|
|
243
|
-
sub=self.element_model.elements[random_element].sub,
|
|
244
|
-
ele_quantity=ele_quantity,
|
|
245
|
-
element_text=element_text,
|
|
246
|
-
is_iframe=self.element_model.elements[random_element].is_iframe
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
element_exists = any(
|
|
250
|
-
existing.exp == new_element.exp and
|
|
251
|
-
existing.loc == new_element.loc and
|
|
252
|
-
existing.sub == new_element.sub and
|
|
253
|
-
existing.is_iframe == new_element.is_iframe
|
|
254
|
-
for existing in self.element_result_model.elements
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
if not element_exists:
|
|
258
|
-
self.element_result_model.elements.append(new_element)
|
|
259
|
-
if is_ass:
|
|
260
|
-
if callable(getattr(AsyncWebAssertion, self.element_model.ope_key, None)):
|
|
261
|
-
i.v = loc
|
|
262
|
-
elif callable(getattr(MangoAssertion(), self.element_model.ope_key, None)):
|
|
263
|
-
i.v = element_text
|
|
264
|
-
else:
|
|
265
|
-
i.v = loc
|
|
266
|
-
i.v = self.base_data.test_data.replace(i.v)
|
|
267
|
-
|
|
236
|
+
await self.query_element(i, is_ass)
|
|
237
|
+
else:
|
|
238
|
+
i.v = self.base_data.test_data.replace(i.v)
|
|
268
239
|
except AttributeError as error:
|
|
269
240
|
self.base_data.log.debug(
|
|
270
241
|
f'获取操作值失败-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
|
|
271
242
|
raise MangoAutomationError(*ERROR_MSG_0027)
|
|
272
243
|
|
|
244
|
+
async def query_element(self, i, is_ass):
|
|
245
|
+
random_element = next(self.elements)
|
|
246
|
+
self.elements_count += 1
|
|
247
|
+
find_params = {
|
|
248
|
+
'name': self.element_model.name,
|
|
249
|
+
'_type': self.element_model.type,
|
|
250
|
+
'exp': random_element.exp,
|
|
251
|
+
'loc': random_element.loc,
|
|
252
|
+
'sub': random_element.sub
|
|
253
|
+
}
|
|
254
|
+
loc_text = random_element.loc
|
|
255
|
+
try:
|
|
256
|
+
if self.drive_type == DriveTypeEnum.WEB.value:
|
|
257
|
+
loc, ele_quantity, element_text = await self.web_find_element(**find_params,
|
|
258
|
+
is_iframe=random_element.is_iframe)
|
|
259
|
+
elif self.drive_type == DriveTypeEnum.ANDROID.value:
|
|
260
|
+
loc, ele_quantity, element_text = self.a_find_ele(**find_params)
|
|
261
|
+
else:
|
|
262
|
+
loc, ele_quantity, element_text = None, 0, None
|
|
263
|
+
except MangoAutomationError as e:
|
|
264
|
+
if not self.base_data.is_ai:
|
|
265
|
+
raise e
|
|
266
|
+
if self.elements_count < len(self.element_model.elements):
|
|
267
|
+
raise e
|
|
268
|
+
self.failed_expression.append(find_params.get('loc'))
|
|
269
|
+
self.elements_count = 0
|
|
270
|
+
loc, loc_text = await self.agent.ai_find_element_async(self.base_data.page,
|
|
271
|
+
self.element_model.name,
|
|
272
|
+
random_element.prompt,
|
|
273
|
+
failed_expression=self.failed_expression)
|
|
274
|
+
loc, ele_quantity, element_text = await self.ai_element_info(loc)
|
|
275
|
+
if loc_text not in self.failed_expression:
|
|
276
|
+
self.failed_expression.append(loc_text)
|
|
277
|
+
element_exists = any(
|
|
278
|
+
existing.exp == random_element.exp and
|
|
279
|
+
existing.loc == random_element.loc and
|
|
280
|
+
existing.sub == random_element.sub and
|
|
281
|
+
existing.is_iframe == random_element.is_iframe
|
|
282
|
+
for existing in self.element_result_model.elements
|
|
283
|
+
)
|
|
284
|
+
if not element_exists:
|
|
285
|
+
new_element = ElementListResultModel(
|
|
286
|
+
exp=random_element.exp,
|
|
287
|
+
loc=random_element.loc,
|
|
288
|
+
sub=random_element.sub,
|
|
289
|
+
ele_quantity=ele_quantity,
|
|
290
|
+
element_text=element_text,
|
|
291
|
+
is_iframe=random_element.is_iframe
|
|
292
|
+
)
|
|
293
|
+
self.element_result_model.elements.append(new_element)
|
|
294
|
+
if is_ass:
|
|
295
|
+
if callable(getattr(AsyncWebAssertion, self.element_model.ope_key, None)):
|
|
296
|
+
i.v = loc
|
|
297
|
+
elif callable(getattr(MangoAssertion(), self.element_model.ope_key, None)):
|
|
298
|
+
i.v = element_text
|
|
299
|
+
else:
|
|
300
|
+
i.v = loc
|
|
301
|
+
|
|
273
302
|
async def __error(self, msg: str, is_screenshot: bool = True):
|
|
274
303
|
try:
|
|
275
304
|
self.element_result_model.status = StatusEnum.FAIL.value
|
|
@@ -283,10 +312,9 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
|
|
|
283
312
|
"""
|
|
284
313
|
)
|
|
285
314
|
if is_screenshot:
|
|
286
|
-
file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
self.element_result_model.picture_path = file_path
|
|
315
|
+
file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.time_stamp()}.jpg'
|
|
316
|
+
await self.__error_screenshot(file_name)
|
|
317
|
+
self.element_result_model.picture_path = os.path.join(self.base_data.screenshot_path, file_name)
|
|
290
318
|
self.element_result_model.picture_name = file_name
|
|
291
319
|
except MangoAutomationError as error:
|
|
292
320
|
self.element_result_model.error_message += f'执行过程中发生失败,准备截图时截图失败,失败原因:{error.msg}'
|
|
@@ -7,8 +7,8 @@ from typing import Optional
|
|
|
7
7
|
from unittest.mock import MagicMock
|
|
8
8
|
|
|
9
9
|
import sys
|
|
10
|
-
from playwright.async_api import Page as
|
|
11
|
-
from playwright.sync_api import Page as
|
|
10
|
+
from playwright.async_api import Page as AsyncPage, BrowserContext as AsyncBrowserContext
|
|
11
|
+
from playwright.sync_api import Page as SyncPage, BrowserContext as SyncBrowserContext
|
|
12
12
|
from uiautomator2 import Device
|
|
13
13
|
|
|
14
14
|
from mangoautomation.enums import DriveTypeEnum
|
|
@@ -35,13 +35,18 @@ class BaseData:
|
|
|
35
35
|
self.download_path: Optional[str | None] = None
|
|
36
36
|
self.screenshot_path: Optional[str | None] = None
|
|
37
37
|
|
|
38
|
+
self.is_ai = False
|
|
39
|
+
self.api_key = None
|
|
40
|
+
self.base_url = None
|
|
41
|
+
self.model = None
|
|
42
|
+
|
|
38
43
|
self.mysql_config: Optional[MysqlConingModel | None] = None
|
|
39
44
|
self.mysql_connect: Optional[MysqlConnect | None] = None
|
|
40
45
|
|
|
41
46
|
self.url: Optional[str | None] = None
|
|
42
47
|
self.is_open_url = False
|
|
43
|
-
self.page: Optional[
|
|
44
|
-
self.context: Optional[
|
|
48
|
+
self.page: Optional[AsyncPage | SyncPage | None] = None
|
|
49
|
+
self.context: Optional[AsyncBrowserContext | SyncBrowserContext | None] = None
|
|
45
50
|
|
|
46
51
|
self.package_name: Optional[str | None] = None
|
|
47
52
|
self.android: Optional[Device | None] = None
|
|
@@ -116,3 +121,10 @@ class BaseData:
|
|
|
116
121
|
raise MangoAutomationError(*ERROR_MSG_0007)
|
|
117
122
|
else:
|
|
118
123
|
pass
|
|
124
|
+
|
|
125
|
+
def set_agent(self, is_ai: bool, api_key: str, base_url: str='https://api.siliconflow.cn/v1', model: str='THUDM/GLM-Z1-9B-0414'):
|
|
126
|
+
self.is_ai = is_ai
|
|
127
|
+
self.api_key = api_key
|
|
128
|
+
self.base_url = base_url
|
|
129
|
+
self.model = model
|
|
130
|
+
return self
|
|
@@ -5,11 +5,9 @@
|
|
|
5
5
|
# @Author : 毛鹏
|
|
6
6
|
|
|
7
7
|
from typing import Optional
|
|
8
|
+
from mangoautomation.mangos import NewAndroid, AsyncWebNewBrowser, SyncWebNewBrowser
|
|
9
|
+
from ..uidrives.pc.new_windows import NewWindows
|
|
8
10
|
|
|
9
|
-
from ..uidrive.android._new_android import NewAndroid
|
|
10
|
-
from ..uidrive.pc.new_windows import NewWindows
|
|
11
|
-
from ..uidrive.web.async_web._new_browser import AsyncWebNewBrowser
|
|
12
|
-
from ..uidrive.web.sync_web._new_browser import SyncWebNewBrowser
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
class DriverObject:
|
|
@@ -4,22 +4,23 @@
|
|
|
4
4
|
# @Time : 2025-04-12 15:55
|
|
5
5
|
# @Author : 毛鹏
|
|
6
6
|
import os
|
|
7
|
-
import random
|
|
8
7
|
import traceback
|
|
9
8
|
from typing import Optional
|
|
10
9
|
|
|
10
|
+
import itertools
|
|
11
11
|
import time
|
|
12
12
|
from playwright._impl._errors import TargetClosedError, Error
|
|
13
13
|
|
|
14
14
|
from mangotools.assertion import MangoAssertion
|
|
15
15
|
from mangotools.decorator import sync_retry
|
|
16
16
|
from mangotools.enums import StatusEnum
|
|
17
|
+
from mangoautomation.mangos import WebAIFinder
|
|
17
18
|
from ..enums import ElementOperationEnum, DriveTypeEnum
|
|
18
19
|
from ..exceptions import MangoAutomationError
|
|
19
20
|
from ..exceptions.error_msg import *
|
|
20
21
|
from ..models import ElementResultModel, ElementModel, ElementListResultModel
|
|
21
|
-
from ..
|
|
22
|
-
from ..
|
|
22
|
+
from ..uidrives.android import AndroidDriver
|
|
23
|
+
from ..uidrives.web import SyncWebDevice, SyncWebAssertion
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class SyncElement(SyncWebDevice, AndroidDriver):
|
|
@@ -31,6 +32,12 @@ class SyncElement(SyncWebDevice, AndroidDriver):
|
|
|
31
32
|
self.element_result_model: Optional[ElementResultModel | None] = None
|
|
32
33
|
self.element_list_model: Optional[list[ElementModel] | None] = None
|
|
33
34
|
self.test_data = self.base_data.test_data
|
|
35
|
+
self.elements = itertools.cycle([])
|
|
36
|
+
self.elements_count = 0
|
|
37
|
+
self.failed_expression = []
|
|
38
|
+
if self.base_data.is_ai:
|
|
39
|
+
self.agent = WebAIFinder(self.base_data.log, self.base_data.api_key, self.base_data.base_url,
|
|
40
|
+
self.base_data.model)
|
|
34
41
|
|
|
35
42
|
def open_device(self, is_open: bool = False):
|
|
36
43
|
if self.drive_type == DriveTypeEnum.WEB.value:
|
|
@@ -47,6 +54,8 @@ class SyncElement(SyncWebDevice, AndroidDriver):
|
|
|
47
54
|
element_model: ElementModel,
|
|
48
55
|
element_list_model: list[ElementModel] | None = None) -> ElementResultModel:
|
|
49
56
|
self.element_model = element_model
|
|
57
|
+
if self.element_model and self.element_model.elements:
|
|
58
|
+
self.elements = itertools.cycle(self.element_model.elements)
|
|
50
59
|
self.element_list_model = element_list_model
|
|
51
60
|
self.element_result_model = ElementResultModel(
|
|
52
61
|
id=self.element_model.id,
|
|
@@ -195,7 +204,9 @@ class SyncElement(SyncWebDevice, AndroidDriver):
|
|
|
195
204
|
|
|
196
205
|
def __custom(self):
|
|
197
206
|
for i in self.element_model.custom:
|
|
198
|
-
|
|
207
|
+
value = self.base_data.test_data.replace(i.get('value'))
|
|
208
|
+
self.base_data.log.debug(f'开始执行自定义-1:key: {i.get("key")}, value: {value}')
|
|
209
|
+
self.base_data.test_data.set_cache(i.get('key'), value)
|
|
199
210
|
|
|
200
211
|
def __condition(self):
|
|
201
212
|
error_list = []
|
|
@@ -222,54 +233,72 @@ class SyncElement(SyncWebDevice, AndroidDriver):
|
|
|
222
233
|
ope_key = 'actual' if is_ass else 'locating'
|
|
223
234
|
for i in self.element_model.ope_value:
|
|
224
235
|
if i.f == ope_key and self.element_model.elements:
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
'name': self.element_model.name,
|
|
228
|
-
'_type': self.element_model.type,
|
|
229
|
-
'exp': self.element_model.elements[random_element].exp,
|
|
230
|
-
'loc': self.element_model.elements[random_element].loc,
|
|
231
|
-
'sub': self.element_model.elements[random_element].sub
|
|
232
|
-
}
|
|
233
|
-
if self.drive_type == DriveTypeEnum.WEB.value:
|
|
234
|
-
loc, ele_quantity, element_text = self.web_find_ele(
|
|
235
|
-
**find_params,is_iframe=self.element_model.is_iframe)
|
|
236
|
-
elif self.drive_type == DriveTypeEnum.ANDROID.value:
|
|
237
|
-
loc, ele_quantity, element_text = self.a_find_ele(**find_params)
|
|
238
|
-
else:
|
|
239
|
-
loc, ele_quantity, element_text = None, 0, None
|
|
240
|
-
new_element = ElementListResultModel(
|
|
241
|
-
exp=self.element_model.elements[random_element].exp,
|
|
242
|
-
loc=self.element_model.elements[random_element].loc,
|
|
243
|
-
sub=self.element_model.elements[random_element].sub,
|
|
244
|
-
ele_quantity=ele_quantity,
|
|
245
|
-
element_text=element_text,
|
|
246
|
-
is_iframe=self.element_model.elements[random_element].is_iframe
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
element_exists = any(
|
|
250
|
-
existing.exp == new_element.exp and
|
|
251
|
-
existing.loc == new_element.loc and
|
|
252
|
-
existing.sub == new_element.sub and
|
|
253
|
-
existing.is_iframe == new_element.is_iframe
|
|
254
|
-
for existing in self.element_result_model.elements
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
if not element_exists:
|
|
258
|
-
self.element_result_model.elements.append(new_element)
|
|
259
|
-
if is_ass:
|
|
260
|
-
if callable(getattr(SyncWebAssertion, self.element_model.ope_key, None)):
|
|
261
|
-
i.v = loc
|
|
262
|
-
elif callable(getattr(MangoAssertion(), self.element_model.ope_key, None)):
|
|
263
|
-
i.v = element_text
|
|
264
|
-
else:
|
|
265
|
-
i.v = loc
|
|
236
|
+
self.query_element(i, is_ass)
|
|
237
|
+
else:
|
|
266
238
|
i.v = self.base_data.test_data.replace(i.v)
|
|
267
|
-
|
|
268
239
|
except AttributeError as error:
|
|
269
240
|
self.base_data.log.debug(
|
|
270
241
|
f'获取操作值失败-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
|
|
271
242
|
raise MangoAutomationError(*ERROR_MSG_0027)
|
|
272
243
|
|
|
244
|
+
def query_element(self, i, is_ass):
|
|
245
|
+
random_element = next(self.elements)
|
|
246
|
+
self.elements_count += 1
|
|
247
|
+
find_params = {
|
|
248
|
+
'name': self.element_model.name,
|
|
249
|
+
'_type': self.element_model.type,
|
|
250
|
+
'exp': random_element.exp,
|
|
251
|
+
'loc': random_element.loc,
|
|
252
|
+
'sub': random_element.sub
|
|
253
|
+
}
|
|
254
|
+
loc_text = random_element.loc
|
|
255
|
+
try:
|
|
256
|
+
if self.drive_type == DriveTypeEnum.WEB.value:
|
|
257
|
+
loc, ele_quantity, element_text = self.web_find_element(**find_params,
|
|
258
|
+
is_iframe=random_element.is_iframe)
|
|
259
|
+
elif self.drive_type == DriveTypeEnum.ANDROID.value:
|
|
260
|
+
loc, ele_quantity, element_text = self.a_find_ele(**find_params)
|
|
261
|
+
else:
|
|
262
|
+
loc, ele_quantity, element_text = None, 0, None
|
|
263
|
+
except MangoAutomationError as e:
|
|
264
|
+
if not self.base_data.is_ai:
|
|
265
|
+
raise e
|
|
266
|
+
if self.elements_count < len(self.element_model.elements):
|
|
267
|
+
raise e
|
|
268
|
+
self.failed_expression.append(find_params.get('loc'))
|
|
269
|
+
self.elements_count = 0
|
|
270
|
+
loc, loc_text = self.agent.ai_find_element_sync(self.base_data.page,
|
|
271
|
+
self.element_model.name,
|
|
272
|
+
random_element.prompt,
|
|
273
|
+
failed_expression=self.failed_expression)
|
|
274
|
+
loc, ele_quantity, element_text = self.ai_element_info(loc)
|
|
275
|
+
if loc_text not in self.failed_expression:
|
|
276
|
+
self.failed_expression.append(loc_text)
|
|
277
|
+
element_exists = any(
|
|
278
|
+
existing.exp == random_element.exp and
|
|
279
|
+
existing.loc == random_element.loc and
|
|
280
|
+
existing.sub == random_element.sub and
|
|
281
|
+
existing.is_iframe == random_element.is_iframe
|
|
282
|
+
for existing in self.element_result_model.elements
|
|
283
|
+
)
|
|
284
|
+
if not element_exists:
|
|
285
|
+
new_element = ElementListResultModel(
|
|
286
|
+
exp=random_element.exp,
|
|
287
|
+
loc=random_element.loc,
|
|
288
|
+
sub=random_element.sub,
|
|
289
|
+
ele_quantity=ele_quantity,
|
|
290
|
+
element_text=element_text,
|
|
291
|
+
is_iframe=random_element.is_iframe
|
|
292
|
+
)
|
|
293
|
+
self.element_result_model.elements.append(new_element)
|
|
294
|
+
if is_ass:
|
|
295
|
+
if callable(getattr(SyncWebAssertion, self.element_model.ope_key, None)):
|
|
296
|
+
i.v = loc
|
|
297
|
+
elif callable(getattr(MangoAssertion(), self.element_model.ope_key, None)):
|
|
298
|
+
i.v = element_text
|
|
299
|
+
else:
|
|
300
|
+
i.v = loc
|
|
301
|
+
|
|
273
302
|
def __error(self, msg: str, is_screenshot: bool = True):
|
|
274
303
|
try:
|
|
275
304
|
self.element_result_model.status = StatusEnum.FAIL.value
|
|
@@ -283,10 +312,9 @@ class SyncElement(SyncWebDevice, AndroidDriver):
|
|
|
283
312
|
"""
|
|
284
313
|
)
|
|
285
314
|
if is_screenshot:
|
|
286
|
-
file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.
|
|
287
|
-
|
|
288
|
-
self.
|
|
289
|
-
self.element_result_model.picture_path = file_path
|
|
315
|
+
file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.time_stamp()}.jpg'
|
|
316
|
+
self.__error_screenshot(file_name)
|
|
317
|
+
self.element_result_model.picture_path = os.path.join(self.base_data.screenshot_path, file_name)
|
|
290
318
|
self.element_result_model.picture_name = file_name
|
|
291
319
|
except MangoAutomationError as error:
|
|
292
320
|
self.element_result_model.error_message += f'执行过程中发生失败,准备截图时截图失败,失败原因:{error.msg}'
|