Skip to content

Commit 6b21a67

Browse files
authored
feat: use 'touch' pointer action (appium#670)
* chore: specify touch * comment out touch in drag_and_drop * fix mypy * add desctiption of touch action
1 parent 02d6c8c commit 6b21a67

File tree

4 files changed

+32
-4
lines changed

4 files changed

+32
-4
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ If you would like to use the old protocol (MJSONWP), please use v1 Appium Python
3434
- https://appiumpro.com/editions/29-automating-complex-gestures-with-the-w3c-actions-api
3535
- `launch_app`, `close_app` and `reset` are deprecated. Please read [issues#15807](https://github.com/appium/appium/issues/15807) for more details
3636

37+
#### MultiAction/TouchAction to W3C actions
38+
39+
On UIA2, some elements can be handled with `touch` pointer action insead of the default `mouse` pointer action in the Selenium Python cleint.
40+
For example, the below action builder is to replace the default one with the `touch` pointer action.
41+
42+
```python
43+
from selenium.webdriver.common.actions import interaction
44+
from selenium.webdriver.common.actions.action_builder import ActionBuilder
45+
46+
actions = ActionChains(driver)
47+
# override as 'touch' pointer action
48+
actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
49+
actions.w3c_actions.pointer_action.move_to_location(start_x, start_y)
50+
actions.w3c_actions.pointer_action.pointer_down()
51+
actions.w3c_actions.pointer_action.pause(2)
52+
actions.w3c_actions.pointer_action.move_to_location(end_x, end_y)
53+
actions.w3c_actions.pointer_action.release()
54+
actions.perform()
55+
```
56+
3757
## Getting the Appium Python client
3858

3959
There are three ways to install and use the Appium Python client.

appium/webdriver/extensions/action_helpers.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616

1717
from selenium import webdriver
1818
from selenium.webdriver.common.action_chains import ActionChains
19+
from selenium.webdriver.common.actions import interaction
20+
from selenium.webdriver.common.actions.action_builder import ActionBuilder
1921
from selenium.webdriver.common.actions.mouse_button import MouseButton
22+
from selenium.webdriver.common.actions.pointer_input import PointerInput
2023

21-
from appium.webdriver.common.multi_action import MultiAction
22-
from appium.webdriver.common.touch_action import TouchAction
2324
from appium.webdriver.webelement import WebElement
2425

2526
if TYPE_CHECKING:
@@ -54,6 +55,7 @@ def scroll(self: T, origin_el: WebElement, destination_el: WebElement, duration:
5455
duration_sec = duration / 1000
5556

5657
actions = ActionChains(self)
58+
actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
5759
dest_el_rect = destination_el.rect
5860

5961
# https://github.com/SeleniumHQ/selenium/blob/3c82c868d4f2a7600223a1b3817301d0b04d28e4/py/selenium/webdriver/common/actions/pointer_actions.py#L83
@@ -83,6 +85,7 @@ def drag_and_drop(self: T, origin_el: WebElement, destination_el: WebElement) ->
8385
Union['WebDriver', 'ActionHelpers']: Self instance
8486
"""
8587
actions = ActionChains(self)
88+
# 'mouse' pointer action
8689
actions.w3c_actions.pointer_action.click_and_hold(origin_el)
8790
actions.w3c_actions.pointer_action.move_to(destination_el)
8891
actions.w3c_actions.pointer_action.release()
@@ -106,6 +109,7 @@ def tap(self: T, positions: List[Tuple[int, int]], duration: Optional[int] = Non
106109
"""
107110
if len(positions) == 1:
108111
actions = ActionChains(self)
112+
actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
109113
x = positions[0][0]
110114
y = positions[0][1]
111115
actions.w3c_actions.pointer_action.move_to_location(x, y)
@@ -156,6 +160,7 @@ def swipe(self: T, start_x: int, start_y: int, end_x: int, end_y: int, duration:
156160
Union['WebDriver', 'ActionHelpers']: Self instance
157161
"""
158162
actions = ActionChains(self)
163+
actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
159164
actions.w3c_actions.pointer_action.move_to_location(start_x, start_y)
160165
actions.w3c_actions.pointer_action.pointer_down()
161166
actions.w3c_actions.pointer_action.pause(duration / 1000)
@@ -180,6 +185,7 @@ def flick(self: T, start_x: int, start_y: int, end_x: int, end_y: int) -> T:
180185
Union['WebDriver', 'ActionHelpers']: Self instance
181186
"""
182187
actions = ActionChains(self)
188+
actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
183189
actions.w3c_actions.pointer_action.move_to_location(start_x, start_y)
184190
actions.w3c_actions.pointer_action.pointer_down()
185191
actions.w3c_actions.pointer_action.move_to_location(end_x, end_y)

appium/webdriver/extensions/search_context/android.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
if TYPE_CHECKING:
2626
from appium.webdriver.webelement import WebElement
2727

28-
T = TypeVar('T', bound=Union[BaseSearchContext, 'AndroidSearchContext'])
28+
T = TypeVar('T', bound='AndroidSearchContext')
2929

3030

3131
class AndroidSearchContext(BaseSearchContext):

appium/webdriver/webdriver.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,9 @@ def _addCommands(self) -> None:
493493
# https://github.com/appium/python-client/issues/342
494494
for mixin_class in filter(lambda x: not issubclass(x, WebDriver), self.__class__.__mro__):
495495
if hasattr(mixin_class, self._addCommands.__name__):
496-
getattr(mixin_class, self._addCommands.__name__, None)(self)
496+
get_atter = getattr(mixin_class, self._addCommands.__name__, None)
497+
if get_atter:
498+
get_atter(self)
497499

498500
self.command_executor._commands[Command.TOUCH_ACTION] = ('POST', '/session/$sessionId/touch/perform')
499501
self.command_executor._commands[Command.MULTI_ACTION] = ('POST', '/session/$sessionId/touch/multi/perform')

0 commit comments

Comments
 (0)