Installation (prerequisite):
brew install cameroncooke/axe/axe
The iOS Simulator must be running with the app under test.
Observe
- Take a screenshot:
axe screenshot --udid {UDID} --output /tmp/screen.png
- Read the accessibility tree:
axe describe-ui --udid {UDID}
- To inspect a specific point:
axe describe-ui --point 100,200 --udid {UDID}
Act — choose based on what you need to do:
- Tap by accessibility label:
axe tap --label "Login" --udid {UDID}
- Tap by accessibility identifier:
axe tap --id "loginButton" --udid {UDID}
- Tap by coordinates (fallback):
axe tap -x 200 -y 400 --udid {UDID}
- Type text:
axe type 'user@example.com' --udid {UDID}
- Type from stdin:
echo "text" | axe type --stdin --udid {UDID}
- Type from file:
axe type --file input.txt --udid {UDID}
- Scroll:
axe gesture scroll-down --udid {UDID}
- Swipe:
axe swipe --start-x 200 --start-y 500 --end-x 200 --end-y 200 --duration 0.3 --udid {UDID}
- Advanced touch (hold):
axe touch -x 150 -y 250 --down --up --delay 1.0 --udid {UDID}
- Press key:
axe key 40 --udid {UDID} (Enter)
- Key sequence:
axe key-sequence --keycodes 11,8,15,15,18 --udid {UDID}
- Home button:
axe button home --udid {UDID}
- Siri:
axe button siri --udid {UDID}
Verify
After each action, take a screenshot and check whether the expected change occurred. If something is wrong, note the issue and investigate.
Timing controls — add delays when animations or loading cause flakiness:
--pre-delay 0.5 — wait before acting
--post-delay 1.0 — wait after acting
--duration 0.3 — control gesture speed
For specific screen sizes: axe gesture swipe-from-left-edge --screen-width 430 --screen-height 932 --udid {UDID}
# Stream logs from the booted simulator (Ctrl+C to stop)
xcrun simctl spawn booted log stream --level debug --predicate 'subsystem == "com.apple.UIKit" OR processImagePath CONTAINS "{APP_NAME}"' 2>&1 | head -200
# Get recent log entries
xcrun simctl spawn booted log show --last 5m --predicate 'processImagePath CONTAINS "{APP_NAME}"' --style compact
# Check for crash logs
ls ~/Library/Logs/DiagnosticReports/*{APP_NAME}* 2>/dev/null
Replace {APP_NAME} with the app's process name (visible in describe-ui output or from xcrun simctl listapps booted).
If this is a React Native app, invoke the debugging-react-native skill (https://github.com/mikekelly/debugging-react-native) for React Native-specific diagnosis including Metro bundler issues, JS errors, and red box screens.
1---2name: outside-in-testing-ios-apps3description: Test iOS apps running in Simulator from the outside in. Use PROACTIVELY when you need to verify an iOS app works, run acceptance tests, check UI behavior, perform outside-in testing, end-to-end testing, functional testing, exploratory testing, or smoke testing of iOS apps. Covers launching test flows, verifying screens, interacting with UI elements, and diagnosing failures. Triggers on: test my app, verify the app, check the UI, does this work, acceptance test, outside-in test, e2e test, functional test, smoke test, exploratory test.4---56<objective>7Guide agents through outside-in testing of iOS apps running in Simulator. The agent interacts with the app as a real user would — navigating screens, tapping buttons, entering text, and verifying that the app behaves correctly. When the app misbehaves, the agent diagnoses failures using simulator logs.8</objective>910<tool>11All interactions use the AXe CLI (`axe`), a tool for driving iOS Simulators via accessibility APIs and HID.1213**Installation (prerequisite):**14```bash15brew install cameroncooke/axe/axe16```1718The iOS Simulator must be running with the app under test.19</tool>2021<quick_start>221. Find the simulator: `axe list-simulators` — look for a Booted simulator, capture its UDID232. Screenshot current state: `axe screenshot --udid {UDID} --output /tmp/screen.png`243. Describe the UI: `axe describe-ui --udid {UDID}`254. Interact: `axe tap --label "Button" --udid {UDID}`265. Repeat: screenshot → describe → interact → verify27</quick_start>2829<process>30Follow an **Observe → Act → Verify** loop for each step of the test flow.3132**Observe**33- Take a screenshot: `axe screenshot --udid {UDID} --output /tmp/screen.png`34- Read the accessibility tree: `axe describe-ui --udid {UDID}`35- To inspect a specific point: `axe describe-ui --point 100,200 --udid {UDID}`3637**Act** — choose based on what you need to do:3839- Tap by accessibility label: `axe tap --label "Login" --udid {UDID}`40- Tap by accessibility identifier: `axe tap --id "loginButton" --udid {UDID}`41- Tap by coordinates (fallback): `axe tap -x 200 -y 400 --udid {UDID}`42- Type text: `axe type 'user@example.com' --udid {UDID}`43- Type from stdin: `echo "text" | axe type --stdin --udid {UDID}`44- Type from file: `axe type --file input.txt --udid {UDID}`45- Scroll: `axe gesture scroll-down --udid {UDID}`46- Swipe: `axe swipe --start-x 200 --start-y 500 --end-x 200 --end-y 200 --duration 0.3 --udid {UDID}`47- Advanced touch (hold): `axe touch -x 150 -y 250 --down --up --delay 1.0 --udid {UDID}`48- Press key: `axe key 40 --udid {UDID}` (Enter)49- Key sequence: `axe key-sequence --keycodes 11,8,15,15,18 --udid {UDID}`50- Home button: `axe button home --udid {UDID}`51- Siri: `axe button siri --udid {UDID}`5253**Verify**54After each action, take a screenshot and check whether the expected change occurred. If something is wrong, note the issue and investigate.5556**Timing controls** — add delays when animations or loading cause flakiness:57- `--pre-delay 0.5` — wait before acting58- `--post-delay 1.0` — wait after acting59- `--duration 0.3` — control gesture speed60</process>6162<gesture_presets>63Available preset gestures (use with `axe gesture {preset} --udid {UDID}`):64- `scroll-up`, `scroll-down`, `scroll-left`, `scroll-right`65- `swipe-from-left-edge`, `swipe-from-right-edge`66- `swipe-from-top-edge`, `swipe-from-bottom-edge`6768For specific screen sizes: `axe gesture swipe-from-left-edge --screen-width 430 --screen-height 932 --udid {UDID}`69</gesture_presets>7071<recording>72Record video of test sessions for evidence or debugging:73- Record MP4: `axe record-video --udid {UDID} --fps 15 --output recording.mp4`74- Lower quality/size: `axe record-video --udid {UDID} --fps 10 --quality 60 --scale 0.5 --output recording.mp4`75- Stream MJPEG: `axe stream-video --udid {UDID} --fps 10 --format mjpeg > stream.mjpeg`76</recording>7778<diagnosing_failures>79When the app is not behaving as expected, fetch simulator logs to diagnose:8081```bash82# Stream logs from the booted simulator (Ctrl+C to stop)83xcrun simctl spawn booted log stream --level debug --predicate 'subsystem == "com.apple.UIKit" OR processImagePath CONTAINS "{APP_NAME}"' 2>&1 | head -2008485# Get recent log entries86xcrun simctl spawn booted log show --last 5m --predicate 'processImagePath CONTAINS "{APP_NAME}"' --style compact8788# Check for crash logs89ls ~/Library/Logs/DiagnosticReports/*{APP_NAME}* 2>/dev/null90```9192Replace `{APP_NAME}` with the app's process name (visible in `describe-ui` output or from `xcrun simctl listapps booted`).9394**If this is a React Native app**, invoke the `debugging-react-native` skill (https://github.com/mikekelly/debugging-react-native) for React Native-specific diagnosis including Metro bundler issues, JS errors, and red box screens.95</diagnosing_failures>9697<gotchas>98- **Labels with special characters fail**: `axe tap --label "Reload (⌘R)"` breaks. Use coordinates from `describe-ui` instead.99- **Tapping input fields may show context menus**: iOS may show "Paste"/"AutoFill" instead of the keyboard. Tap elsewhere to dismiss, then tap the field again or just use `axe type`.100- **Coordinates are in points, not pixels**: Use values from `describe-ui` directly — do not multiply by screen scale.101- **React Native apps need Metro bundler**: If you see "No script URL provided", Metro isn't running. Start it with `npm start` in the app directory.102</gotchas>103104<success_criteria>105Testing is complete when:106- App launched and initial screen verified via screenshot107- Core user flows exercised (navigate, interact, verify outcomes)108- Key interactive elements respond correctly109- No crashes or unhandled errors encountered (or failures diagnosed via logs)110- Findings documented: what worked, what failed, and why111</success_criteria>