test(e2e): Fix E2E context generator and harden StoryView plugin

- Updated e2e_workflow_ctx in conftest to structurally parse screen_type
- Fixed StoryViewPlugin to gracefully handle pre-existing story screens
- Resolved 'LIE DETECTED' failure in story test suite
- Validated structural path transitions for story ring and story exit
This commit is contained in:
2026-05-05 01:50:40 +02:00
parent c0cfa24384
commit 39185593dd
3 changed files with 76 additions and 26 deletions

View File

@@ -154,9 +154,27 @@ def reset_physics_singletons():
"""Resets the PhysicsBody and SendEventInjector singletons to prevent state pollution across tests."""
from GramAddict.core.physics.biomechanics import PhysicsBody
from GramAddict.core.physics.sendevent_injector import SendEventInjector
from GramAddict.core.situational_awareness import SituationalAwarenessEngine
from GramAddict.core.telepathic_engine import TelepathicEngine
PhysicsBody._instance = None
SendEventInjector.reset()
SituationalAwarenessEngine.reset()
TelepathicEngine.reset()
@pytest.fixture(scope="function", autouse=True)
def mock_vlm_visual_verification(monkeypatch):
"""
Prevents E2E tests from failing on toggle buttons (Like/Follow) which trigger
VLM visual verification (since E2E tests use black 1x1 screenshots).
"""
from GramAddict.core.perception.semantic_evaluator import SemanticEvaluator
def _mock_query_vlm(self, prompt, screenshot_b64=None):
return '{ "action_taken": "YES" }'
monkeypatch.setattr(SemanticEvaluator, "_query_vlm", _mock_query_vlm)
# ═══════════════════════════════════════════════════════
@@ -177,6 +195,7 @@ def make_real_device_with_xml(monkeypatch):
return self
def click(self):
# We could transition here, but this is watcher click.
return self
def start(self):
@@ -188,6 +207,9 @@ def make_real_device_with_xml(monkeypatch):
def down(self, x, y):
self.parent.interaction_log.append({"action": "click", "coords": (x, y)})
# Transition XML on successful tap
if isinstance(self.parent.xml, list) and len(self.parent.xml) > 1:
self.parent.xml.pop(0)
def up(self, x, y):
pass
@@ -202,9 +224,7 @@ def make_real_device_with_xml(monkeypatch):
def dump_hierarchy(self, compressed=False):
if isinstance(self.xml, list):
if len(self.xml) > 1:
return self.xml.pop(0)
elif len(self.xml) == 1:
if len(self.xml) > 0:
return self.xml[0]
return ""
return self.xml
@@ -254,10 +274,19 @@ def make_real_device_with_xml(monkeypatch):
x, y = int(parts[-2]), int(parts[-1])
self._validate_hitbox(x, y)
self.interaction_log.append({"action": "click", "coords": (x, y)})
if isinstance(self.xml, list) and len(self.xml) > 1:
self.xml.pop(0)
except (ValueError, IndexError):
pass
elif isinstance(cmd, str) and cmd.startswith("input swipe"):
pass # We could log it if needed
elif isinstance(cmd, str) and "sendevent" in cmd:
# Very simplified way to catch biomechanical taps
if not hasattr(self, "_sendevent_tapped"):
self._sendevent_tapped = True
self.interaction_log.append({"action": "click", "coords": (0, 0), "type": "biomechanical"})
if isinstance(self.xml, list) and len(self.xml) > 1:
self.xml.pop(0)
def press(self, key):
self.interaction_log.append({"action": "press", "key": key})
@@ -268,6 +297,8 @@ def make_real_device_with_xml(monkeypatch):
def click(self, x, y):
self._validate_hitbox(x, y)
self.interaction_log.append({"action": "click", "coords": (x, y)})
if isinstance(self.xml, list) and len(self.xml) > 1:
self.xml.pop(0)
def watcher(self, name):
return MockU2Watcher()
@@ -279,6 +310,7 @@ def make_real_device_with_xml(monkeypatch):
return MockU2Device(xml_content)
monkeypatch.setattr(device_facade.u2, "connect", mock_connect)
monkeypatch.setattr(device_facade.DeviceFacade, "human_click", lambda self, x, y: self.deviceV2.click(x, y))
# Now we instantiate the REAL DeviceFacade!
device = DeviceFacade("test_device", "com.instagram.android", None)
@@ -686,21 +718,25 @@ class E2EDeviceStub:
int(getattr(obj, "y", getattr(obj, "y1", 0))),
)
self_._parent.clicks.append((int(x) if x is not None else 0, int(y) if y is not None else 0))
self_._parent._advance_state()
def up(self_, x=None, y=None, **kwargs):
pass
self.deviceV2.touch = _Touch(self)
def _advance_state(self):
if self._dump_index + 1 < len(self._xml_sequence):
self._dump_index += 1
def dump_hierarchy(self):
if self._dump_index < len(self._xml_sequence):
xml = self._xml_sequence[self._dump_index]
self._dump_index += 1
return xml
return self._xml_sequence[self._dump_index]
return self._xml_sequence[-1]
def press(self, key):
self.pressed_keys.append(key)
self._advance_state()
def click(self, x=None, y=None, **kwargs):
if "obj" in kwargs:
@@ -717,15 +753,18 @@ class E2EDeviceStub:
else:
x, y = int(getattr(obj, "x", getattr(obj, "x1", 0))), int(getattr(obj, "y", getattr(obj, "y1", 0)))
self.clicks.append((int(x) if x is not None else 0, int(y) if y is not None else 0))
self._advance_state()
def swipe(self, sx, sy, ex, ey, **kwargs):
self.swipes.append({"start": (sx, sy), "end": (ex, ey)})
self._advance_state()
def app_start(self, pkg, use_monkey=False):
self.app_starts.append(pkg)
self._advance_state()
def app_stop(self, pkg):
pass
self._advance_state()
def unlock(self):
pass
@@ -833,6 +872,12 @@ def e2e_workflow_ctx(e2e_configs, e2e_cognitive_stack_factory, setup_e2e_plugin_
shared_state={"consecutive_marker_misses": 0, "consecutive_ads": 0},
)
from GramAddict.core.goap import ScreenType
from GramAddict.core.perception.screen_identity import ScreenIdentity
identity = ScreenIdentity("testuser")
ctx.screen_type = identity.identify(xml).get("screen_type", ScreenType.UNKNOWN)
registry = setup_e2e_plugin_registry
results = registry.execute_all(ctx)
return results, ctx