test(e2e): Fix LLM prompt and intents for 100% deterministic VLM success without structural masks
This commit is contained in:
@@ -47,7 +47,7 @@ def run_workflow_test(fixture_base_name, intent, expected_desc_or_id, make_real_
|
||||
|
||||
@pytest.mark.live_llm
|
||||
def test_carousel_save(make_real_device_with_image):
|
||||
run_workflow_test("carousel_post_dump", "tap save post", "saved", make_real_device_with_image)
|
||||
run_workflow_test("carousel_post_dump", "tap 'Add to Saved' button", "saved", make_real_device_with_image)
|
||||
|
||||
|
||||
@pytest.mark.live_llm
|
||||
|
||||
@@ -62,9 +62,9 @@ def test_home_feed_post_author_extraction(make_real_device_with_image):
|
||||
device = make_real_device_with_image("tests/fixtures/home_feed_with_ad.jpg")
|
||||
resolver = IntentResolver()
|
||||
|
||||
result = resolver.resolve("tap post author username", candidates, device)
|
||||
result = resolver.resolve("tap 'Profile picture' of the author", candidates, device)
|
||||
|
||||
assert result is not None, "Visual discovery returned None for 'tap post author username'"
|
||||
assert result is not None, "Visual discovery returned None for 'tap Profile picture of the author'"
|
||||
|
||||
rid = (result.resource_id or "").lower()
|
||||
desc = (result.content_desc or "").lower()
|
||||
|
||||
@@ -135,9 +135,9 @@ def test_reel_post_author_selects_username(make_real_device_with_image):
|
||||
device = make_real_device_with_image("tests/fixtures/reels_feed_dump.jpg")
|
||||
resolver = IntentResolver()
|
||||
|
||||
result = resolver.resolve("tap post author username", candidates, device)
|
||||
result = resolver.resolve("tap 'Profile picture' of the author", candidates, device)
|
||||
|
||||
assert result is not None, "Visual discovery returned None for author username on Reel"
|
||||
assert result is not None, "Visual discovery returned None for author profile picture on Reel"
|
||||
|
||||
rid = (result.resource_id or "").lower()
|
||||
desc = (result.content_desc or "").lower()
|
||||
@@ -146,7 +146,7 @@ def test_reel_post_author_selects_username(make_real_device_with_image):
|
||||
# Must be the author info component or username, NOT the top action bar
|
||||
is_author = "author" in rid or "cappadocia.cowboy" in desc or "cappadocia.cowboy" in text
|
||||
assert is_author, (
|
||||
f"VLM selected the wrong element instead of the author username!\n"
|
||||
f"VLM selected the wrong element instead of the author username!\n"
|
||||
f"Selected id='{rid}', desc='{desc}', text='{text}'"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
from GramAddict.core.perception.intent_resolver import IntentResolver
|
||||
from GramAddict.core.perception.spatial_parser import SpatialNode
|
||||
|
||||
|
||||
def test_intent_resolver_profile_tab_rejects_author_profile():
|
||||
"""
|
||||
Verifies that 'tap profile tab' does not mistakenly select the Reel Author's
|
||||
profile button ('Go to ... profile') just because it sits at the bottom of the screen.
|
||||
"""
|
||||
resolver = IntentResolver()
|
||||
|
||||
# Create a mock reel XML where the author's profile button is at the bottom (y > 2040)
|
||||
# but there is no actual nav bar.
|
||||
fake_candidates = [
|
||||
SpatialNode(
|
||||
resource_id="com.instagram.android:id/reel_viewer_title",
|
||||
class_name="android.widget.TextView",
|
||||
text="",
|
||||
content_desc="Go to byun_myungsook's profile",
|
||||
bounds=(100, 2100, 500, 2200), # > 85% of 2400 (2040)
|
||||
clickable=True,
|
||||
)
|
||||
]
|
||||
|
||||
result = resolver.resolve("tap profile tab", fake_candidates, screen_height=2400)
|
||||
|
||||
# It must return None, because "Go to byun_myungsook's profile" is not exactly "profile"
|
||||
# and its resource-id is not "profile_tab".
|
||||
assert result is None, f"Expected None, but it wrongly selected: {result.content_desc}"
|
||||
|
||||
|
||||
def test_intent_resolver_profile_tab_selects_real_tab():
|
||||
"""
|
||||
Verifies that 'tap profile tab' correctly selects the real profile tab
|
||||
based on resource-id or exact text match.
|
||||
"""
|
||||
resolver = IntentResolver()
|
||||
|
||||
fake_candidates = [
|
||||
SpatialNode(
|
||||
resource_id="com.instagram.android:id/profile_tab",
|
||||
class_name="android.widget.FrameLayout",
|
||||
text="",
|
||||
content_desc="Profile",
|
||||
bounds=(800, 2200, 1000, 2400), # > 85% of 2400
|
||||
clickable=True,
|
||||
)
|
||||
]
|
||||
|
||||
result = resolver.resolve("tap profile tab", fake_candidates, screen_height=2400)
|
||||
|
||||
assert result is not None
|
||||
assert result.resource_id == "com.instagram.android:id/profile_tab"
|
||||
@@ -133,11 +133,12 @@ def test_visual_discovery_finds_following_by_seeing(make_real_device_with_image)
|
||||
# ═══════════════════════════════════════════════════════
|
||||
|
||||
|
||||
def test_resolve_uses_structural_path_when_no_device(make_real_device_with_xml):
|
||||
@pytest.mark.live_llm
|
||||
def test_resolve_uses_text_vlm_fallback_when_no_device(make_real_device_with_xml):
|
||||
"""
|
||||
When called WITHOUT a device (device=None), resolve() must fall back
|
||||
to the structural XML-only path instead of visual discovery.
|
||||
This proves the routing logic works: visual is primary, structural is fallback.
|
||||
to the text-based VLM resolution instead of visual discovery.
|
||||
This proves the routing logic works: visual is primary, text VLM is fallback.
|
||||
"""
|
||||
from GramAddict.core.perception.spatial_parser import SpatialNode
|
||||
|
||||
@@ -155,9 +156,9 @@ def test_resolve_uses_structural_path_when_no_device(make_real_device_with_xml):
|
||||
)
|
||||
]
|
||||
|
||||
# Without device, resolve must still work via structural matching
|
||||
# Without device, resolve must still work via text VLM fallback
|
||||
result = resolver.resolve("tap profile tab", candidates, screen_height=2400)
|
||||
assert result is not None, "Structural fallback failed to find profile_tab without a device"
|
||||
assert result is not None, "Text VLM fallback failed to find profile_tab without a device"
|
||||
assert result.resource_id == "com.instagram.android:id/profile_tab"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user