--- name: qa-device-management description: > Boot and control iOS Simulators and Android Emulators for QA testing using agent-device CLI. Manage sessions, capture screenshots, launch apps, and control devices across platforms. Invoke when user says "bring up simulators", "boot the device", "take a screenshot", "launch the app", "compare iOS and Android", "test both platforms", "visual parity check", or any task requiring device/simulator lifecycle management. allowed-tools: Bash(agent-device:*) Bash(xcrun:*) Bash(adb:*) Bash(open:*) Bash(find:*) Bash(npx:*) Read --- # qa-device-management Side-by-side iOS Simulator and Android Emulator control using the `agent-device` CLI. Manages the device lifecycle for all QA Automation skills. ## When to Use - Bringing up simulators/emulators for testing - Launching your app on one or both platforms - Capturing baseline or comparison screenshots - Checking device state, app state, or accessibility tree - Managing agent-device sessions across platforms ## Configuration All device settings are in `qa.config.sh`. Set these before using: ```bash # In qa.config.sh or qa.config.local.sh: export APP_BUNDLE_ID="com.yourapp.dev" # Your app's bundle/package ID export SIMULATOR_UDID="auto" # "auto" or specific UDID export SIMULATOR_DEVICE_NAME="iPhone 16 Pro" # For creating simulators export ANDROID_AVD="Pixel_8" # Android AVD name export ANDROID_SERIAL="emulator-5554" # Android serial ``` ## Quick Start — Full Startup Sequence ### Boot iOS Simulator ```bash # Auto-detect a booted simulator, or boot one source .pi/skills/qa-automation/qa.config.sh UDID=$(qa_detect_simulator_udid) # Or boot a specific one xcrun simctl boot "$SIMULATOR_UDID" 2>&1 || true open -a Simulator ``` ### Boot Android Emulator ```bash nohup $EMULATOR_PATH -avd "$ANDROID_AVD" -no-snapshot-load > /tmp/qa-emu.log 2>&1 & # Wait for boot for i in $(seq 1 30); do BOOT=$($ADB_PATH shell getprop sys.boot_completed 2>/dev/null | tr -d '\r') if [ "$BOOT" = "1" ]; then echo "Android emulator booted after ~$((i*2))s" break fi sleep 2 done ``` ### Verify Both Devices ```bash agent-device devices --json ``` ### Launch App on iOS ```bash agent-device open "$APP_BUNDLE_ID" --platform ios --session default ``` ### Launch App on Android ```bash agent-device open "$APP_BUNDLE_ID" --platform android --serial "$ANDROID_SERIAL" --session android ``` ### Capture Baseline Screenshots ```bash agent-device screenshot /tmp/qa-ios-baseline.png --session default agent-device screenshot /tmp/qa-android-baseline.png --session android ``` ## Session Management agent-device binds each session to one platform. Use the correct session flag: | Platform | Session Flag | Example | |----------|-------------|---------| | iOS | `--session default` (or omit) | `agent-device snapshot --session default` | | Android | `--session android` | `agent-device snapshot --session android` | ```bash # List active sessions agent-device session list # Release a session agent-device close --session default ``` ## Common Operations ### Screenshots (Both Platforms) ```bash agent-device screenshot /tmp/qa-ios.png --session default agent-device screenshot /tmp/qa-android.png --session android ``` ### Accessibility Snapshots ```bash agent-device snapshot --session default # iOS agent-device snapshot --session android # Android # With options agent-device snapshot -i --session default # Interactive elements only agent-device snapshot --depth 3 # Limit depth ``` ### Navigate and Interact ```bash # Tap agent-device click 200 400 --session default # Swipe agent-device swipe 200 800 200 200 --session default # Scroll agent-device scroll down --session default # Type agent-device fill @e3 "hello world" --session default ``` ### Go Home / Go Back ```bash agent-device home --session default agent-device back --session android ``` ### Check Foreground App ```bash agent-device appstate --session default agent-device appstate --session android ``` ### Relaunch App (Fresh State) ```bash agent-device open "$APP_BUNDLE_ID" --session default --relaunch ``` ## Building and Installing Your App ### iOS — Expo ```bash cd "$PROJECT_DIR" npx expo run:ios --device "$SIMULATOR_DEVICE_NAME" ``` ### iOS — React Native CLI ```bash cd "$PROJECT_DIR" npx react-native run-ios --simulator "$SIMULATOR_DEVICE_NAME" ``` ### Android — Expo ```bash cd "$PROJECT_DIR" npx expo run:android ``` ### Android — React Native CLI ```bash cd "$PROJECT_DIR" npx react-native run-android ``` ### Check If App Is Installed ```bash # iOS xcrun simctl listapps booted 2>/dev/null | grep "$APP_BUNDLE_ID" # Android $ADB_PATH shell pm list packages | grep "$APP_BUNDLE_ID" ``` ## Shutdown Sequence ```bash # Close agent-device sessions agent-device close --session default agent-device close --session android # Shutdown simulators xcrun simctl shutdown "$SIMULATOR_UDID" $ADB_PATH emu kill ``` ## CDP Connection (for React Native apps) When coordinate-based tapping fails (e.g., full-screen video players intercept touches), use CDP to control navigation directly via the React Native Hermes runtime. ### Prerequisites - Dev server running (e.g., `npx expo start`) - `ws` npm package available ### Discover CDP Endpoints ```bash # List available debug targets curl -s http://localhost:$METRO_PORT/json # Get WebSocket URL (auto-detected by qa.config.sh) source qa.config.sh qa_detect_cdp_ws_url ``` ### Navigate via CDP ```bash source .pi/skills/qa-automation/qa-test-flows/lib/cdp-helpers.sh # Navigate to a screen cdp_navigate "SettingsScreen" # Navigate to a tab cdp_navigate_tab "ProfileScreen" # Get current route cdp_get_route ``` ## Troubleshooting | Problem | Solution | |---------|----------| | "No device found" | Verify simulator is booted: `xcrun simctl list devices \| grep Booted` | | Session bound to wrong platform | Use `--session android` for Android, close session and rebind | | Simulator already booted (error 149) | Safe to ignore — simulator is already running | | App not installed | Build and install: `npx expo run:ios` or `npx expo run:android` | | agent-device click hangs | Wrap with timeout: `timeout 5 agent-device click 100 200` | | CDP "Connection refused" | Ensure dev server is running: `curl http://localhost:$METRO_PORT/status` |