Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support w3c actions and velocity swipe #160

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions wda/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from wda.usbmux import fetch
from wda.usbmux.pyusbmux import list_devices, select_device
from wda.utils import inject_call, limit_call_depth, AttrDict, convert
from wda.w3c_actions import W3CActions


try:
Expand Down Expand Up @@ -888,6 +889,32 @@ def swipe(self, x1, y1, x2, y2, duration=0):

data = dict(fromX=x1, fromY=y1, toX=x2, toY=y2, duration=duration)
return self._session_http.post('/wda/dragfromtoforduration', data=data)

def swipe_with_velocity(self, x1: Union[int, float], y1: Union[int, float], x2: Union[int, float], y2: Union[int, float],
press_duration: float, hold_duration: float, velocity: float):
"""
Press down and drag with velocity, appium forked version of wda only
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最好注明一下appium wda开始支持的版本


Args:
- x1, y1, x2, y2 (Union[int, float]): The start and end coordinates if all value is of `int` type, otherwise the start
and end percentage of screen axis
- press_duration (float): the duration before swiping
- hold_duration (float): the duration after swiping
- velocity (float): the velocity of swiping
Linloir marked this conversation as resolved.
Show resolved Hide resolved

[[FBRoute POST:@"/wda/pressAndDragWithVelocity"] respondWithTarget:self action:@selector(handlePressAndDragCoordinateWithVelocity:)]
"""
if any(isinstance(v, float) for v in [x1, y1, x2, y2]):
size = self.window_size()
x1, y1 = self._percent2pos(x1, y1, size)
x2, y2 = self._percent2pos(x2, y2, size)

data = dict(fromX=x1, fromY=y1, toX=x2, toY=y2, pressDuration=press_duration, velocity=velocity, holdDuration=hold_duration)
return self._session_http.post('/wda/pressAndDragWithVelocity', data=data)

def performW3CTouchActions(self, actions: W3CActions):
Linloir marked this conversation as resolved.
Show resolved Hide resolved
data = dict(actions=actions.data)
return self._session_http.post('/actions', data=data)

def _fast_swipe(self, x1, y1, x2, y2, velocity: int = 500):
"""
Expand Down
112 changes: 112 additions & 0 deletions wda/w3c_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# coding: utf-8

from typing import Any, Dict, List, Optional, Union


class FingerMovement:
def __init__(self):
self.__data: Dict[str, Any] = {
"type": "pointerMove"
}

@property
def data(self) -> Dict[str, Any]:
return self.__data

def with_xy(self, x: Union[int, float], y: Union[int, float]) -> "FingerMovement":
self.__data["x"] = x
self.__data["y"] = y
return self

def with_origin(self, element_uid: Optional[str]=None) -> "FingerMovement":
if element_uid is not None:
self.__data["origin"] = element_uid
return self

def with_duration(self, second: Optional[float]=None) -> "FingerMovement":
if second is not None:
self.__data["duration"] = second * 1000
return self


class FingerAction:
def __init__(self):
self.__data: List[Dict[str, Any]] = []

@property
def data(self) -> List[Dict[str, Any]]:
return self.__data

def move(self, movement: FingerMovement) -> "FingerAction":
self.__data.append(movement.data)
return self

def down(self) -> "FingerAction":
self.__data.append({"type": "pointerDown"})
return self

def up(self) -> "FingerAction":
self.__data.append({"type": "pointerUp"})
return self

def pause(self, second: float=0.5) -> "FingerAction":
self.__data.append({"type": "pause", "duration": second * 1000})
return self


class W3CActions:
def __init__(self):
self.__data: List[Dict[str, Any]] = []

@property
def data(self) -> List[Dict[str, Any]]:
return self.__data

def send_keys(self, text: str) -> "W3CActions":
keyboard: Dict[str, Any] = {
"type": "key",
"id": f"keyboard{len(self.__data)}",
"actions": [
(a for a in [
{"type": "keyDown", "value": v},
{"type": "keyUp", "value": v}
]) for v in text
]
}
self.__data.append(keyboard)
return self

def inject_touch_actions(self, *actions: FingerAction) -> "W3CActions":
for action in actions:
pointer: Dict[str, Any] = {
"type": "pointer",
"id": f"finger{len(self.__data)}",
"parameters": {
"pointerType": "touch"
},
"actions": action.data
}
self.__data.append(pointer)
return self

def tap(self, x: Union[int, float], y: Union[int, float], element_uid: Optional[str]=None) -> "W3CActions":
movement = FingerMovement().with_xy(x, y).with_origin(element_uid)
action = FingerAction().move(movement).down().pause(0.1).up()
Linloir marked this conversation as resolved.
Show resolved Hide resolved
self.inject_touch_actions(action)
return self

def press(self, x: Union[int, float], y: Union[int, float],
element_uid: Optional[str]=None, second: float=2.0) -> "W3CActions":
movement = FingerMovement().with_xy(x, y).with_origin(element_uid)
action = FingerAction().move(movement).down().pause(second).up()
self.inject_touch_actions(action)
return self

def swipe(self, from_x: Union[int, float], from_y: Union[int, float],
to_x: Union[int, float], to_y: Union[int, float], element_uid: Optional[str]=None,
press_seconds: float=0.25, swipe_seconds: Optional[float]=None, hold_seconds: float=0.25) -> "W3CActions":
movement_from = FingerMovement().with_xy(from_x, from_y).with_origin(element_uid)
movement_to = FingerMovement().with_xy(to_x, to_y).with_origin(element_uid).with_duration(swipe_seconds)
action = FingerAction().move(movement_from).down().pause(press_seconds).move(movement_to).pause(hold_seconds).up()
self.inject_touch_actions(action)
return self