android-e2e-testing
Test Expo Router features on Android emulators using ADB. Use after implementing native Android features or when verifying UI behavior on Android.
Works with
--- name: android-e2e-testing description: Test Expo Router features on Android emulators using ADB. Use after implementing native Android features or when verifying UI behavior on Android. license: MIT --- # Android E2E Testing for Expo Router Use `adb` to manually test Expo Router screens and components on Android emulators. ## When to Use - After implementing or modifying native Android UI components (toolbars, tabs, menus) - When verifying Jetpack Compose components (`@expo/ui/jetpack-compose`) - When running the `native-navigation` or other E2E apps on Android - Before opening a PR that touches Android-specific behavior ## Prerequisites An Android emulator must be running. Prefer **Pixel emulators** over tablet ones for standard phone-sized testing. ```bash # Verify emulator is connected adb devices # Check which emulator is running adb -s DEVICE_ID emu avd name # Check screen resolution (important for coordinate calculations) adb -s DEVICE_ID shell wm size ``` ## Step 1: Build and Launch ### Router E2E apps Package name: `dev.expo.routere2e` Each app in `apps/router-e2e/__e2e__/` has a corresponding `yarn android:<name>` script. Check `apps/router-e2e/package.json` for available scripts. ```bash cd apps/router-e2e yarn android:[APP_NAME] # e.g. yarn android:native-navigation ``` If the app is already built, relaunch it: ```bash adb shell monkey -p dev.expo.routere2e -c android.intent.category.LAUNCHER 1 ``` To find the package name of any installed app: ```bash adb shell pm list packages | grep -i <keyword> ``` ## Step 2: Navigate Using UI Dump **CRITICAL: Always use `uiautomator dump` for element coordinates.** Screenshot pixel coordinates have display scaling factors that make them unreliable for `adb shell input tap`. The UI dump provides actual device coordinates. ### Dump the view hierarchy ```bash adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml ``` This returns XML with every UI element including: - `text` — displayed text - `content-desc` — accessibility description (useful for icon buttons) - `bounds` — position as `[left,top][right,bottom]` - `clickable` — whether the element responds to taps - `class` — Android view class ### Find and tap an element 1. Search the XML for your target element by `text` or `content-desc` 2. Extract the `bounds` attribute: `bounds="[left,top][right,bottom]"` 3. Calculate center: `x = (left + right) / 2`, `y = (top + bottom) / 2` 4. Tap: ```bash adb shell input tap <x> <y> ``` **Example:** For `bounds="[367,498][714,633]"`: - x = (367 + 714) / 2 = 540 - y = (498 + 633) / 2 = 565 ```bash adb shell input tap 540 565 ``` ### Wait for navigation to settle After tapping a navigation element, wait before verifying: ```bash sleep 1 ``` For slow transitions or heavy screens, use `sleep 2`. ## Step 3: Interact ### Tap items ```bash adb shell input tap <x> <y> ``` ### Scroll ```bash # Scroll down adb shell input swipe 540 1500 540 500 300 # Scroll up adb shell input swipe 540 500 540 1500 300 # Scroll further (larger distance) adb shell input swipe 540 1500 540 200 500 ``` ### Type text ```bash adb shell input text "hello%sworld" # %s = space ``` ### Press hardware buttons ```bash adb shell input keyevent 4 # Back adb shell input keyevent 3 # Home adb shell input keyevent 82 # Menu / React Native dev menu ``` ### Long press ```bash adb shell input swipe <x> <y> <x> <y> 1000 ``` ## Step 4: Verify ### Visual verification via screenshot ```bash adb shell screencap -p /sdcard/screenshot.png && adb pull /sdcard/screenshot.png /tmp/screenshot.png ``` Then use the `Read` tool to view `/tmp/screenshot.png`. Screenshots are useful for: - Confirming visual appearance (colors, layout, styling) - Verifying toolbar/tab positioning - Checking selection states and visual feedback **Note:** Use screenshots for *visual* verification only. For element positions and tapping, always use `uiautomator dump`. ### Programmatic verification via UI dump ```bash adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml ``` Search the XML for expected content: - Verify text content appears - Check `content-desc` for accessibility labels - Confirm element presence after navigation - Verify selection states (look for checkmarks, content-desc changes) ### Check for errors ```bash # React Native JS errors adb logcat -d -s ReactNativeJS:E | tail -20 # Crash logs adb logcat -b crash -d # All recent errors adb logcat -d *:E | tail -30 ``` ## Step 5: Report Results After testing, summarize results in a table: | Test | Result | |------|--------| | Navigation to screen | PASS/FAIL | | Component renders correctly | PASS/FAIL | | Interaction works | PASS/FAIL | | No JS errors in logcat | PASS/FAIL | Include details for any failures: what was expected vs what happened, relevant logcat output, and screenshots. Preferably attach screenshots for features you tested. ## Testing Jetpack Compose Components Components from `@expo/ui/jetpack-compose` (like `HorizontalFloatingToolbar`, `IconButton`, `Host`) render as Compose views inside React Native. In UI dumps they appear as: - `androidx.compose.ui.platform.ComposeView` — the Compose container - `android.widget.HorizontalScrollView` — inside toolbar layouts - `android.widget.Button` — Compose buttons - `android.view.View` with `content-desc` — icon buttons with accessibility labels When testing Compose components: 1. Look for `content-desc` attributes to identify buttons (e.g., `content-desc="Clear selection"`) 2. The `ComposeView` wrapper may have different bounds than the inner interactive elements 3. Tap the interactive element's bounds, not the container's ## Troubleshooting ### uiautomator dump fails or returns empty This can happen during animations or transitions. Wait and retry: ```bash sleep 2 && adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml ``` ### Tap doesn't register - Recalculate coordinates from a fresh UI dump — the layout may have shifted - Ensure you're tapping a `clickable="true"` element - Try tapping the parent element if the child isn't clickable ### App navigated to wrong screen or went to home - The Back button (`keyevent 4`) can exit the app entirely if on the root screen - Use `monkey` command to relaunch: `adb shell monkey -p dev.expo.routere2e -c android.intent.category.LAUNCHER 1` - Wait 2 seconds after launch before interacting ### Metro bundler not connecting ```bash adb reverse tcp:8081 tcp:8081 ``` ### App crashes on launch ```bash # Check crash buffer adb logcat -b crash -d # Look for fatal exceptions adb logcat -d | grep -A 10 "FATAL EXCEPTION" ``` ### Reload the app ```bash # Open React Native dev menu and tap Reload adb shell input keyevent 82 # Or force-stop and relaunch adb shell am force-stop dev.expo.routere2e && adb shell monkey -p dev.expo.routere2e -c android.intent.category.LAUNCHER 1 ``` ## Disable Animations (Recommended for Testing) Disabling animations prevents flaky UI dumps and makes testing more reliable: ```bash adb shell settings put global window_animation_scale 0 adb shell settings put global transition_animation_scale 0 adb shell settings put global animator_duration_scale 0 ``` Re-enable when done: ```bash adb shell settings put global window_animation_scale 1 adb shell settings put global transition_animation_scale 1 adb shell settings put global animator_duration_scale 1 ``` ## Complete Example: Testing a Toolbar Screen ```bash # 1. Launch app adb shell monkey -p dev.expo.routere2e -c android.intent.category.LAUNCHER 1 sleep 2 # 2. Dump UI to find navigation button adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml # Find: content-desc="Android Toolbar" bounds="[367,498][714,633]" # Center: (540, 565) # 3. Navigate to screen adb shell input tap 540 565 sleep 1 # 4. Take screenshot to verify visual appearance adb shell screencap -p /sdcard/screenshot.png && adb pull /sdcard/screenshot.png /tmp/screenshot.png # 5. Dump UI to find toolbar buttons adb shell uiautomator dump /sdcard/ui.xml && adb shell cat /sdcard/ui.xml # Find buttons by content-desc: "Clear selection", "Select all", "Delete", "Add" # 6. Test toolbar interactions adb shell input tap 457 2233 # "Select all" button center sleep 1 # 7. Verify state changed adb shell screencap -p /sdcard/screenshot.png && adb pull /sdcard/screenshot.png /tmp/screenshot.png # 8. Check for errors adb logcat -d -s ReactNativeJS:E | tail -20 ```
More Testing skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
setup-pre-commit
mattpocock/skills
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
agent-browser
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

