"""Tests for UI inspection mixin (dump, find, wait, tap_text)."""
from tests.conftest import fail, ok
SAMPLE_UI_XML = """
"""
class TestUiDump:
async def test_dump(self, server, ctx):
server.run_shell_args.side_effect = [
ok(), # uiautomator dump
ok(stdout=SAMPLE_UI_XML), # cat
ok(), # rm cleanup
]
result = await server.ui_dump(ctx)
assert result["success"] is True
assert result["element_count"] >= 2 # Settings + Wi-Fi at minimum
assert "xml" in result
async def test_dump_failure(self, server, ctx):
server.run_shell_args.return_value = fail("error")
result = await server.ui_dump(ctx)
assert result["success"] is False
class TestParseUiElements:
def test_parse_clickable(self, server):
elements = server._parse_ui_elements(SAMPLE_UI_XML)
texts = [e["text"] for e in elements]
assert "Settings" in texts
assert "Wi-Fi" in texts
def test_center_coordinates(self, server):
elements = server._parse_ui_elements(SAMPLE_UI_XML)
settings = [e for e in elements if e["text"] == "Settings"][0]
assert settings["center"] == {"x": 100, "y": 125}
def test_content_desc_included(self, server):
elements = server._parse_ui_elements(SAMPLE_UI_XML)
icon = [e for e in elements if e["content_desc"] == "Settings icon"]
assert len(icon) == 1
def test_empty_xml(self, server):
elements = server._parse_ui_elements("")
assert elements == []
class TestUiFindElement:
async def test_find_by_text(self, server):
server.run_shell_args.side_effect = [ok(), ok(stdout=SAMPLE_UI_XML), ok()]
result = await server.ui_find_element(text="Settings")
assert result["success"] is True
assert result["count"] == 1
assert result["matches"][0]["text"] == "Settings"
async def test_find_by_resource_id(self, server):
server.run_shell_args.side_effect = [ok(), ok(stdout=SAMPLE_UI_XML), ok()]
result = await server.ui_find_element(resource_id="title")
# Settings and Wi-Fi both have "title" in their resource-id
assert result["count"] >= 2
async def test_not_found(self, server):
server.run_shell_args.side_effect = [ok(), ok(stdout=SAMPLE_UI_XML), ok()]
result = await server.ui_find_element(text="Missing")
assert result["success"] is True
assert result["count"] == 0
class TestWaitForText:
async def test_found_immediately(self, server):
server.run_shell_args.side_effect = [ok(), ok(stdout=SAMPLE_UI_XML), ok()]
result = await server.wait_for_text("Settings", timeout_seconds=1)
assert result["success"] is True
assert result["found"] is True
assert result["attempts"] == 1
async def test_timeout(self, server):
server.run_shell_args.side_effect = [
ok(),
ok(stdout=""),
ok(),
] * 10
result = await server.wait_for_text(
"Missing", timeout_seconds=0.1, poll_interval=0.05
)
assert result["success"] is False
assert result["found"] is False
class TestWaitForTextGone:
async def test_already_gone(self, server):
server.run_shell_args.side_effect = [
ok(),
ok(stdout=""),
ok(),
]
result = await server.wait_for_text_gone("Missing", timeout_seconds=1)
assert result["success"] is True
assert result["gone"] is True
class TestTapText:
async def test_tap_found(self, server):
# find_element calls ui_dump which has 3 calls, then tap has 1
server.run_shell_args.side_effect = [
ok(),
ok(stdout=SAMPLE_UI_XML),
ok(), # ui_dump for find
ok(), # tap
]
result = await server.tap_text("Settings")
assert result["success"] is True
assert result["coordinates"] == {"x": 100, "y": 125}
async def test_not_found(self, server):
server.run_shell_args.side_effect = [
ok(),
ok(stdout=SAMPLE_UI_XML),
ok(), # first search by text
ok(),
ok(stdout=SAMPLE_UI_XML),
ok(), # fallback search by content_desc
]
result = await server.tap_text("NonExistent")
assert result["success"] is False
assert "No element found" in result["error"]