mangoautomation 1.1.22__tar.gz → 1.1.24__tar.gz

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 (79) hide show
  1. {mangoautomation-1.1.22/mangoautomation.egg-info → mangoautomation-1.1.24}/PKG-INFO +12 -4
  2. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/enums/__init__.py +0 -1
  3. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/exceptions/__init__.py +0 -2
  4. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/exceptions/error_msg.py +3 -3
  5. mangoautomation-1.1.24/mangoautomation/mangos/__init__.py +14 -0
  6. mangoautomation-1.1.24/mangoautomation/mangos/__pycache__/__init__.cpython-310.pyc +0 -0
  7. mangoautomation-1.1.24/mangoautomation/mangos/mangos.cp310-win_amd64.pyd +0 -0
  8. mangoautomation-1.1.24/mangoautomation/mangos/mangos.cp312-win_amd64.pyd +0 -0
  9. mangoautomation-1.1.24/mangoautomation/mangos/mangos.cpython-310-darwin.so +0 -0
  10. mangoautomation-1.1.24/mangoautomation/mangos/mangos.cpython-310-x86_64-linux-gnu.so +0 -0
  11. mangoautomation-1.1.24/mangoautomation/mangos/mangos.cpython-312-darwin.so +0 -0
  12. mangoautomation-1.1.24/mangoautomation/mangos/mangos.cpython-312-x86_64-linux-gnu.so +0 -0
  13. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/models/__init__.py +0 -1
  14. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/models/_ui_model.py +1 -0
  15. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/tools/__init__.py +0 -1
  16. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/tools/_uiautodev.py +1 -1
  17. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/__init__.py +2 -3
  18. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/_async_element.py +74 -48
  19. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/_base_data.py +16 -4
  20. mangoautomation-1.1.24/mangoautomation/uidrives/_driver_object.py +33 -0
  21. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/_sync_element.py +75 -46
  22. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/android/__init__.py +2 -16
  23. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/pc/__init__.py +1 -2
  24. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/pc/element.py +1 -2
  25. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/pc/input_device.py +1 -2
  26. mangoautomation-1.1.24/mangoautomation/uidrives/web/__init__.py +10 -0
  27. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/__init__.py → mangoautomation-1.1.24/mangoautomation/uidrives/web/_async_web.py +82 -81
  28. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/__init__.py → mangoautomation-1.1.24/mangoautomation/uidrives/web/_sync_web.py +80 -74
  29. {mangoautomation-1.1.22 → mangoautomation-1.1.24/mangoautomation.egg-info}/PKG-INFO +12 -4
  30. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation.egg-info/SOURCES.txt +12 -24
  31. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation.egg-info/requires.txt +2 -0
  32. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/setup.py +10 -4
  33. mangoautomation-1.1.24/tests/__init__.py +0 -0
  34. mangoautomation-1.1.24/tests/demo1.py +94 -0
  35. mangoautomation-1.1.24/tests/get_ope.py +17 -0
  36. mangoautomation-1.1.24/tests/test_ai_element.py +36 -0
  37. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/tests/test_ui_web.py +7 -3
  38. mangoautomation-1.1.22/MANIFEST.in +0 -3
  39. mangoautomation-1.1.22/mangoautomation/uidrives/_driver_object.py +0 -66
  40. mangoautomation-1.1.22/mangoautomation/uidrives/android/_application.py +0 -70
  41. mangoautomation-1.1.22/mangoautomation/uidrives/android/_assertion.py +0 -90
  42. mangoautomation-1.1.22/mangoautomation/uidrives/android/_customization.py +0 -15
  43. mangoautomation-1.1.22/mangoautomation/uidrives/android/_element.py +0 -169
  44. mangoautomation-1.1.22/mangoautomation/uidrives/android/_equipment.py +0 -151
  45. mangoautomation-1.1.22/mangoautomation/uidrives/android/_new_android.py +0 -54
  46. mangoautomation-1.1.22/mangoautomation/uidrives/android/_page.py +0 -116
  47. mangoautomation-1.1.22/mangoautomation/uidrives/web/__init__.py +0 -5
  48. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/_assertion.py +0 -303
  49. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/_browser.py +0 -112
  50. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/_customization.py +0 -14
  51. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/_element.py +0 -250
  52. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/_input_device.py +0 -82
  53. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/_new_browser.py +0 -153
  54. mangoautomation-1.1.22/mangoautomation/uidrives/web/async_web/_page.py +0 -63
  55. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/_assertion.py +0 -304
  56. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/_browser.py +0 -112
  57. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/_customization.py +0 -14
  58. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/_element.py +0 -250
  59. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/_input_device.py +0 -80
  60. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/_new_browser.py +0 -153
  61. mangoautomation-1.1.22/mangoautomation/uidrives/web/sync_web/_page.py +0 -61
  62. mangoautomation-1.1.22/tests/__init__.py +0 -10
  63. mangoautomation-1.1.22/tests/get_ope.py +0 -8
  64. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/LICENSE +0 -0
  65. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/README.md +0 -0
  66. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/__init__.py +0 -0
  67. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/enums/_base_enum.py +0 -0
  68. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/enums/_ui_enum.py +0 -0
  69. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/exceptions/_exceptions.py +0 -0
  70. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/tools/_mate.py +0 -0
  71. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrive/__init__.py +0 -0
  72. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/ios/__init__.py +0 -0
  73. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/pc/assertion.py +0 -0
  74. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/pc/customization.py +0 -0
  75. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation/uidrives/pc/new_windows.py +0 -0
  76. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation.egg-info/dependency_links.txt +0 -0
  77. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/mangoautomation.egg-info/top_level.txt +0 -0
  78. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/setup.cfg +0 -0
  79. {mangoautomation-1.1.22 → mangoautomation-1.1.24}/tests/test_ui_and.py +0 -0
@@ -1,14 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: mangoautomation
3
- Version: 1.1.22
3
+ Version: 1.1.24
4
4
  Summary: 测试工具
5
5
  Home-page: https://gitee.com/mao-peng/testkit
6
6
  Author: 毛鹏
7
7
  Author-email: 729164035@qq.com
8
8
  Classifier: Programming Language :: Python :: 3.10
9
- Classifier: Programming Language :: Python :: 3.11
10
9
  Classifier: Programming Language :: Python :: 3.12
11
- Classifier: Programming Language :: Python :: 3.13
12
10
  License-File: LICENSE
13
11
  Requires-Dist: setuptools==78.1.1
14
12
  Requires-Dist: pydantic>=2.9.2
@@ -18,6 +16,16 @@ Requires-Dist: uiautomator2>=3.2.5
18
16
  Requires-Dist: mangotools>=1.1.42
19
17
  Requires-Dist: adbutils~=2.8.9
20
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
21
29
 
22
30
  # testkit
23
31
 
@@ -6,7 +6,6 @@
6
6
 
7
7
  from ..enums._ui_enum import ElementExpEnum, ElementOperationEnum, DeviceEnum, BrowserTypeEnum, DriveTypeEnum
8
8
 
9
-
10
9
  __all__ = [
11
10
  'ElementOperationEnum',
12
11
  'DeviceEnum',
@@ -6,6 +6,4 @@
6
6
 
7
7
  from ._exceptions import MangoAutomationError
8
8
 
9
-
10
-
11
9
  __all__ = ['MangoAutomationError']
@@ -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
+ ]
@@ -5,7 +5,6 @@
5
5
 
6
6
  from ..models._ui_model import ElementModel, ElementResultModel, ElementListResultModel
7
7
 
8
-
9
8
  __all__ = [
10
9
  'ElementModel',
11
10
  'ElementResultModel',
@@ -23,6 +23,7 @@ class ElementListModel(BaseModel):
23
23
  loc: str
24
24
  sub: int | None = None
25
25
  is_iframe: int | None = None
26
+ prompt: str | None = None
26
27
 
27
28
 
28
29
  class ElementModel(BaseModel):
@@ -7,5 +7,4 @@
7
7
  from ..tools._mate import Meta
8
8
  from ..tools._uiautodev import start_uiautodev, stop_uiautodev
9
9
 
10
-
11
10
  __all__ = ['Meta', 'start_uiautodev', 'stop_uiautodev']
@@ -37,7 +37,7 @@ def stop_uiautodev():
37
37
  try:
38
38
  uiautodev_process.terminate()
39
39
  uiautodev_process.wait(timeout=5)
40
- return "uiautodev 服务已关闭"
40
+ return "uiautodev 服务已关闭"
41
41
  except subprocess.TimeoutExpired:
42
42
  uiautodev_process.kill()
43
43
  return "uiautodev 服务被强制终止"
@@ -3,17 +3,16 @@
3
3
  # @Description: # @Time : 2023-07-15 11:57
4
4
  # @Author : 毛鹏
5
5
 
6
- from .web.async_web import AsyncWebDevice, AsyncWebCustomization
7
- from .web.sync_web import SyncWebDevice, SyncWebCustomization
6
+ from .web import AsyncWebDevice, AsyncWebCustomization, SyncWebDevice, SyncWebCustomization
8
7
  from ..uidrives._async_element import AsyncElement
9
8
  from ..uidrives._base_data import BaseData
10
9
  from ..uidrives._driver_object import DriverObject
11
10
  from ..uidrives._sync_element import SyncElement
12
11
 
13
12
  __all__ = [
14
- 'AsyncElement',
15
13
  'BaseData',
16
14
  'DriverObject',
15
+ 'AsyncElement',
17
16
  'SyncElement',
18
17
  'AsyncWebDevice',
19
18
  'SyncWebDevice',
@@ -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 ..uidrives.android import AndroidDriver
22
- from ..uidrives.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:
@@ -47,6 +54,8 @@ class AsyncElement(AsyncWebDevice, 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,
@@ -194,8 +203,6 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
194
203
  await run(i.get('sql'), i.get('key_list'))
195
204
 
196
205
  async def __custom(self):
197
- 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')))
199
206
  for i in self.element_model.custom:
200
207
  value = self.base_data.test_data.replace(i.get('value'))
201
208
  self.base_data.log.debug(f'开始执行自定义-1:key: {i.get("key")}, value: {value}')
@@ -226,53 +233,72 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
226
233
  ope_key = 'actual' if is_ass else 'locating'
227
234
  for i in self.element_model.ope_value:
228
235
  if i.f == ope_key and self.element_model.elements:
229
- random_element = random.randint(0, len(self.element_model.elements) - 1)
230
- find_params = {
231
- 'name': self.element_model.name,
232
- '_type': self.element_model.type,
233
- 'exp': self.element_model.elements[random_element].exp,
234
- 'loc': self.element_model.elements[random_element].loc,
235
- 'sub': self.element_model.elements[random_element].sub
236
- }
237
- if self.drive_type == DriveTypeEnum.WEB.value:
238
- loc, ele_quantity, element_text = await self.web_find_ele(
239
- **find_params, is_iframe=self.element_model.elements[random_element].is_iframe)
240
- elif self.drive_type == DriveTypeEnum.ANDROID.value:
241
- loc, ele_quantity, element_text = self.a_find_ele(**find_params)
242
- else:
243
- loc, ele_quantity, element_text = None, 0, None
244
- new_element = ElementListResultModel(
245
- exp=self.element_model.elements[random_element].exp,
246
- loc=self.element_model.elements[random_element].loc,
247
- sub=self.element_model.elements[random_element].sub,
248
- ele_quantity=ele_quantity,
249
- element_text=element_text,
250
- is_iframe=self.element_model.elements[random_element].is_iframe
251
- )
252
-
253
- element_exists = any(
254
- existing.exp == new_element.exp and
255
- existing.loc == new_element.loc and
256
- existing.sub == new_element.sub and
257
- existing.is_iframe == new_element.is_iframe
258
- for existing in self.element_result_model.elements
259
- )
260
-
261
- if not element_exists:
262
- self.element_result_model.elements.append(new_element)
263
- if is_ass:
264
- if callable(getattr(AsyncWebAssertion, self.element_model.ope_key, None)):
265
- i.v = loc
266
- elif callable(getattr(MangoAssertion(), self.element_model.ope_key, None)):
267
- i.v = element_text
268
- else:
269
- i.v = loc
270
- i.v = self.base_data.test_data.replace(i.v)
236
+ await self.query_element(i, is_ass)
237
+ else:
238
+ i.v = self.base_data.test_data.replace(i.v)
271
239
  except AttributeError as error:
272
240
  self.base_data.log.debug(
273
241
  f'获取操作值失败-1,类型:{type(error)},失败详情:{error},失败明细:{traceback.format_exc()}')
274
242
  raise MangoAutomationError(*ERROR_MSG_0027)
275
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
+
276
302
  async def __error(self, msg: str, is_screenshot: bool = True):
277
303
  try:
278
304
  self.element_result_model.status = StatusEnum.FAIL.value
@@ -286,7 +312,7 @@ class AsyncElement(AsyncWebDevice, AndroidDriver):
286
312
  """
287
313
  )
288
314
  if is_screenshot:
289
- file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.get_time_for_min()}.jpg'
315
+ file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.time_stamp()}.jpg'
290
316
  await self.__error_screenshot(file_name)
291
317
  self.element_result_model.picture_path = os.path.join(self.base_data.screenshot_path, file_name)
292
318
  self.element_result_model.picture_name = file_name
@@ -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
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Project: 芒果测试平台
3
+ # @Description:
4
+ # @Time : 2024-04-24 10:43
5
+ # @Author : 毛鹏
6
+
7
+ from typing import Optional
8
+ from mangoautomation.mangos import NewAndroid, AsyncWebNewBrowser, SyncWebNewBrowser
9
+ from ..uidrives.pc.new_windows import NewWindows
10
+
11
+
12
+
13
+ class DriverObject:
14
+
15
+ def __init__(self, log, is_async=False):
16
+ self.log = log
17
+ self.is_async = is_async
18
+ self.web: Optional[AsyncWebNewBrowser | SyncWebNewBrowser] = None
19
+ self.android: Optional[NewAndroid] = None
20
+ self.windows: Optional[NewWindows] = None
21
+
22
+ def set_web(self, **kwargs):
23
+ kwargs['log'] = self.log
24
+ if self.is_async:
25
+ self.web = AsyncWebNewBrowser(**kwargs)
26
+ else:
27
+ self.web = SyncWebNewBrowser(**kwargs)
28
+
29
+ def set_android(self, and_equipment: str):
30
+ self.android = NewAndroid(and_equipment)
31
+
32
+ def set_windows(self, win_path: str, win_title: str):
33
+ self.windows = NewWindows(win_path, win_title)
@@ -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
22
  from ..uidrives.android import AndroidDriver
22
- from ..uidrives.web.sync_web import SyncWebDevice, SyncWebAssertion
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.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(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,7 +312,7 @@ 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'
315
+ file_name = f'失败截图-{self.element_model.name}{self.base_data.test_data.time_stamp()}.jpg'
287
316
  self.__error_screenshot(file_name)
288
317
  self.element_result_model.picture_path = os.path.join(self.base_data.screenshot_path, file_name)
289
318
  self.element_result_model.picture_name = file_name
@@ -8,26 +8,13 @@ from uiautomator2 import UiObject, UiObjectNotFoundError
8
8
  from uiautomator2.exceptions import XPathElementNotFoundError
9
9
  from uiautomator2.xpath import XPathSelector
10
10
 
11
+ from mangoautomation.mangos import AndroidApplication, AndroidAssertion, AndroidElement, AndroidCustomization, \
12
+ AndroidEquipment, AndroidPage
11
13
  from mangotools.assertion import MangoAssertion
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
14
  from ...enums import ElementExpEnum
19
15
  from ...exceptions import MangoAutomationError
20
16
  from ...exceptions.error_msg import *
21
17
 
22
- __all__ = [
23
- 'AndroidApplication',
24
- 'AndroidAssertion',
25
- 'AndroidElement',
26
- 'AndroidCustomization',
27
- 'AndroidEquipment',
28
- 'AndroidPage',
29
- 'AndroidDriver',
30
- ]
31
18
 
32
19
  from mangotools.mangos import Mango
33
20
 
@@ -68,7 +55,6 @@ class AndroidDriver(AndroidPage,
68
55
  is_method = callable(getattr(AndroidAssertion(self.base_data), ope_key, None))
69
56
  if is_method and ope_value.get('actual') is None:
70
57
  raise MangoAutomationError(*ERROR_MSG_0031, value=(name,))
71
-
72
58
  try:
73
59
  if is_method:
74
60
  self.base_data.log.debug(f'开始断言-1,方法:{ope_key},断言值:{ope_value}')
@@ -24,13 +24,12 @@ else:
24
24
  from uiautomation import Control
25
25
  import uiautomation
26
26
 
27
- from mangoautomation.uidrives._base_data import BaseData
28
27
  from mangoautomation.uidrives.pc.element import WinElement
29
28
  from mangoautomation.uidrives.pc.input_device import WinDeviceInput
30
29
 
31
30
 
32
31
  class WinDriver(WinElement, WinDeviceInput):
33
- def __init__(self, base_data: BaseData):
32
+ def __init__(self, base_data):
34
33
  super().__init__(base_data)
35
34
 
36
35
  def find_element(