feat(driver): add W3C actions helper and Driver.swipe_path

This commit is contained in:
2026-07-15 19:04:57 +08:00
parent ff91bd4f70
commit c25ccb491d
10 changed files with 189 additions and 0 deletions
+5
View File
@@ -64,6 +64,11 @@ class FakeDriver(Driver):
) -> None:
self.calls.append(("swipe", (start_x, start_y, end_x, end_y, duration_ms)))
def swipe_path(
self, waypoints: list[tuple[float, float]], duration_ms: int
) -> None:
self.calls.append(("swipe_path", (tuple(waypoints), duration_ms)))
def input(self, text: str) -> None:
self.calls.append(("input", (text,)))
+18
View File
@@ -104,6 +104,7 @@ def test_connect_failure_raises_device_offline_and_clears_client() -> None:
("unlock", {}),
("disconnect", {}),
("long_press", {"x": 1, "y": 2}),
("swipe_path", {"waypoints": [(0, 0), (1, 1)], "duration_ms": 100}),
],
)
def test_operation_before_connect_raises_device_offline(
@@ -229,6 +230,23 @@ def test_home_uses_presskey_with_home_keycode() -> None:
)
def test_swipe_path_sends_w3c_actions() -> None:
from driver._w3c_actions import build_swipe_actions
driver = _connected_driver()
waypoints = [(0, 0), (50, 5), (100, 0)]
driver.swipe_path(waypoints, 600)
args = driver._client.execute.call_args.args
assert args[1] == {"actions": build_swipe_actions(waypoints, 600)}
def test_swipe_path_wraps_exception_into_driver_error() -> None:
driver = _connected_driver()
driver._client.execute.side_effect = RuntimeError("boom")
with pytest.raises(DriverError):
driver.swipe_path([(0, 0), (1, 1)], 100)
def test_swipe_uses_drag_gesture_with_converted_speed() -> None:
driver = _connected_driver()
# 100px horizontal drag over 100ms => 100 / 0.1 = 1000 px/s
+5
View File
@@ -46,6 +46,11 @@ class TreeFailingDriver(Driver):
) -> None:
return None
def swipe_path(
self, waypoints: list[tuple[float, float]], duration_ms: int
) -> None:
return None
def input(self, text: str) -> None:
return None
+53
View File
@@ -0,0 +1,53 @@
from __future__ import annotations
import pytest
from driver._w3c_actions import (
build_double_tap_actions,
build_swipe_actions,
)
def test_build_swipe_actions_shape_and_duration_split():
actions = build_swipe_actions([(0, 0), (50, 10), (100, 0)], 600)
assert len(actions) == 1
pointer = actions[0]
assert pointer["type"] == "pointer"
assert pointer["id"] == "finger1"
assert pointer["parameters"]["pointerType"] == "touch"
seq = pointer["actions"]
types = [a["type"] for a in seq]
assert types == [
"pointerMove",
"pointerDown",
"pointerMove",
"pointerMove",
"pointerUp",
]
# 600ms over 2 segments => 300ms per move after pointerDown
moves_after_down = [a for a in seq if a["type"] == "pointerMove"][1:]
assert all(m["duration"] == 300 for m in moves_after_down)
assert seq[0]["x"] == 0 and seq[0]["y"] == 0
assert seq[-1]["x"] == 100 and seq[-1]["y"] == 0
def test_build_swipe_actions_requires_two_waypoints():
with pytest.raises(ValueError):
build_swipe_actions([(1, 1)], 100)
def test_build_double_tap_actions_shape():
actions = build_double_tap_actions(10, 20, interval_ms=80)
seq = actions[0]["actions"]
types = [a["type"] for a in seq]
assert types == [
"pointerMove",
"pointerDown",
"pointerUp",
"pause",
"pointerDown",
"pointerUp",
]
pause = next(a for a in seq if a["type"] == "pause")
assert pause["duration"] == 80
assert seq[0]["x"] == 10 and seq[0]["y"] == 20