Mobile testing
Run plain-English tests on Android and iOS apps through Appium, on emulators, simulators and phones, here or on a remote.
Mobile tests use the same plain-English steps as web tests. agent-qa drives the app through Appium, with UiAutomator2 on Android and XCUITest on iOS, on a device on this machine or on a remote one.
Set up Android testing
Set up agent-qa to test this project's Android app on a local emulator or device, and run one test. Read https://vostride.com/docs/agent-qa/guides/mobile-testing.md first. 1. Check for the Android SDK (ANDROID_HOME or ANDROID_SDK_ROOT) and an emulator or a connected device. Tell me if either is missing; do not install Android Studio yourself. 2. Install Appium in the project, then the Android driver with npx agent-qa install-mobile-drivers --android. 3. Run npx agent-qa devices to see the phones, emulators and AVDs this machine has. Add a device under registry.devices in agent-qa.config.yaml with platform: android and a model it lists: the model a phone reports, or an emulator's AVD name or device profile. Add os, quoted, only to pin a version. Never create agent-qa.local.yaml; agent-qa no longer reads it. 4. Add an Android target with the app's appPackage and appActivity, app.path when a debug build is available, and device set to that device's name. 5. Run npx agent-qa doctor and fix the mobile checks it reports. 6. Write a short test for the app's first screen, and run it. It runs on the target's device. Report the files you changed, the doctor results, and the run's verdict.
What you need
For devices on this machine:
-
Appium. agent-qa does not bundle it. Install it in the project, or globally:
npm install -D appium -
Drivers. Install them through agent-qa:
npx agent-qa install-mobile-drivers --androidUse
--iosor--allfor iOS.--updateupdates installed drivers. -
Android: the Android SDK, with
ANDROID_HOMEorANDROID_SDK_ROOTset, and an emulator or a connected phone. -
iOS: a Mac with Xcode and a simulator.
A device on a remote Appium server or on BrowserStack needs none of these here. npx agent-qa doctor checks what your devices need, and skips the local tools when every device is remote. See doctor's rows.
Set up the project
npx agent-qa@latest init --platform androidUse ios, or a list such as web,android or web,ios, as needed. A mobile project starts with an example-android or example-ios target, a commented device example and no example tests, because there is no shared app to test.
Describe the app
The target holds the app's IDs and builds, and names the device its tests use:
registry:
targets:
shop-android:
platform: android
appPackage: com.example.shop
appActivity: .MainActivity
device: pixel
app:
path: builds/shop-debug.apk| Key | Meaning |
|---|---|
appPackage, appActivity | The Android app. |
bundleId | The iOS app, with platform: ios. |
device | The device this target's tests run on, unless a suite or test picks another. |
app.path | A build installed on a device on this machine before the test, relative to the config file. |
app.ref | What a remote server installs: an https URL or the server's own reference, such as a BrowserStack bs:// ID. |
Describe the device
A device is described by what people call it. agent-qa finds it on this machine when a test needs it:
registry:
devices:
pixel:
platform: android
model: Pixel 8
iphone:
platform: ios
model: iPhone 16
os: "18.4"| Key | Meaning |
|---|---|
platform | android or ios. |
model | What the device is called: Pixel 8, SM-S921B, iPhone 16. |
os | The Android or iOS version, in quotes: os: "17.10". YAML would read an unquoted 17.10 as the number 17.1, so a number is refused. |
id | An Android serial or a simulator UDID. Set it only when two identical devices are attached at once. |
remote | A remote the device runs on: an Appium server or a plugin. Without it, the device is on this machine. |
capabilities | Appium capabilities for this device, such as appium:automationName or a mobile browserName. |
App IDs belong on the target, never on the device. Everything about a device lives in agent-qa.config.yaml, so every machine and CI job reads the same description.
How a device is found here
- iOS: a simulator whose name is the
model, on theoswhen one is set. A plugged-in iPhone is never used. - Android: a phone by the model it reports, as
adb devices -lprints it (model:SM_S921B), or an emulator or AVD by its AVD name or its device profile. - Case does not matter, and spaces,
_and-count as the same.os: "18"matches 18.2. - When several match, the newest OS wins, then a running one. If that still leaves more than one, the test is refused and
idpicks one. - With no
model, the one running device of that platform is used. - A matching simulator or AVD that is not running is started. agent-qa never creates one.
- When nothing matches, the test is refused before it starts, with a line listing what this machine has.
npx agent-qa devices shows where each device would run and what this machine has, so you can copy the model to write:
$ npx agent-qa devices
pixel here: Pixel_8_API_35 emulator emulator-5554
iphone not here: wants an iPhone 16 simulator on iOS 18.4
galaxy-farm remote farm (appium https://farm.example.com:443)
Attached: none
Emulators: Pixel_8_API_35 (Pixel 8, Android 15, running emulator-5554)
Simulators: iPhone 16 Pro (18.4), iPhone 16e (18.4)npx agent-qa devices list --json prints the same as JSON.
Choose the device
A test runs on --device when you pass it, else the device in its own use, else its target's device:
use:
device: pixelnpx agent-qa run tests/mobile/sign-in.yaml --device pixel- A suite runs on one device:
--device, else thedevicein the suite'suse, else the one device its tests agree on. Tests that disagree are refused before the suite starts. devicegoes in a suite's or test'suse, or on the target, never in the config'suse.--devicepicks devices on this machine only, and refuses a device with aremote. To send a test to a remote device, name it in the suite's or test'suse, or on the target.
Choose the app state
use.mobile.appState decides whether each session starts fresh:
preservekeeps the app's data between sessions, so a signed-in user stays signed in;resetstarts from a clean install state.
A native mobile app target needs it, and init writes preserve for Android and iOS projects.
Write the test
test-id: t_mint-river-glow-salt-cove-dune-fern-harp-lake-moss
name: Sign in on Android
target: shop-android
steps:
- Tap Sign in.
- Enter email {{env:TEST_EMAIL}} and password {{secret:TEST_PASSWORD}}, then submit.
- Verify the home screen greets the user by name.The test runs on the target's device. A step can also run an Appium command directly, such as {{appium: mobile: pressKey, keycode: 4}}.
Capabilities
A device's capabilities are merged after agent-qa's own and after the remote's, key by key, and null removes a key. A key carries a prefix such as appium: unless it is a W3C one such as platformName or browserName:
registry:
devices:
pixel-chrome:
platform: android
model: Pixel 8
capabilities:
browserName: Chrome
appium:automationName: UiAutomator2- A capability that contradicts the device or its target is refused before the session opens, with one line naming both places: for example
appium:deviceNameagainstmodel,appium:appPackageagainst the target, orappium:noResetagainstuse.mobile.appState. - Write every credential as a quoted
{{secret:NAME}}reference.validaterefuses a literal under a capability name that holds a credential word, at any depth.appium:keystorePath,appium:keyAliasandappium:sendKeyStrategyare settings, not credentials;appium:keystorePasswordandappium:keyPasswordare credentials. - Secrets in a device's capabilities or a target's
app.refare used only to connect to the server. Steps, expected values, target URLs and hooks cannot use them.
Appium on this machine
For a device on this machine, agent-qa uses the dashboard's Appium when the dashboard runs one, or starts its own on port 4723. To use an Appium server you run yourself on this machine, set AGENT_QA_APPIUM_URL. It must point at this machine; list any other server under registry.remotes instead.
Remote devices
A device with a remote runs on that remote, and agent-qa starts no Appium for it:
- An Appium server you or your team run, listed with
protocol: appium. The server picks the device frommodelandos, and installsapp.ref. See Remote browsers and devices. - BrowserStack's real devices, through the BrowserStack plugin, which also uploads
app.pathfor you.
plugins:
- name: browserstack
package: "@vostride/agent-qa-plugin-browserstack"
options:
username: "{{secret:BROWSERSTACK_USERNAME}}"
accessKey: "{{secret:BROWSERSTACK_ACCESS_KEY}}"
registry:
remotes:
- name: browserstack-devices
plugin: browserstack
devices:
bs-pixel:
platform: android
remote: browserstack-devices
model: Google Pixel 9
os: "15"The run page names where each mobile test ran: this machine, or the remote's server, Appium version and device type.
Good to know
- Android runs record a video of the session. iOS runs do not.
- Saved logins are web only. On mobile,
appState: preservekeeps a signed-in session. - Android emulators and phones, and iOS simulators, are covered by agent-qa's own tests. Real iPhones behind a remote server work through capabilities, but agent-qa's tests do not cover them.
agent-qa.local.yamlis no longer read, and a leftover one stops every command that loads the config. See v0.2.x to v0.3.x.