diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-19 22:28:09 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-19 22:28:09 +0200 |
| commit | 2373b6f02ef027a423762d5d6349cd9e0f36090e (patch) | |
| tree | 7509b0b1905d7c593074bba8ed4c94e30e437604 /tools/tests/test_ui_flow.py | |
| parent | 35042ff04ffc50e55ff59a385849442be4429d6b (diff) | |
test(ui): drive the simulator with a scripted flow and check every screen
tools/ui_flow.py clicks buttons and taps from the device files, waits for
DIAG shown lines and compares 10 screens per watch with goldens on four
test and three spot-check devices. Adds the fixture-wrap generator, UI
logic tests and driver tests; the launcher opens apps from their glance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/tests/test_ui_flow.py')
| -rw-r--r-- | tools/tests/test_ui_flow.py | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/tools/tests/test_ui_flow.py b/tools/tests/test_ui_flow.py new file mode 100644 index 0000000..7e0d336 --- /dev/null +++ b/tools/tests/test_ui_flow.py @@ -0,0 +1,73 @@ +# Author: cirakg & claude ai +# Summary: Tests for the UI flow driver's pure parts: device key layout, JSON lookup and the app-log reader. +from __future__ import annotations + +import json +import threading +import time +from pathlib import Path + +import pytest +import ui_flow + + +def write_sim(tmp_path: Path, config: dict[str, object]) -> Path: + (tmp_path / "simulator.json").write_text(json.dumps(config), encoding="utf-8") + return tmp_path + + +def test_load_keys_gives_button_centres(tmp_path: Path) -> None: + device = write_sim( + tmp_path, + { + "keys": [ + {"id": "enter", "behavior": "onSelect", "location": {"x": 10, "y": 20, "width": 30, "height": 40}}, + { + "id": "menu", + "behavior": "onMenu", + "isHold": True, + "location": {"x": 0, "y": 0, "width": 2, "height": 2}, + }, + {"id": "start", "location": {"x": 5, "y": 5, "width": 10, "height": 10}}, + ] + }, + ) + keys = ui_flow.load_keys(device) + assert keys["enter"] == ui_flow.Key(25, 40, "onSelect", False) + assert keys["menu"].hold + assert keys["start"].behavior == "" + + +def test_find_key_searches_nested_structures() -> None: + data = {"display": {"isTouch": True}, "glance": [{"contentArea": {"x": 1}}]} + assert ui_flow.find_key(data, "isTouch") is True + assert ui_flow.find_key(data, "contentArea") == {"x": 1} + assert ui_flow.find_key(data, "missing") is None + + +def test_app_log_waits_only_for_lines_after_the_mark(tmp_path: Path) -> None: + log_path = tmp_path / "app.log" + log_path.write_text("DIAG shown list\n", encoding="utf-8") + log = ui_flow.AppLog(log_path) + assert log.wait_for(r"DIAG shown list\s*$", 1).group(0).startswith("DIAG shown list") + log.set_mark() + + def append_later() -> None: + time.sleep(0.2) + with log_path.open("a", encoding="utf-8") as f: + f.write("DIAG shown otp\n") + + writer = threading.Thread(target=append_later) + writer.start() + assert log.wait_for(r"DIAG shown otp", 3) + writer.join() + with pytest.raises(ui_flow.FlowError): + log.wait_for(r"DIAG shown list", 0.3) # only before the mark + + +def test_app_log_latest_returns_the_last_match(tmp_path: Path) -> None: + log_path = tmp_path / "app.log" + log_path.write_text("DIAG list_focus y=10\nother\nDIAG list_focus y=42\n", encoding="utf-8") + match = ui_flow.AppLog(log_path).latest(r"DIAG list_focus y=(\d+)") + assert match is not None and match.group(1) == "42" + assert ui_flow.AppLog(tmp_path / "missing.log").latest("x") is None |
