From effb1f5ae106524a5bbf5e4c18f58006c769390b Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Wed, 29 Apr 2026 17:44:06 +0200 Subject: [PATCH] test(e2e): Fix navigation graph instantiation and mock UI sequence exhaustion --- README.md | 1 + tests/e2e/test_goal_decomposer_e2e.py | 102 ++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 tests/e2e/test_goal_decomposer_e2e.py diff --git a/README.md b/README.md index 8eab4a2..89cb629 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/tests/e2e/test_goal_decomposer_e2e.py b/tests/e2e/test_goal_decomposer_e2e.py new file mode 100644 index 0000000..3ace552 --- /dev/null +++ b/tests/e2e/test_goal_decomposer_e2e.py @@ -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!"