Poco API精讲之滑动swipe()
上期回顾:Poco API精讲之点击click()、long_click()、double_click()
以下基于
python3.8;airtestIDE1.2.13;airtest1.2.4;pocoui1.0.85
注意:Poco框架和Airtest框架很多API是同名的,但使用方法完全不一样!!!一定不要搞混了,我初学时也经常搞混,这点一定要注意!
具体Poco框架和Airtest框架是什么关系,可以看之前文章:Airtest Project——UI自动化利器介绍
今天来讲Poco的滑动swipe(),大家不要和Airtest框架的swipe()弄混了。
Airtest框架的swipe()是基于绝对坐标或图片的;Poco的swipe()是基于屏幕相对坐标或元素的。
Airtest的swipe()详情可以看之前的文章:Airtest API精讲之swipe()
对坐标不熟的可以看之前的文章:Airtest和Poco坐标详解
Poco的swipe分两种,一种是基于全局操作的swipe、一种是基于UI对象的swipe,两种API汇总可以看之前的文章
Poco实例(全局操作) API汇总
Poco UI对象 API汇总
Poco基于全局操作的swipe
swipe(p1, p2=None, direction=None, duration=2.0)
滑动
参数:
p1 - 起点,屏幕相对坐标,如[0.5,0.5]
p2 - 终点,屏幕相对坐标,如[0.6,0.6]
direction - 滑动向量,如[0.1,0.1],从起始点向右10%向下10%滑动。如屏幕为100*100,起始点为[0.5,0.5],则是从绝对坐标(50,50)滑到(60,60)
duration - 滑动时长,默认2秒
异常:
InvalidOperationException: 坐标在屏幕以外时报错
源码解析:
# 源码位置:your_python_path\site-packages\poco\pocofw.py
def swipe(self, p1, p2=None, direction=None, duration=2.0):
try:
duration = float(duration)
except ValueError:
raise ValueError('Argument `duration` should be <float>. Got {}'.format(repr(duration)))
if not (0 <= p1[0] <= 1) or not (0 <= p1[1] <= 1):
raise InvalidOperationException('Swipe origin out of screen. {}'.format(repr(p1)))
if direction is not None:
p2 = [p1[0] + direction[0], p1[1] + direction[1]]
elif p2 is not None:
p2 = p2
else:
raise TypeError('Swipe end not set.')
return self.agent.input.swipe(p1[0], p1[1], p2[0], p2[1], duration)
首先请记住,起/终点或滑动向量,都是屏幕相对坐标。
第1个try,用来确定滑动时长变量。
第1个if,判断起始坐标是否超出屏幕范围。
第2个if-else,如果指定了滑动向量,则通过滑动向量计算出终点坐标;如果给了终点坐标,则直接使用
最后return,直接调用代理的滑动,并且把计算好的起/终点坐标传进去。
示例:
from airtest.core.api import *
from poco.drivers.unity3d import UnityPoco
auto_setup(__file__)
poco = UnityPoco()
# 从中心向右滑,滑动时长2秒
poco.swipe([0.5,0.5], [0.9,0.5])
# 从中心向左上滑动(左上屏幕宽的10%长的10%的那个点),滑动过程持续3秒
poco.swipe([0.5,0.5], direction=[-0.1,-0.1], duration=3)
Poco基于UI对象的swipe
swipe(direction, focus=None, duration=0.5)
滑动
参数:
direction - 滑动方向,可以是屏幕相对坐标或是指定方向'up', 'down', 'left', 'right'。'up'=[0, -0.1], 'down'=[0, 0.1], 'left'=[-0.1, 0], 'right'=[0.1, 0]。如[0, -0.1],指元素长的方向不动,整个屏幕宽-10%的位置,即基于元素中心点垂直向上。
focus - 元素相对坐标,如[0.1,0.1],指元素长、宽各10%的位置,即左上角,取值范围0~1
duration - 滑动时长,默认0.5秒
异常:
PocoNoSuchNodeException:元素不存在
源码解析:
# 源码位置:your_python_path\site-packages\poco\proxy.py
@wait
def swipe(self, direction, focus=None, duration=0.5):
try:
duration = float(duration)
except ValueError:
raise ValueError('Argument `duration` should be <float>. Got {}'.format(repr(duration)))
focus = focus or self._focus or 'anchor'
dir_vec = self._direction_vector_of(direction)
origin = self.get_position(focus)
self.poco.pre_action('swipe', self, (origin, dir_vec))
ret = self.poco.swipe(origin, direction=dir_vec, duration=duration)
self.poco.post_action('swipe', self, (origin, dir_vec))
return ret
第1个try,用来确定滑动时长变量。
focus = focus or self._focus or 'anchor'
origin = self.get_position(focus)
获取指定的锚点,默认是中心点。
并通过get_position()
带入锚点,计算出起始坐标(屏幕相对坐标)
dir_vec = self._direction_vector_of(direction)
通过self._direction_vector_of()
计算出终点坐标(屏幕相对坐标)
ret = self.poco.swipe(origin, direction=dir_vec, duration=duration)
可以看到,基于UI对象的swipe最终还是通过上面刚刚讲过的 Poco基于全局操作的swipe来执行。
接下来我们看看上面计算终点坐标的self._direction_vector_of()
源码:
# 源码位置:your_python_path\site-packages\poco\proxy.py
def _direction_vector_of(self, dir_):
if dir_ == 'up':
dir_vec = [0, -0.1]
elif dir_ == 'down':
dir_vec = [0, 0.1]
elif dir_ == 'left':
dir_vec = [-0.1, 0]
elif dir_ == 'right':
dir_vec = [0.1, 0]
elif type(dir_) in (list, tuple):
dir_vec = dir_
else:
raise TypeError('Unsupported direction type {}. '
'Only "up/down/left/right" or 2-list/2-tuple available.'.format(type(dir_)))
return dir_vec
代码很简单,如果你指定了上/下/左/右关键字,则替换为指定的屏幕相对坐标(向指定方向滑动屏幕长或宽的10%距离);如果你直接给的就是坐标,则直接使用。
另外说下此处头上的@wait装饰器,就是加了一个wait_for_appearance()的等待:
# 源码位置:your_python_path\site-packages\poco\proxy.py
def wait(func):
@wraps(func)
def wrapped(proxy, *args, **kwargs):
try:
return func(proxy, *args, **kwargs)
except PocoNoSuchNodeException as e:
try:
proxy.wait_for_appearance(timeout=proxy.poco._pre_action_wait_for_appearance)
return func(proxy, *args, **kwargs)
except PocoTargetTimeout:
raise e
return wrapped
wait装饰器逻辑:首先尝试直接执行原方法,如果报PocoNoSuchNodeException的错,则通过wait_for_appearance()等待
对装饰器不熟的可以看:Python三大器之装饰器
示例:
qasite = poco('测试工程师小站')
# 从元素中心向上滑动屏幕宽10%(即1000*0.1)的距离
qasite.swipe([0, -0.1])
# 从元素中心向上滑动屏幕宽10%的距离,参数使用关键字
qasite.swipe('up')
# 从元素左上角向上滑动屏幕宽10%的距离,滑动过程持续3秒
qasite.swipe(direction='up', focus=[0.1,0.1], duration=3)
示例中第3个,假设屏幕是1000*1000,元素绝对长宽为400*400,元素位于屏幕中心即[500,500]
那么可以算出元素左上角坐标是[300,300]
focus=[0.1,0.1]
表示是在元素长宽各10%的那个点,可以算出该点屏幕绝对坐标为[300+400*0.1,300+400*0.1]=[340,340]
向上滑屏幕宽10%(1000*0.1)的距离,所以可以算出终点屏幕绝对坐标为[340,240]
所以最终就是从[340,340]滑到了[340,240],所以如果用Airtest框架的swipe,就是swipe([340,340],[340,240])
图片手工绘制,不够精准,凑合着看
这里给大家算出屏幕绝对坐标是为了方便大家理解原理,实际使用的时候,你不用换算成屏幕绝对坐标,你就直接代入相对坐标用就可以。如果你算不准相对坐标,可以在AirtestIDE上开启显示相对坐标,这样来获取,或者调试几次也能找到你要的位置了。
需要注意的是,ios的duration是按下的时间,而不是滑动的时间,也许wda就是这样设计的吧,或者是bug。
from airtest.core.api import *
from poco.drivers.ios import iosPoco
auto_setup(__file__)
poco = iosPoco()
# 按下3秒,再从中心向右滑
poco.swipe([0.5,0.5], [0.9,0.5], duration=3)
# 按下3秒,再将元素向下滑
poco("测试工程师小站").swipe(direction='down', duration=3)
---------------------------------------------------------------------------------
关注微信公众号即可在手机上查阅,并可接收更多测试分享~