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.

expo/expo49 installsMITSynced Aug 25

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
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

← All Testing skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY