Mobile Testing
The platform runs Appium-based mobile UI tests against four execution tiers. Pick the one that fits your team's constraints — vendor lock-in, infrastructure ownership, iOS coverage, cost.
The four tiers
| Tier | Where the device lives | Best for | Cost |
|---|---|---|---|
| T1 — Local emulator | Developer's macOS host | Dev loop, demos | $0 |
| T2 — Self-hosted in your K8s | Customer-owned bare-metal or KVM-enabled cloud nodes | Production CI, on-prem, "no vendor lock" | infra + ops |
| T3 — Self-hosted real devices | OpenSTF / DeviceFarmer in your device lab | Hardware-specific bugs, full sensor access | hardware + ops |
| T4 — Hosted device farms | BrowserStack / Sauce Labs / AWS Device Farm | iOS without owning Macs, on-demand scale | per-minute |
You can mix tiers. Common shapes:
- Dev → T1, CI → T2, release matrix → T4 — most popular split
- All T2 — strongest "data stays in our infra" posture
- All T4 — fastest to set up, no ops burden
How a mobile app is configured
Every mobile app on the platform carries a cloud_provider value:
| Value | Routes to |
|---|---|
NONE | T1 (local Appium) |
SELF_HOSTED | T2 (your K8s registry — picks an emulator pod by capability match) |
BROWSERSTACK | T4 BrowserStack App Automate |
SAUCELABS | T4 Sauce Labs Real Device Cloud |
AWS_DEVICE_FARM | T4 AWS Device Farm (async; coming soon) |
The agent reads this field at job time and dispatches to the right driver.
What's the same across tiers
- YAML test definition — write once, run anywhere. See yaml-format.
- Test data — credentials, app binaries, environment variables work the same way.
- Result reporting — pass/fail/screenshots flow back into the same Job History view.
- Credential vault — vendor keys live once in your environment vault, referenced by tag. See credentials.
Before you crawl: static inspection
Before booting a device, run static inspection on an uploaded APK/IPA — it
extracts a screen map + element inventory with no device (seconds, backend-side), and tells you
whether a live crawl is even needed via a recommendation field. Reliable for native apps; it
honestly declines for React Native / Flutter and points you at the live device inspection.
After you crawl: what you get back
A crawl returns the same element shape for Android and iOS, so a tool written against one platform works unchanged against the other — see Crawl element schema.
It also grades how testable the app is. Controls that can only be found by their text or their position on screen are flagged, with a plain suggestion for the developer, because those are exactly the tests that break on the next redesign. That verdict is the part only your team can act on.
What's different across tiers
| Concern | T1 Local | T2 Self-hosted | T4 Vendor |
|---|---|---|---|
| iOS support | Simulator only (macOS) | Android only (KVM) | Yes (real devices) |
| Real device support | Via USB | Via OpenSTF (T3) | Yes |
| APK upload | Local file | Local file | Auto-uploaded to vendor |
| Parallel runs | 1 | N pods | Up to your concurrency tier |
| Network access | Localhost | Cluster-internal | Vendor-managed |
| Setup time | 30 min | 1-2 days infra | 15 min (signup) |
Quick start
The fastest way to see a passing mobile test:
- Set up Appium locally — see Local emulator for the macOS native path
- Create a mobile app — pick
cloud_provider = NONE, upload an APK - Write a YAML test — three steps: tap, type, assert
- Run — agent connects to local Appium and executes
Once that's green, switch the same test to BrowserStack by changing cloud_provider and pointing at a vault credential. No YAML changes. See device-farms.
Architecture diagram
Platform Backend
┌────────────────────┐
│ Application registry│
│ (Mobile apps) │
│ /mobile-config │
└─────────┬──────────┘
│ job created
▼
mobile-test-agent (JAR)
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ T1 Local │ │ T2 Self │ │ T4 Vendor│
│ Appium │ │ hosted │ │ farm │
│ on macOS │ │ pods │ │ APIs │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
Emulator on Emulator in BrowserStack /
developer Mac K8s pod (KVM) Sauce Labs cloud
When to use which tier
Use T1 when: you're a developer iterating on tests, or running a demo on your laptop.
Use T2 when: you self-host the platform, you have bare-metal or KVM-enabled K8s capacity, and you want zero vendor data exposure. Best balance of cost + control for sustained CI usage.
Use T4 when: you need iOS coverage (without owning Macs), real-device behavior (sensors, biometrics, OEM-specific bugs), or burst capacity beyond what your own infra provides.
Mix tiers when: your workflow has different stages with different needs (dev loop = T1, CI = T2, release matrix on real devices = T4). The platform doesn't care — same YAML, same Job History, different cloud_provider per app.
Next steps
- Local emulator setup — macOS Appium + Android Emulator from scratch
- Device farms — BrowserStack + Sauce Labs in 15 minutes
- Self-hosted K8s pods — your own emulator fleet
- Credentials — vault pattern for vendor keys
- Crawl element schema — what a crawl returns, one shape for both platforms, and the testability advisory