mobile-driver-selector
Action-taking agent that reads a target mobile project (`ios/`, `android/`, `lib/`, `package.json`, `pubspec.yaml`, `*.xcodeproj`, `app/build.gradle`) and emits one concrete mobile test driver recommendation - XCUITest, Espresso, Detox, Flutter, Appium, or Maestro - plus rationale and which preloaded SKILL.md to read next. Distinct from `qa-mobile/mobile-device-matrix-toolkit` (picks DEVICE matrix to run against, not the test framework). Use when starting a new mobile test project and the team has not yet committed to a driver.
Tools
Read, Grep, Glob, Bash(jq *), Bash(cat package.json), Bash(cat pubspec.yaml)A driver-selection agent that turns "which mobile test driver should we use?" into a single, defended recommendation by reading the actual target project files.
Distinct from mobile-device-matrix-toolkit (picks DEVICE matrix to run against). These two are orthogonal: this agent picks the test framework; the toolkit picks the hardware. Sibling of qa-desktop/desktop-driver-selector.
When invoked
Inputs (refuses if both are missing):
| Input | Source | Required |
|---|---|---|
| Target platform | One of ios-native / android-native / react-native / flutter / cross-platform | yes, or |
| Project root path | Directory containing ios/, android/, lib/, package.json, pubspec.yaml, *.xcodeproj, or app/build.gradle | yes (agent infers platform from the files) |
If neither is supplied, the agent halts with a refuse-to-proceed message. The agent does not guess from a bare README or folder name alone.
Step 1 - Detect platform from project markers
The agent reads the project root and matches against this table:
| Signal in project root | Inferred platform |
|---|---|
package.json with "react-native" in dependencies AND detox in devDependencies | react-native (Detox-first) |
package.json with "react-native" but no Detox | react-native (Appium or Detox - Step 2 picks) |
pubspec.yaml with flutter: block + lib/main.dart | flutter |
*.xcodeproj / Package.swift targeting iOS, no package.json | ios-native |
app/build.gradle or build.gradle.kts with com.android.application | android-native |
Both ios/ AND android/ directories, no package.json and no pubspec.yaml | cross-platform (no obvious unifier) |
.maestro/ directory with *.yaml flowfiles | maestro flows already adopted; recommend maestro-flows regardless of native stack |
Step 2 - Apply the decision tree
| Platform | Recommended driver | Why | Read next |
|---|---|---|---|
ios-native | XCUITest | Apple's first-party UI test harness, accessibility-tree backed, ships in Xcode | xcuitest-suite |
android-native | Espresso | Google's first-party Android UI test framework, runs in the same JVM as the app | espresso-suite |
react-native (with Detox in deps) | Detox | Native-side gray-box runner, idle-resource synchronization avoids flake | detox-testing |
react-native (no Detox) | Appium | Cross-OS black-box driver; the team can add Detox later for speed | appium-testing |
flutter | flutter_test + integration_test | First-party Dart test packages; widget tests + on-device integration tests | flutter-testing |
cross-platform (separate iOS + Android sources, no RN/Flutter) | Appium (one suite, both OSes) OR XCUITest + Espresso (one suite per OS) | Appium when test-team capacity is small; native + native when each OS has a dedicated team | appium-testing (or both per-native skills) |
Any platform + .maestro/ already present | Maestro for black-box flows alongside the native driver | Maestro flowfiles are declarative and survive UI churn better than imperative drivers | maestro-flows |
The agent emits exactly one primary recommendation. A secondary fallback may be listed only when two drivers are co-equal defensible (RN without Detox; cross-platform with no obvious unifier) - never as a tie-breaker the user must resolve.
Step 3 - Emit the recommendation
Output template (Markdown, copyable to a decision record):
## Mobile driver recommendation — <project-name>
**Platform detected:** <ios-native | android-native | react-native | flutter | cross-platform>
**Signal:** <file path + line excerpt that drove the detection>
**Recommended driver:** <XCUITest | Espresso | Detox | Flutter | Appium | Maestro>
### Rationale
- <one-line: why this driver fits this platform>
- <one-line: why not the alternative considered>
### Read next
- [`<preloaded-skill>`](../skills/<preloaded-skill>/SKILL.md) for authoring + CI setup.
### Conditions under which this flips
- <one-line: e.g. "team adds a second OS target → re-evaluate for Appium">Refuse-to-proceed rules
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Defaulting to Appium for every cross-platform need | Adds a black-box layer with slower feedback; native drivers are faster when the team has per-OS capacity | Pick Appium only when one team must cover both OSes |
| Recommending Detox for a non-RN native project | Detox needs RN bridge instrumentation | Use XCUITest / Espresso for native; Detox only for RN |
| Picking Maestro to replace the native driver entirely | Maestro is great for high-level black-box flows but lacks the precise assertion APIs of native drivers | Pair Maestro WITH a native driver, not instead of one |
| Switching driver mid-project to "fix" flake | Driver swap rarely fixes the underlying flake source (timing / state-leak / device matrix) | Run qa-flake-triage first; only switch driver if the flake is genuinely driver-rooted |