forked from Rain0193/python-appium
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBaseOperate.py
More file actions
400 lines (360 loc) · 17.4 KB
/
Copy pathBaseOperate.py
File metadata and controls
400 lines (360 loc) · 17.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# -*- coding: utf-8 -*-
import re
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException, TimeoutException, WebDriverException, StaleElementReferenceException
from Base.BaseElements import Element as be
import os
from appium.webdriver.common.touch_action import TouchAction
'''
# 此脚本主要用于查找元素是否存在,操作页面元素
'''
class OperateElement:
def __init__(self, driver=""):
self.driver = driver
def findElement(self, mOperate):
'''
查找元素.mOperate,dict|list
operate_type:对应的操作
element_info:元素详情
find_type: find类型
'''
try:
if type(mOperate) == list: # 多检查点
for item in mOperate:
# if item.get("is_webview", "0") == 1: # 1表示切换到webview
# self.switchToWebview()
# elif item.get("is_webview", "0") == 2:
# self.switchToNative()
if item.get("element_info", "0") == "0": # 如果没有页面元素,就不检测是页面元素,可能是滑动等操作
return {"result": True}
t = item["check_time"] if item.get("check_time", "0") != "0" else be.WAIT_TIME
WebDriverWait(self.driver, t).until(lambda x: self.elements_by(item))
return {"result": True}
if type(mOperate) == dict: # 单检查点
# if mOperate.get("is_webview", "0") == 1 and self.switchToWebview() is False: # 1表示切换到webview
# print("切换到webview失败,请确定是否在webview页面")
# return {"result": False, "webview": False}
# elif mOperate.get("is_webview", "0") == 2:
# self.switchToNative()
if mOperate.get("element_info", "0") == "0": # 如果没有页面元素,就不检测是页面元素,可能是滑动等操作
return {"result": True}
t = mOperate["check_time"] if mOperate.get("check_time", "0") != "0" else be.WAIT_TIME # 如果自定义检测时间为空,就用默认的检测等待时间
WebDriverWait(self.driver, t).until(lambda x: self.elements_by(mOperate)) # 操作元素是否存在
return {"result": True}
except TimeoutException:
# print("==查找元素超时==")
return {"result": False, "type": be.TIME_OUT}
except NoSuchElementException:
# print("==查找元素不存在==")
return {"result": False, "type": be.NO_SUCH}
except WebDriverException:
# print("WebDriver出现问题了")
return {"result": False, "type": be.WEB_DROVER_EXCEPTION}
'''
查找元素.mOperate是字典
operate_type:对应的操作
element_info:元素详情
find_type: find类型
testInfo: 用例介绍
logTest: 记录日志
device: 设备名
'''
def operate(self, mOperate, testInfo, logTest, device):
res = self.findElement(mOperate)
if res["result"]:
return self.operate_by(mOperate, testInfo, logTest, device)
else:
return res
def operate_by(self, operate, testInfo, logTest, device):
try:
info = operate.get("element_info", " ") + "_" + operate.get("operate_type", " ") + str(operate.get(
"code", " ")) + operate.get("msg", " ")
logTest.buildStartLine(testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + info) # 记录日志
print("==操作步骤:%s==" % info)
if operate.get("operate_type", "0") == "0": # 如果没有此字段,说明没有相应操作,一般是检查点,直接判定为成功
return {"result": True}
# threading._start_new_thread(self.click_windows(device),())
elements = {
be.SWIPE_DOWN: lambda: self.swipeToDown(),
be.SWIPE_UP: lambda: self.swipeToUp(),
be.SWIPE_RIGHT: lambda: self.swipeToRight(),
be.SWIPE_LEFT: lambda: self.swipeToLeft(operate.get("element_info")),
be.CLICK: lambda: self.click(operate),
be.SCREEN_TAP:lambda: self.screen_tap(200,200),
be.GET_VALUE: lambda: self.get_value(operate),
be.SET_VALUE: lambda: self.set_value(operate),
be.ADB_TAP: lambda: self.adb_tap(operate, device),
be.GET_CONTENT_DESC: lambda: self.get_content_desc(operate),
be.PRESS_KEY_CODE: lambda: self.press_keycode(operate)
}
return elements[operate.get("operate_type")]()
except IndexError:
logTest.buildStartLine(
testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + operate["element_info"] + "索引错误") # 记录日志
# print(operate["element_info"] + "索引错误")
return {"result": False, "type": be.INDEX_ERROR}
except NoSuchElementException:
logTest.buildStartLine(
testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + operate[
"element_info"] + "页面元素不存在或没加载完成") # 记录日志
# print(operate["element_info"] + "页面元素不存在或没有加载完成")
return {"result": False, "type": be.NO_SUCH}
except StaleElementReferenceException:
logTest.buildStartLine(
testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + operate[
"element_info"] + "页面元素已经变化") # 记录日志
# print(operate["element_info"] + "页面元素已经变化")
return {"result": False, "type": be.STALE_ELEMENT_REFERENCE_EXCEPTION}
except KeyError:
# 如果key不存在,一般都是在自定义的page页面去处理了,这里直接返回为真
return {"result": True}
# 获取到元素到坐标点击,主要解决浮动层遮档无法触发driver.click的问题
def adb_tap(self, mOperate, device):
bounds = self.elements_by(mOperate).location
x = str(bounds["x"])
y = str(bounds["y"])
cmd = "adb -s " + device + " shell input tap " + x + " " + y
print(cmd)
os.system(cmd)
return {"result": True}
def toast(self, xpath, logTest, testInfo):
logTest.buildStartLine(testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + "查找弹窗元素_" + xpath) # 记录日志
try:
WebDriverWait(self.driver, 10, 0.5).until(
expected_conditions.presence_of_element_located((By.XPATH, xpath)))
return {"result": True}
except TimeoutException:
return {"result": False}
except NoSuchElementException:
return {"result": False}
# 点击事件
def click(self, mOperate):
# print(self.driver.page_source)
if mOperate["find_type"] == be.find_element_by_id or mOperate["find_type"] == be.find_element_by_xpath or mOperate["find_type"] == be.find_element_by_android_uiautomator or \
mOperate["find_type"] == be.find_element_by_accessibility_id or mOperate["find_type"] == be.find_element_by_name:
self.elements_by(mOperate).click()
elif mOperate.get("find_type") == be.find_elements_by_id or mOperate.get("find_type") == be.find_elements_by_xpath:
self.elements_by(mOperate)[mOperate["index"]].click()
return {"result": True}
# code 事件
def press_keycode(self, mOperate):
self.driver.press_keycode(mOperate.get("code", 0))
return {"result": True}
def get_content_desc(self, mOperate):
result = self.elements_by(mOperate).get_attribute("contentDescription")
re_reulst = re.findall(r'[a-zA-Z\d+\u4e00-\u9fa5]', result)
return {"result": True, "text": "".join(re_reulst)}
# '''
# 切换native
#
# '''
#
# def switchToNative(self):
# self.driver.switch_to.context("NATIVE_APP") # 切换到native
#
# '''
# 切换webview
# '''
#
# def switchToWebview(self):
# try:
# n = 1
# while n < 10:
# time.sleep(3)
# n = n + 1
# print(self.driver.contexts)
# for cons in self.driver.contexts:
# if cons.lower().startswith("webview"):
# self.driver.switch_to.context(cons)
# # print(self.driver.page_source)
# self.driver.execute_script('document.querySelectorAll("html")[0].style.display="block"')
# self.driver.execute_script('document.querySelectorAll("head")[0].style.display="block"')
# self.driver.execute_script('document.querySelectorAll("title")[0].style.display="block"')
# print("切换webview成功")
# return {"result": True}
# return {"result": False}
# except appium.common.exceptions.NoSuchContextException:
# print("切换webview失败")
# return {"result": False, "text": "appium.common.exceptions.NoSuchContextException异常"}
def get_size(self):
"""获取屏幕分辨率."""
rect = self.driver.get_window_size()
return rect['width'], rect['height']
def swipe_by_ratio(self,start_x, start_y, direction, ratio, duration=None):
"""
按照屏幕比例的滑动.
:param start_x: 起始横坐标
:param start_y: 起始纵坐标
:param direction: 滑动方向,只支持'up'、'down'、'left'、'right'四种方向参数
:param ratio: 滑动距离与屏幕的比例,范围0到1
:param duration: 滑动时间,单位ms
:return:
"""
direction_list = ['up', 'down', 'left', 'right']
if direction not in direction_list:
print('滑动方向%s不支持', direction)
width, height = self.get_size()
def swipe_up():
"""上滑."""
end_y = start_y - ratio * height
if end_y < 0:
print('上滑距离过大')
return False
else:
self.driver.swipe(start_x, start_y, start_x, end_y, duration)
return True
def swipe_down():
"""下滑."""
end_y = start_y + ratio * height
if end_y > height:
print('下滑距离过大')
return False
else:
self.driver.swipe(start_x, start_y, start_x, end_y, duration)
return True
def swipe_left():
"""左滑."""
end_x = start_x - ratio * width
if end_x < 0:
print('左滑距离过大')
return False
else:
self.driver.swipe(start_x, start_y, end_x, start_y, duration)
return True
def swipe_right():
"""右滑."""
end_x = start_x + ratio * width
if end_x > width:
print('右滑距离过大')
return False
else:
self.driver.swipe(start_x, start_y, end_x, start_y, duration)
return True
swipe_dict = {'up': swipe_up, 'down': swipe_down, 'left': swipe_left,
'right': swipe_right}
return swipe_dict[direction]()
# 左滑动
def swipeToLeft(self,element_info):
'''
以某个元素作为标准点,左滑动
:param element_info: 某标准点元素
:return:
'''
print('向左滑动')
coord_x = element_info.location.get('x')
coord_y = element_info.location.get('y')
self.swipe_by_ratio(coord_x, coord_y, 'left', 0.7, 300) # 从某一元素向左滑动
return {"result": True}
def swipeToDown(self):
width, height = self.get_size()
start_x = width // 2
start_y = height // 8
start_bottom = height - start_y
print("向下滑动")
self.swipe_by_ratio(start_x, start_bottom, 'down', 0.5, 500)
return {"result": True}
def swipeToUp(self):
width, height = self.get_size()
start_x = width // 2
start_bottom = height - height // 8
print("向上滑动")
self.swipe_by_ratio(start_x, start_bottom, 'up', 0.5, 500)
return {"result": True}
def swipeToRight(self):
width, height = self.get_size()
start_x = width // 8
start_bottom = height // 2
print("向右滑动")
self.swipe_by_ratio(start_x, start_bottom, 'right', 0.5, 500)
return {"result": True}
def screen_tap(self, x, y):
'''
:param fun: 要消除的storyboard控件名称,如贴纸/滤镜等需要点击屏幕消除的
:param x: 横坐标 eg.200
:param y: 纵坐标 eg.200
:return:
'''
print('点击屏幕消除弹窗控件')
actions = TouchAction(self.driver)
actions.tap(None, x, y).release().perform()
def set_value(self, mOperate):
"""
输入值,代替过时的send_keys
:param mOperate:
:return:
"""
self.elements_by(mOperate).send_keys(mOperate["msg"])
return {"result": True}
def get_value(self, mOperate):
'''
读取element的值,支持webview下获取值
:param mOperate:
:return:
'''
if mOperate.get("find_type") == be.find_elements_by_id:
element_info = self.elements_by(mOperate)[mOperate["index"]]
if mOperate.get("is_webview", "0") == 1:
result = element_info.text
else:
result = element_info.get_attribute("text")
re_reulst = re.findall(r'[a-zA-Z\d+\u4e00-\u9fa5]', result) # 只匹配中文,大小写,字母
return {"result": True, "text": "".join(re_reulst)}
element_info = self.elements_by(mOperate)
if mOperate.get("is_webview", "0") == 1:
result = element_info.text
else:
result = element_info.get_attribute("text")
re_reulst = re.findall(r'[a-zA-Z\d+\u4e00-\u9fa5]', result)
return {"result": True, "text": "".join(re_reulst)}
# def click_windows(self, device):
# try:
# button0 = 'com.huawei.systemmanager:id/btn_allow'
# # button1 = 'com.android.packageinstaller:id/btn_allow_once'
# # button2 = 'com.android.packageinstaller:id/bottom_button_two'
# # button3 = 'com.android.packageinstaller:id/btn_continue_install'
# # button4 = 'android:id/button1'
# # button5 = 'vivo:id/vivo_adb_install_ok_button'
# button_list = [button0]
# for elem in button_list:
# find = self.driver.find_element_by_id(elem)
# WebDriverWait(self.driver, 1).until(lambda x: self.elements_by(find(elem)))
# bounds = find.location
# x = str(bounds["x"])
# y = str(bounds["y"])
# cmd = "adb -s " + device + " shell input tap " + x + " " + y
# print(cmd)
# os.system(cmd)
# print("==点击授权弹框_%s==" % elem)
# except TimeoutException:
# # print("==查找元素超时==")
# pass
# except NoSuchElementException:
# # print("==查找元素不存在==")
# pass
# except WebDriverException:
# # print("WebDriver出现问题了")
# pass
# 封装常用的标签
def elements_by(self, mOperate):
elements = {
be.find_element_by_id: lambda: self.driver.find_element_by_id(mOperate["element_info"]),
be.find_elements_by_id: lambda: self.driver.find_elements_by_id(mOperate["element_info"])[mOperate['index']],
be.find_element_by_xpath: lambda: self.driver.find_element_by_xpath(mOperate["element_info"]),
be.find_elements_by_xpath: lambda: self.driver.find_elements_by_xpath(mOperate["element_info"])[mOperate['index']],
be.find_element_by_name: lambda: self.driver.find_element_by_name(mOperate['element_info']),
be.find_elements_by_name: lambda: self.driver.find_elements_by_name(mOperate['element_info'])[mOperate['index']],
be.find_element_by_class_name: lambda: self.driver.find_element_by_class_name(mOperate['element_info']),
be.find_elements_by_class_name: lambda: self.driver.find_elements_by_class_name(mOperate['element_info'])[
mOperate['index']],
be.find_element_by_accessibility_id: lambda: self.driver.find_element_by_accessibility_id(
mOperate["element_info"]),
be.find_elements_by_accessibility_id: lambda: self.driver.find_elements_by_accessibility_id(
mOperate["element_info"])[mOperate['index']],
be.find_element_by_ios_predicate: lambda: self.driver.find_element_by_ios_predicate(mOperate["element_info"]),
be.find_elements_by_ios_predicate: lambda: self.driver.find_elements_by_ios_predicate(mOperate["element_info"])[mOperate['index']],
be.find_element_by_android_uiautomator: lambda: self.driver.find_element_by_android_uiautomator(
mOperate["element_info"])
}
return elements[mOperate["find_type"]]()