Skip to main content

Automated iOS App Testing

Use Synapse + Computer Control API to automate iOS app testing via Simulator.


Automated iOS App Testing

Combine Synapse's memory system with the Computer Control API to build LLM-driven iOS app tests. The LLM remembers test scenarios, learns from past failures, and adapts to UI changes.

Architecture

┌──────────────┐    commands    ┌──────────────┐    screenshots    ┌──────────────┐
│  LLM Agent   │ ─────────────▶│  Synapse     │ ────────────────▶ │  iOS Sim     │
│  (Claude)    │               │  Computer    │ ◀──────────────── │  (via agent) │
└──────────────┘               │  Control     │    results        └──────────────┘
       │                       └──────────────┘
       │ store/recall
       ▼
┌──────────────┐
│  Memories    │ (test scenarios, past failures, UI patterns)
└──────────────┘

Prerequisites

  • Synapse account + Mind Key
  • Synapse MCP server configured in Claude Desktop
  • iOS Simulator with screen-remote-agent installed
  • Computer registered in Synapse (see Computer Control API)

Step 1: Register the Simulator Computer

On the Mac running iOS Simulator:

# Get install code from Synapse
curl -X POST https://synapse.schaefer.zone/computers/install-code \
  -H "Authorization: Bearer YOUR_MIND_KEY" \
  -d '{"computer_name":"ios-sim"}'
# → { "install_code": "ic_..." }

# Run screen-remote-agent on the Mac
# (uses the install code to register)

Step 2: Store Test Scenarios in Memory

Store reusable test scenarios as memories:

import requests

def store_test_scenario(name, steps, app):
    requests.post(f"{URL}/memory",
        headers={"Authorization": f"Bearer {MIND_KEY}"},
        json={
            "category": "skill",
            "key": f"test_scenario_{name}",
            "content": f"App: {app}\nSteps:\n" + "\n".join(steps),
            "tags": ["test", "ios", app],
            "priority": "high"
        })

store_test_scenario("login_flow", [
    "Launch app",
    "Tap email field",
    "Type test@example.com",
    "Tap password field",
    "Type password123",
    "Tap Login button",
    "Verify home screen appears"
], "MyApp")

Step 3: LLM-Driven Test Execution

In Claude Desktop (with Synapse MCP configured):

Run the login_flow test scenario on the iOS Simulator.
Take a screenshot after each step and verify the expected UI.
If any step fails, store the failure as a memory so we can
avoid it next time.

Claude will:

  1. Call memory_search to find the test_scenario_login_flow memory
  2. Call computer_screenshot to see the current state
  3. Execute each step via computer_command_queue (click, type)
  4. Verify results via screenshots
  5. Store any failures as mistake memories

Step 4: Self-Healing Tests

When a test fails, store the failure and the recovery:

def store_test_failure(scenario, step, error, recovery):
    requests.post(f"{URL}/memory",
        headers={"Authorization": f"Bearer {MIND_KEY}"},
        json={
            "category": "mistake",
            "key": f"failure_{scenario}_{step}",
            "content": f"Scenario: {scenario}\nStep: {step}\nError: {error}\nRecovery: {recovery}",
            "tags": ["test", "failure", "ios", scenario],
            "priority": "high"
        })

# Example
store_test_failure("login_flow", "tap_login",
    "Login button not found at expected coordinates",
    "Button moved due to new logo. Search by accessibility label instead.")

Next time the LLM runs the test, it recalls the failure and applies the recovery automatically.

Step 5: Test Result Tracking

Track test runs as tasks:

def track_test_run(scenario, status, duration):
    requests.post(f"{URL}/mind/task",
        headers={"Authorization": f"Bearer {MIND_KEY}",
                 "Content-Type": "application/json"},
        json={
            "title": f"Test: {scenario}",
            "description": f"Status: {status}, Duration: {duration}s",
            "priority": "normal"
        })

Common Commands

Action Command
Launch Simulator xcrun simctl launch booted com.example.app
Screenshot computer_screenshot (via Synapse MCP)
Tap at (x,y) computer_command_queue {type:"click", payload:{x,y}}
Type text computer_command_queue {type:"type", payload:{text:"..."}}
Press Home computer_command_queue {type:"key", payload:{keys:["Cmd","Shift","H"]}}

Best Practices

Next Steps