# IOS Simulator Debug

> Debug React Native app in iOS simulator. Execute JavaScript functions via WebSocket, tap/swipe UI elements, take screenshots, inspect accessibility tree, control GPS, and manage app lifecycle. Use when testing or debugging the app during development.

- Skill: `nilskj/ios-simulator-debug` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add nilskj/ios-simulator-debug`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nilskj/ios-simulator-debug/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: nilskj (https://skillmd.com/u/nilskj)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nilskj/ios-simulator-debug

---


# iOS Simulator Debug

Complete debugging toolkit for React Native on iOS Simulator:
- **JavaScript execution** via Chrome DevTools Protocol
- **UI automation** with Facebook's `idb` (tap, swipe, text input)
- **Visual inspection** (screenshots, accessibility tree)
- **Simulator control** (GPS, appearance, app lifecycle)

## Prerequisites

- App running with Metro bundler (`pnpm ios`)
- `ws` npm package (install once: `cd <skill-dir> && npm install`)
- `idb` (iOS Development Bridge) — already installed

## Execute JavaScript in the App

Run any JS expression in the running app context via WebSocket:

```bash
./scripts/js-eval.js '<expression>'
```

### Subscription Debug Functions

```bash
./scripts/js-eval.js '__showSubscription()'
./scripts/js-eval.js '__setSubscription("global_driver")'
./scripts/js-eval.js '__setSubscription("road_traveller")'
./scripts/js-eval.js '__setSubscription("lifetime")'
./scripts/js-eval.js '__clearSubscription()'
```

Tiers: `free` (default), `road_traveller` (Basic — British spelling), `global_driver` (Unlimited), `lifetime`

### Arbitrary JS

```bash
./scripts/js-eval.js '2 + 2'
./scripts/js-eval.js 'Object.keys(globalThis).filter(k => k.startsWith("__")).join(", ")'
```

## UI Automation (idb)

### Tap

```bash
./scripts/tap.sh X Y [duration]
```

Examples:
```bash
./scripts/tap.sh 200 400              # Quick tap
./scripts/tap.sh 200 400 1.0          # Long press (1 second)
```

### Swipe

```bash
./scripts/swipe.sh X1 Y1 X2 Y2 [duration]
```

Examples:
```bash
./scripts/swipe.sh 200 600 200 200   # Swipe up
./scripts/swipe.sh 100 400 500 400   # Swipe right
```

### Type Text

```bash
./scripts/type.sh "text to type"
```

### Hardware Buttons

```bash
./scripts/button.sh HOME
./scripts/button.sh LOCK
./scripts/button.sh SIRI
./scripts/button.sh SIDE_BUTTON
```

## Visual Inspection

### Screenshot

```bash
./scripts/screenshot.sh [output_path]
./scripts/screenshot.sh                    # Saves to /tmp/idb_screenshot_*.png
./scripts/screenshot.sh ~/Desktop/app.png  # Custom path
```

### Describe UI Elements

```bash
./scripts/describe.sh all          # Full accessibility tree (JSON)
./scripts/describe.sh 200 400      # Element at coordinates (JSON)
```

The accessibility tree shows:
- Element types (Button, Text, etc.)
- Labels and values
- Frame coordinates (x, y, width, height)
- Enabled/visible state
- Hierarchy

## Simulator Control

### GPS Location (idb)

```bash
./scripts/location.sh LAT LNG
./scripts/location.sh 37.7749 -122.4194   # San Francisco (NorCal)
./scripts/location.sh 34.0522 -118.2437   # Los Angeles (SoCal)
./scripts/location.sh 29.7604 -95.3698    # Houston, Texas
./scripts/location.sh 59.3293 18.0686     # Stockholm, Sweden
```

### Appearance (xcrun)

```bash
xcrun simctl ui booted appearance dark
xcrun simctl ui booted appearance light
```

### App Lifecycle (xcrun)

```bash
xcrun simctl terminate booted com.nordhud.app
xcrun simctl launch booted com.nordhud.app
curl -s "http://localhost:8081/reload"               # Hot reload Metro
```

## Testing Workflow

Complete end-to-end testing example:

```bash
# 1. Take screenshot to see current state
./scripts/screenshot.sh

# 2. Get accessibility tree to find elements
./scripts/describe.sh all | jq '.[] | select(.label | contains("Settings"))'

# 3. Tap the Settings button (found at coordinates)
./scripts/tap.sh 690 970

# 4. Change subscription via JavaScript
./scripts/js-eval.js '__setSubscription("global_driver")'

# 5. Verify UI updated
./scripts/screenshot.sh

# 6. Navigate back (tap back button at top-left)
./scripts/tap.sh 38 81

# 7. Test location-based features
./scripts/location.sh 37.7749 -122.4194

# 8. Take final screenshot
./scripts/screenshot.sh
```

## Finding Element Coordinates

Use `describe.sh all` to get the accessibility tree, then extract coordinates:

```bash
# Get all buttons and their positions
./scripts/describe.sh all | jq '.[] | select(.type == "Button") | {label, frame}'

# Find specific element
./scripts/describe.sh all | jq '.[] | select(.label | contains("Settings")) | .frame'

# Output: {"x": 660, "y": 940, "width": 60, "height": 60}
# Tap center: x + width/2, y + height/2 = 690, 970
```

## Metro Logs

If running Metro in tmux:

```bash
tmux capture-pane -t dev -p | tail -30              # Last 30 lines
tmux capture-pane -t dev -p | grep -i subscription  # Filter
```

## Common Patterns

### Navigate to Settings

```bash
./scripts/tap.sh 200 600                  # Show toolbar (if hidden)
./scripts/tap.sh 690 970                  # Tap Settings button
```

### Test Subscription Changes

```bash
./scripts/js-eval.js '__setSubscription("global_driver")'
./scripts/screenshot.sh
./scripts/describe.sh all | jq '.[] | select(.label | contains("Unlimited"))'
```

### Test GPS-Based Features

```bash
./scripts/location.sh 37.7749 -122.4194   # Set to NorCal
sleep 2                                    # Wait for app to react
./scripts/screenshot.sh
./scripts/describe.sh all | grep -i "norcal"
```

### Full UI Test Flow

```bash
# Take initial screenshot
./scripts/screenshot.sh initial.png

# Change state via JS
./scripts/js-eval.js '__setSubscription("global_driver")'

# Navigate to feature that requires subscription
./scripts/tap.sh 690 970                  # Settings
./scripts/tap.sh 400 600                  # Some feature
./scripts/screenshot.sh feature.png

# Verify feature is unlocked
./scripts/describe.sh all | jq '.[] | select(.enabled == true)'
```

## Reference: MCP iOS Simulator Tools

If the MCP ios-simulator tools are available, they provide similar functionality:

```
mcp__ios-simulator__ui_view          # Screenshot
mcp__ios-simulator__ui_describe_all  # Accessibility tree
mcp__ios-simulator__ui_tap           # Tap at (x, y)
mcp__ios-simulator__ui_swipe         # Swipe gesture
mcp__ios-simulator__ui_type          # Type text
mcp__ios-simulator__launch_app       # Launch by bundle ID
```

This skill's scripts (`tap.sh`, `describe.sh`, etc.) use `idb` directly and are faster for scripting.

## Troubleshooting

### "Could not connect to Metro"
Metro isn't running. Start with `pnpm ios`.

### "idb: command not found"
Install idb: `brew tap facebook/fb && brew install idb-companion`

### JavaScript eval timeout
App may have reloaded. Re-run the command.

### Tap/swipe not working
- Verify coordinates with `./scripts/describe.sh all`
- Check if element is visible/enabled
- Take screenshot first to confirm layout

### Screenshot shows wrong state
Wait a moment after actions: `sleep 1 && ./scripts/screenshot.sh`

## Advanced: idb Direct Commands

You can use `idb` directly for more features:

```bash
idb video record video.mp4 &           # Start recording
# ... perform actions ...
killall idb                            # Stop recording

idb log --tail                         # Stream device logs
idb file push local.txt /tmp/app.txt   # Push file to device
idb contacts update                    # Update contacts database
```

See `idb --help` for all commands.

