test(e2e): Fix navigation graph instantiation and mock UI sequence exhaustion

This commit is contained in:
2026-04-29 17:44:06 +02:00
parent 0e43996ccd
commit effb1f5ae1
2 changed files with 103 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ If Instagram updates its app and moves a button, GramPilot doesn't crash. It fal
## ✨ Core Features
* 🚫 **Zero Limits Configuration**: Forget about configuring "max_likes" or "delays". GramPilot uses a **Dopamine Pacing Engine** to simulate human boredom. If the content isn't interesting, it skips it or ends the session early.
* 🎯 **Mission-Driven Navigation**: Say goodbye to abstract goal configurations. Define a `strategy` (like `aggressive_growth` or `nurture_community`) in `config.yml`, and the **Goal Decomposer Engine** automatically orchestrates the optimal routing and task allocation using enabled plugins.
* ⚖️ **Active Inference (Shadow Mode)**: The bot continuously predicts the outcome of its clicks. If it lands on a popup instead of a profile, it registers a "Prediction Error", presses back, and dynamically recalibrates without panicking.
* ⛩️ **Telepathic Engine**: A strictly tiered resolution cascade (Keyword -> Vectors -> LLM) that ensures 90% of navigation happens at 0-token cost while maintaining fallback AI resilience.
* 🧬 **Resonance Oracle**: The bot only interacts with content that matches a pre-defined persona aesthetic, completely bypassing spam or low-quality content.

View File

@@ -0,0 +1,102 @@
"""
E2E Test: Goal Decomposition and Autonomous Orchestration
==========================================================
This test proves that the bot's core autonomy pipeline (Task Generation -> Selection -> Navigation)
works end-to-end using real configuration objects and real UI XML dumps.
"""
import os
import pytest
from GramAddict.core.goal_decomposer import GoalDecomposer
from GramAddict.core.growth_brain import GrowthBrain
from GramAddict.core.q_nav_graph import QNavGraph
from GramAddict.core.telepathic_engine import TelepathicEngine
FIXTURE_DIR = os.path.join(os.path.dirname(__file__), "fixtures")
def _load_fixture(name: str) -> str:
path = os.path.join(FIXTURE_DIR, name)
with open(path, "r", encoding="utf-8") as f:
return f.read()
class MockZeroEngine:
"""Mock ZeroEngine needed by nav_graph to run actions without full active_inference logic."""
def __init__(self, device):
self.device = device
self.telepathic = TelepathicEngine()
def do(self, intent: str):
# Simplistic execution for navigation
xml = self.device.dump_hierarchy()
node = self.telepathic.find_best_node(xml, intent, self.device)
if node:
# Just pretend we clicked
return True
return False
@pytest.mark.live_llm
class TestAutonomousOrchestrationE2E:
"""End-to-End pipeline: Config -> GoalDecomposer -> GrowthBrain -> NavGraph -> UI XML"""
def test_e2e_mission_to_explore_feed_navigation(self, make_real_device_with_xml, monkeypatch):
"""
Simulates the bot_flow.py autonomous loop:
1. Decomposer parses aggressive_growth mission.
2. Brain selects ExploreFeed task.
3. Orchestrator uses nav_graph to reach ExploreFeed.
"""
# 1. Setup simulated device with XML sequence
home_xml = _load_fixture("home_feed_real.xml")
explore_xml = _load_fixture("explore_grid_real.xml")
# Sequence for nav_graph.navigate_to("ExploreFeed")
# We provide a long sequence of explore_xml at the end to simulate the app remaining on the Explore screen
# after the transition.
xml_sequence = [
home_xml, # Initial perception (HomeFeed)
home_xml, # finding explore button
explore_xml, # post-click state (ExploreFeed)
explore_xml, # Goal validation check
] + [explore_xml] * 20
device = make_real_device_with_xml(xml_sequence)
# 2. Fake Config inputs
mission = {"strategy": "aggressive_growth"}
plugins = {"likes": {"percentage": 100}}
actions = {"explore": "1-3"}
# 3. Generate Tasks
decomposer = GoalDecomposer(plugins=plugins, actions=actions, mission=mission)
tasks = decomposer.generate_tasks()
assert len(tasks) > 0, "Decomposer must generate tasks"
# Force selection of ExploreFeed for deterministic test
monkeypatch.setattr(
"random.choices", lambda population, weights, k: [t for t in population if t.target_screen == "ExploreFeed"]
)
# 4. Brain Selection
brain = GrowthBrain(username="testuser")
class MockDopamine:
boredom = 0.0
selected_task = brain.select_task(MockDopamine(), tasks)
assert selected_task is not None
assert selected_task.target_screen == "ExploreFeed"
# 5. Execute Navigation (mimicking bot_flow.py)
nav_graph = QNavGraph(device=device)
zero_engine = MockZeroEngine(device)
success = nav_graph.navigate_to(selected_task.target_screen, zero_engine)
assert success is True, "Orchestrator failed to navigate to the decomposed Task's target screen!"