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.

Files changed (67) hide show
  1. mangoautomation/__init__.py +1 -1
  2. mangoautomation/enums/__init__.py +0 -2
  3. mangoautomation/exceptions/__init__.py +0 -3
  4. mangoautomation/exceptions/error_msg.py +4 -4
  5. mangoautomation/mangos/__init__.py +14 -0
  6. mangoautomation/mangos/__pycache__/__init__.cpython-310.pyc +0 -0
  7. mangoautomation/mangos/mangos.cp310-win_amd64.pyd +0 -0
  8. mangoautomation/mangos/mangos.cp312-win_amd64.pyd +0 -0
  9. mangoautomation/mangos/mangos.cpython-310-darwin.so +0 -0
  10. mangoautomation/mangos/mangos.cpython-310-x86_64-linux-gnu.so +0 -0
  11. mangoautomation/mangos/mangos.cpython-312-darwin.so +0 -0
  12. mangoautomation/mangos/mangos.cpython-312-x86_64-linux-gnu.so +0 -0
  13. mangoautomation/models/__init__.py +0 -2
  14. mangoautomation/models/_ui_model.py +2 -1
  15. mangoautomation/tools/__init__.py +0 -2
  16. mangoautomation/tools/_uiautodev.py +1 -3
  17. mangoautomation/uidrive/__init__.py +5 -7
  18. mangoautomation/uidrives/__init__.py +21 -0
  19. mangoautomation/{uidrive → uidrives}/_async_element.py +80 -52
  20. mangoautomation/{uidrive → uidrives}/_base_data.py +16 -4
  21. mangoautomation/{uidrive → uidrives}/_driver_object.py +2 -4
  22. mangoautomation/{uidrive → uidrives}/_sync_element.py +78 -50
  23. mangoautomation/{uidrive → uidrives}/android/__init__.py +2 -16
  24. mangoautomation/{uidrive → uidrives}/android/_application.py +1 -1
  25. mangoautomation/{uidrive → uidrives}/android/_assertion.py +1 -1
  26. mangoautomation/{uidrive → uidrives}/android/_customization.py +1 -1
  27. mangoautomation/{uidrive → uidrives}/android/_element.py +3 -3
  28. mangoautomation/{uidrive → uidrives}/android/_equipment.py +1 -1
  29. mangoautomation/{uidrive → uidrives}/android/_page.py +1 -1
  30. mangoautomation/{uidrive → uidrives}/pc/__init__.py +3 -4
  31. mangoautomation/{uidrive → uidrives}/pc/customization.py +1 -1
  32. mangoautomation/{uidrive → uidrives}/pc/element.py +1 -2
  33. mangoautomation/{uidrive → uidrives}/pc/input_device.py +1 -2
  34. mangoautomation/uidrives/web/__init__.py +10 -0
  35. mangoautomation/uidrives/web/_async_web.py +166 -0
  36. mangoautomation/uidrives/web/_sync_web.py +166 -0
  37. mangoautomation/{uidrive → uidrives}/web/async_web/__init__.py +8 -8
  38. mangoautomation/{uidrive → uidrives}/web/async_web/_assertion.py +1 -1
  39. mangoautomation/{uidrive → uidrives}/web/async_web/_browser.py +2 -2
  40. mangoautomation/{uidrive → uidrives}/web/async_web/_customization.py +1 -1
  41. mangoautomation/{uidrive → uidrives}/web/async_web/_element.py +3 -13
  42. mangoautomation/{uidrive → uidrives}/web/async_web/_input_device.py +1 -1
  43. mangoautomation/{uidrive → uidrives}/web/async_web/_page.py +1 -1
  44. mangoautomation/{uidrive → uidrives}/web/sync_web/__init__.py +8 -8
  45. mangoautomation/{uidrive → uidrives}/web/sync_web/_assertion.py +1 -1
  46. mangoautomation/{uidrive → uidrives}/web/sync_web/_browser.py +3 -3
  47. mangoautomation/{uidrive → uidrives}/web/sync_web/_customization.py +1 -1
  48. mangoautomation/{uidrive → uidrives}/web/sync_web/_element.py +3 -13
  49. mangoautomation/{uidrive → uidrives}/web/sync_web/_input_device.py +1 -1
  50. mangoautomation/{uidrive → uidrives}/web/sync_web/_page.py +2 -2
  51. {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/METADATA +4 -4
  52. mangoautomation-1.1.23.dist-info/RECORD +71 -0
  53. tests/__init__.py +0 -10
  54. tests/demo1.py +21 -0
  55. tests/test_ai_element.py +36 -0
  56. tests/test_ui_web.py +31 -31
  57. mangoautomation/uidrive/web/__init__.py +0 -5
  58. mangoautomation-1.1.21.dist-info/RECORD +0 -58
  59. /mangoautomation/{uidrive → uidrives}/android/_new_android.py +0 -0
  60. /mangoautomation/{uidrive → uidrives}/ios/__init__.py +0 -0
  61. /mangoautomation/{uidrive → uidrives}/pc/assertion.py +0 -0
  62. /mangoautomation/{uidrive → uidrives}/pc/new_windows.py +0 -0
  63. /mangoautomation/{uidrive → uidrives}/web/async_web/_new_browser.py +0 -0
  64. /mangoautomation/{uidrive → uidrives}/web/sync_web/_new_browser.py +0 -0
  65. {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/LICENSE +0 -0
  66. {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/WHEEL +0 -0
  67. {mangoautomation-1.1.21.dist-info → mangoautomation-1.1.23.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # @Project: 芒果测试平台
3
3
  # @Description:
4
- # @Time : 2024-09-07 22:15
4
+ # @Time : 2025-10-22 09:50
5
5
  # @Author : 毛鹏
@@ -3,11 +3,9 @@
3
3
  # @Description:
4
4
  # @Time : 2023-04-29 11:23
5
5
  # @Author : 毛鹏
6
- import sys
7
6
 
8
7
  from ..enums._ui_enum import ElementExpEnum, ElementOperationEnum, DeviceEnum, BrowserTypeEnum, DriveTypeEnum
9
8
 
10
-
11
9
  __all__ = [
12
10
  'ElementOperationEnum',
13
11
  'DeviceEnum',
@@ -3,10 +3,7 @@
3
3
  # @Description:
4
4
  # @Time : 2023-07-07 10:14
5
5
  # @Author : 毛鹏
6
- import sys
7
6
 
8
7
  from ._exceptions import MangoAutomationError
9
8
 
10
-
11
-
12
9
  __all__ = ['MangoAutomationError']
@@ -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
+ ]
@@ -2,11 +2,9 @@
2
2
  # @Project: 芒果测试平台
3
3
  # @Description:# @Time : 2023-09-09 23:17
4
4
  # @Author : 毛鹏
5
- import sys
6
5
 
7
6
  from ..models._ui_model import ElementModel, ElementResultModel, ElementListResultModel
8
7
 
9
-
10
8
  __all__ = [
11
9
  'ElementModel',
12
10
  'ElementResultModel',
@@ -22,7 +22,8 @@ class ElementListModel(BaseModel):
22
22
  exp: int
23
23
  loc: str
24
24
  sub: int | None = None
25
- is_iframe: int | None
25
+ is_iframe: int | None = None
26
+ prompt: str | None = None
26
27
 
27
28
 
28
29
  class ElementModel(BaseModel):
@@ -3,10 +3,8 @@
3
3
  # @Description:
4
4
  # @Time : 2025-04-15 11:54
5
5
  # @Author : 毛鹏
6
- import sys
7
6
 
8
7
  from ..tools._mate import Meta
9
8
  from ..tools._uiautodev import start_uiautodev, stop_uiautodev
10
9
 
11
-
12
10
  __all__ = ['Meta', 'start_uiautodev', 'stop_uiautodev']
@@ -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 "uiautodev 服务已关闭"
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 sys
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
- self.base_data.test_data.set_cache(i.get('key'), self.base_data.test_data.replace(i.get('value')))
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
- random_element = random.randint(0, len(self.element_model.elements) - 1)
226
- find_params = {
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 = 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.get_time_for_min()}.jpg'
287
- file_path = os.path.join(self.base_data.screenshot_path, file_name)
288
- await self.__error_screenshot(file_path)
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 ap, BrowserContext as ac
11
- from playwright.sync_api import Page as p, BrowserContext as c
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[p | ap | None] = None
44
- self.context: Optional[c | ac | None] = None
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 ..uidrive.android import AndroidDriver
22
- from ..uidrive.web.sync_web import SyncWebDevice, SyncWebAssertion
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
- self.base_data.test_data.set_cache(i.get('key'), self.base_data.test_data.replace(i.get('value')))
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
- random_element = random.randint(0, len(self.element_model.elements) - 1)
226
- find_params = {
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.get_time_for_min()}.jpg'
287
- file_path = os.path.join(self.base_data.screenshot_path, file_name)
288
- self.__error_screenshot(file_path)
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}'