Skip to main content
@qawolf/flows/android defines Android flows and advanced device controls. QA Wolf runs Android flows on ephemeral emulators by default. A fresh one is provisioned for each run and discarded when it finishes, so nothing carries over from a previous run. Because emulators are created on demand, you don’t reserve or configure devices yourself: choose a target and QA Wolf allocates an emulator for it. QA Wolf can also run Android flows on real phones. See Real phones.

Primary exports

  • flow(...)
  • launch(...)
  • device
  • expect
  • testContextDependencies
It also exports Android-specific target, launch, device, callback context, and flow definition types. Example:

Flow callback context

All Android flow callbacks receive:
  • inputs
  • setOutput(...)
  • test(...)
Launch-enabled Android flows also receive driver.
test(...) can be omitted for simple flows where grouping steps into named sub-steps doesn’t add value. For most flows, wrapping steps in test(...) is recommended — the label appears in your results and makes failures easier to locate.

testContextDependencies

testContextDependencies is exported for runner and tooling integration. Flow authors should usually use the public callback parameters above instead of depending on the raw runner dependency list.

Target model

The target input model is:
Pass either:
  • a target directly for the common path
  • { target, launch } when startup behavior should be part of the flow
Example:

Real phones

Contact your QA Wolf representative to enable real Android phones for your team.
QA Wolf runs Android flows on real Samsung Galaxy A37 phones running Android 16. Target one with the Android - Samsung Galaxy A37 (Android 16) preset. A real-phone target has no | Emulator qualifier in its name. Example:
Real phones are shared across customers. QA Wolf resets a phone between runs: it uninstalls the apps the previous run left, clears Chrome, empties shared storage, and re-applies the device settings.

Dedicated phones

QA Wolf can also dedicate real phones to your team. No preset targets a dedicated phone. Pass a target object with targetDevices set to Team Dedicated Device instead. The default, Any Device, uses the shared phones. androidVersion takes the API level, so Android 16 is "36". Example:
A dedicated phone gets the same reset between runs as a shared one. Emulators are always shared, so QA Wolf rejects a target that combines Team Dedicated Device with an emulator model.

Device controls on real phones

On a real phone, only device.adb(...) works. The other device methods drive the emulator, and Android Device Controls marks each of them Emulator only.

App builds for real phones

Real phones use the arm64-v8a architecture. Include arm64-v8a native libraries in any build you run on them: an APK that ships native libraries only for x86_64 doesn’t install.

flow(...)

Use flow(...) for Android authoring.
  • without launch, the callback receives inputs, setOutput(...), and test(...)
  • with launch: true, the flow calls launch() with default Android startup
  • with launch: <options>, the flow calls launch(options)
  • when launch is enabled, the callback also receives driver
Example:

launch(...)

Starts Android automation for the active flow. Returns:
This API is only available while a flow is running. Example:

Launch shape

Example:

Launch defaults

The implementation applies these defaults:
  • when app is omitted, launch falls back to the runner-provided executable input path and then to installed-app startup through appPackage
  • autoGrantPermissions defaults to true
  • noReset defaults to false
Example:

Supported app formats

QA Wolf installs your app from either a local path or a URL, in either the .apk or .aab format.
QA Wolf writes the version of the installed build to the run log, so you can confirm which build a run tested against. QA Wolf only fetches a URL when its path ends in .apk or .aab. A query string does not change that, so a signed or expiring download link works as long as the path keeps the extension. QA Wolf passes anything else, such as a share page or a download endpoint that names the file elsewhere, to the driver untouched. You can also install an app yourself over adb, which skips everything above:
Prefer handing QA Wolf the .apk or .aab. Installing over adb means you own everything that comes with it: choosing the right split APKs for the device, reading the manifest for the launcher activity, and sizing the transfer. Passing app gets all of that handled for you.

App resolution

When your CI pipeline reports the deploy, it carries the uploaded build’s path as RUN_INPUT_PATH. Omit app in your launch call and QA Wolf will use that path automatically — you only need to provide the appPackage. See Mobile build testing. When app is provided, the resolution order is:
  1. app.path
  2. app.env
  3. app.url
When app is omitted, launch falls back to RUN_INPUT_PATH. Every path must be absolute. An uploaded build is mounted at /home/wolf/run-inputs-executables/<filename>; a relative path is passed to the device unchanged and will not find the build. Explicit app source examples:
RUN_INPUT_PATH fallback example:
If app is present but does not resolve to a value, launch does not fall back to RUN_INPUT_PATH.

Advanced Appium capabilities

The named launch options above cover the most common settings. For anything else, use the capabilities escape hatch: its entries are spread into the underlying webdriver.io remote capabilities and passed straight to the Android driver. startAndroid is a thin wrapper around webdriver.io’s remote, so capabilities that QA Wolf does not set itself are forwarded as-is. See the Appium references for the full list of available keys:
Named options take precedence over capabilities for the same key. In particular, autoGrantPermissions and noReset are always applied (using their defaults when omitted), so configure those through the named options rather than capabilities.

Migrating from wdio.startAndroid

Older flows obtained a wdio handle from the test context and called startAndroid directly. With the flow API, pass the same configuration through the flow’s launch options instead — map the settings that have a named option, and route the rest through capabilities. The driver you receive is the same webdriver.io Browser handle, so there is no separate “raw” driver to obtain.
app: { env: "ANDROID_PATH" } reads the path from the environment variable named ANDROID_PATH, replacing the raw "appium:app": process.env.ANDROID_PATH form.

device

device is a runtime proxy over the Android emulator API. Use it for device-level operations — such as setting location, simulating sensors, or managing device state — that sit outside app UI interactions. Use driver for interacting with the app itself. See Android Device Controls for the full method list. On a real phone, only device.adb(...) works.

expect

The exported expect is the assertion helper for Android flows, backed by expect-webdriverio. All WebdriverIO matchers are available — including auto-retrying element matchers like toBeDisplayed, toExist, toHaveText, and toHaveAttribute. See the expect-webdriverio matchers reference for the full list. Always import expect from @qawolf/flows/android rather than from expect-webdriverio directly, so that QA Wolf’s defaults (timeout, toHaveScreenshot) stay in effect. Example:
For visual regression assertions with expect(driver).toHaveScreenshot(...), see Native mobile screenshots.
Last modified on October 7, 2026