feat(tools): humanize tap coordinates; default off in tests

This commit is contained in:
2026-07-15 19:29:57 +08:00
parent d8e7be4ccb
commit 85f0d6e188
4 changed files with 60 additions and 3 deletions
+11
View File
@@ -0,0 +1,11 @@
import pytest
@pytest.fixture(autouse=True)
def _humanize_disabled_by_default_in_tests(monkeypatch):
"""Humanize defaults ON in production; tests default it OFF so existing
exact-coordinate assertions stay deterministic. Tests that want to
exercise humanize call ``monkeypatch.setenv("APEX_HUMANIZE_ENABLED", "true")``
in their own body, which overrides this fixture (test body runs after
fixture setup)."""
monkeypatch.setenv("APEX_HUMANIZE_ENABLED", "false")
+38
View File
@@ -0,0 +1,38 @@
from __future__ import annotations
from device.manager import DeviceManager
from tests.fakes import FakeDriver
def _connected(driver: FakeDriver) -> DeviceManager:
manager = DeviceManager()
manager.register_device("phone", lambda: driver)
manager.connect("phone", max_retries=1)
return manager
def test_tap_default_off_in_tests_passes_exact(monkeypatch):
# Autouse conftest fixture sets APEX_HUMANIZE_ENABLED=false; reaffirm here.
monkeypatch.setenv("APEX_HUMANIZE_ENABLED", "false")
from tools.tap import tap
driver = FakeDriver()
tap(10, 20, manager=_connected(driver))
assert driver.calls[-1] == ("tap", (10, 20))
def test_tap_enabled_jitters_within_radius(monkeypatch):
import random
monkeypatch.setenv("APEX_HUMANIZE_ENABLED", "true")
from tools.humanize import set_rng
from tools.tap import tap
set_rng(random.Random(11))
try:
driver = FakeDriver()
tap(10, 20, manager=_connected(driver))
finally:
set_rng(None)
px, py = driver.calls[-1][1]
assert abs(px - 10) <= 5.0 and abs(py - 20) <= 5.0
+4 -1
View File
@@ -28,7 +28,10 @@ class HumanizeConfig:
def load_humanize_config(env: Mapping[str, str] | None = None) -> HumanizeConfig:
values = env or os.environ
if env is None:
values: Mapping[str, str] = os.environ
else:
values = env
return HumanizeConfig(
enabled=_parse_bool(values.get(ENABLED_ENV), default=True),
tap_radius_px=_parse_float(values.get(TAP_RADIUS_ENV), DEFAULT_TAP_RADIUS_PX),
+7 -2
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
from device.manager import DeviceManager
from tools._device import get_driver
from tools.humanize import get_rng, jitter_point, load_humanize_config
def tap(
@@ -11,5 +12,9 @@ def tap(
device_id: str | None = None,
manager: DeviceManager | None = None,
) -> dict[str, object]:
get_driver(device_id, manager=manager).tap(x, y)
return {"ok": True, "action": "tap", "x": x, "y": y}
cfg = load_humanize_config()
px, py = x, y
if cfg.enabled:
px, py = jitter_point(x, y, radius=cfg.tap_radius_px, rng=get_rng())
get_driver(device_id, manager=manager).tap(px, py)
return {"ok": True, "action": "tap", "x": px, "y": py}