Mobile Test YAML
Mobile tests use the same YAML shape as UI tests, with mobile-specific actions and selectors. Same steps list, same {{variable}} substitution rules, same assertion patterns.
Minimal example
steps:
- action: tap
selector: accessibility:test-Username
- action: type
selector: accessibility:test-Username
value: standard_user
- action: tap
selector: accessibility:test-Password
- action: type
selector: accessibility:test-Password
value: secret_sauce
- action: tap
selector: accessibility:test-LOGIN
- action: assert_visible
selector: accessibility:test-PRODUCTS
Selectors
Mobile uses Appium's selector syntax — same as Appium docs.
| Prefix | Means | Example |
|---|---|---|
accessibility: | Accessibility ID (preferred) | accessibility:test-Username |
id: | Native resource id (Android) / accessibility id (iOS) | id:com.example:id/username |
xpath: | XPath | xpath://*[@text='Login'] |
class: | Class name | class:android.widget.Button |
predicate: | iOS NSPredicate | predicate:label == 'Login' |
Always prefer accessibility IDs — they're stable across UI redesigns and work the same on Android + iOS when developers tag elements correctly.
Actions
| Action | What it does | Required fields |
|---|---|---|
tap | Tap the element | selector |
type | Type text into a field (tap first if not focused) | selector, value |
swipe | Swipe gesture | direction (up/down/left/right) |
long_press | Press-and-hold | selector, duration (ms, default 1000) |
wait | Pause for a fixed duration | duration (ms) |
wait_for | Wait until element appears (with timeout) | selector, timeout (ms, default 10000) |
back | Android back button / iOS swipe-back | — |
home | Send app to background | — |
assert_visible | Fail if element not on screen | selector |
assert_text | Assert element's text matches | selector, expectedText |
assert_not_visible | Fail if element IS on screen | selector |
screenshot | Capture screen (auto-attached to result) | optional name |
scroll_to | Scroll until element is visible | selector |
clear | Clear a text field | selector |
value vs expectedText
Consistent with UI testing:
value— data for input actions (type,select)expectedText— assertion text for validation actions (assert_text)
assert_text uses contains matching (not equals). For exact match, use assert_text_equals (if available) or scope the selector tighter.
Direction values for swipe
up, down, left, right. Optionally percent (0-100, default 75) controls how much of the screen to swipe.
- action: swipe
direction: down
percent: 50
Variables
Same {{variable}} and ${variable} syntax as the rest of the platform (powered by Apache Commons Text StringSubstitutor).
steps:
- action: type
selector: accessibility:test-Username
value: "{{username}}"
- action: type
selector: accessibility:test-Password
value: "{{password}}"
Values come from the environment's auth config or per-test variables. Never hardcode credentials in the YAML — see Credentials.
Capabilities
The platform builds the Appium capability dict from the mobile-app's config + the device tier. You can extend it via:
Per-app extra capabilities
In the mobile app's config (UI: Mobile Apps → Edit → Appium Capabilities):
{
"appium:autoGrantPermissions": true,
"appium:noReset": false,
"appium:newCommandTimeout": 120
}
Merged on top of platform defaults.
Vendor-specific options
For BrowserStack/Sauce Labs, the platform builds bstack:options / sauce:options automatically from credentials + cloud_config. You can override individual keys via:
{
"bstackOptions": {
"debug": true,
"networkLogs": false,
"buildName": "release-v3.2"
}
}
These get nested under bstack:options in the final capability dict.
Common patterns
Login flow
steps:
- action: type
selector: accessibility:username-field
value: "{{username}}"
- action: type
selector: accessibility:password-field
value: "{{password}}"
- action: tap
selector: accessibility:login-button
- action: wait_for
selector: accessibility:home-screen
timeout: 15000
Scroll-and-find
steps:
- action: scroll_to
selector: accessibility:settings-link
- action: tap
selector: accessibility:settings-link
Form input with validation
steps:
- action: clear
selector: accessibility:email-field
- action: type
selector: accessibility:email-field
value: "invalid"
- action: tap
selector: accessibility:submit-button
- action: assert_visible
selector: accessibility:email-error
- action: assert_text
selector: accessibility:email-error
expectedText: "valid email"
What's different from UI testing
| UI tests | Mobile tests | |
|---|---|---|
| Engine | Playwright / Selenium / HtmlUnit | Appium (UiAutomator2 / XCUITest) |
| Selector syntax | CSS / XPath | accessibility: / id: / xpath: (Appium-style) |
home / back actions | N/A | Native nav |
swipe | rare | common |
| App context | URL-based | Package or pre-installed |
Element discovery
Use Inspect Elements on the mobile app's detail page to crawl screens and capture available accessibility IDs. Saves accidental selector drift when the app's resource IDs change.
Tips
- Lean on accessibility IDs — they survive UI redesigns.
- Use
wait_foraggressively — mobile UIs animate, andtapon an off-screen element fails.wait_formakes tests stable. - Keep tests short — < 20 steps per test. Long tests are harder to debug.
- Tag step results with screenshots — adds
action: screenshotafter critical state transitions. Auto-attached to the run result for triage.
Related
- Local emulator — set up Appium locally to develop tests
- Device farms — run the same YAML on real BrowserStack devices
- Credentials —
{{username}}/{{password}}come from the vault