zeno-mobile-runner 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/CHANGELOG.md +497 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/FEATURES.md +111 -0
  4. package/LICENSE +21 -0
  5. package/README.md +176 -0
  6. package/SECURITY.md +34 -0
  7. package/build.zig +38 -0
  8. package/build.zig.zon +7 -0
  9. package/clients/README.md +149 -0
  10. package/clients/go/README.md +24 -0
  11. package/clients/go/examples/fake-session/main.go +93 -0
  12. package/clients/go/go.mod +3 -0
  13. package/clients/go/zmr/client.go +432 -0
  14. package/clients/kotlin/README.md +35 -0
  15. package/clients/kotlin/build.gradle.kts +35 -0
  16. package/clients/kotlin/settings.gradle.kts +15 -0
  17. package/clients/kotlin/src/main/kotlin/dev/zmr/FakeSession.kt +86 -0
  18. package/clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt +67 -0
  19. package/clients/python/README.md +29 -0
  20. package/clients/python/examples/fake_session.py +48 -0
  21. package/clients/python/pyproject.toml +13 -0
  22. package/clients/python/zmr_client.py +202 -0
  23. package/clients/rust/Cargo.lock +107 -0
  24. package/clients/rust/Cargo.toml +10 -0
  25. package/clients/rust/README.md +19 -0
  26. package/clients/rust/examples/fake_session.rs +70 -0
  27. package/clients/rust/src/lib.rs +461 -0
  28. package/clients/swift/Package.swift +16 -0
  29. package/clients/swift/README.md +36 -0
  30. package/clients/swift/Sources/ZMRClient/ZMRClient.swift +114 -0
  31. package/clients/swift/Sources/ZMRFakeSession/main.swift +86 -0
  32. package/clients/typescript/README.md +34 -0
  33. package/clients/typescript/examples/fake-session.mjs +36 -0
  34. package/clients/typescript/index.d.ts +144 -0
  35. package/clients/typescript/index.mjs +192 -0
  36. package/clients/typescript/package.json +8 -0
  37. package/docs/adr/0001-agent-native-runner-boundary.md +31 -0
  38. package/docs/adr/0002-app-local-zmr-contract.md +39 -0
  39. package/docs/adr/0003-ios-simulator-xctest-shim.md +41 -0
  40. package/docs/adr/0004-benchmark-claims-and-baseline-collection.md +37 -0
  41. package/docs/adr/README.md +12 -0
  42. package/docs/ai-agents.md +154 -0
  43. package/docs/app-integration.md +330 -0
  44. package/docs/benchmarking.md +273 -0
  45. package/docs/client-installation.md +133 -0
  46. package/docs/clients.md +98 -0
  47. package/docs/config.md +175 -0
  48. package/docs/demo.md +259 -0
  49. package/docs/frameworks.md +72 -0
  50. package/docs/install.md +95 -0
  51. package/docs/npm.md +356 -0
  52. package/docs/protocol-fixtures/README.md +8 -0
  53. package/docs/protocol-fixtures/core-session.requests.jsonl +8 -0
  54. package/docs/protocol-fixtures/core-session.responses.jsonl +8 -0
  55. package/docs/protocol-versioning.md +65 -0
  56. package/docs/protocol.md +560 -0
  57. package/docs/scenario-authoring.md +88 -0
  58. package/docs/trace-privacy.md +88 -0
  59. package/docs/troubleshooting.md +256 -0
  60. package/examples/android-app-auth-probe.json +89 -0
  61. package/examples/android-app-error-state.json +13 -0
  62. package/examples/android-app-login-smoke.json +192 -0
  63. package/examples/android-app-onboarding.json +12 -0
  64. package/examples/android-app-referral-deep-link.json +12 -0
  65. package/examples/android-shim-smoke.json +19 -0
  66. package/examples/demo-failure.json +12 -0
  67. package/examples/demo-fake.json +14 -0
  68. package/examples/ios-dev-client-open-link.json +26 -0
  69. package/examples/ios-dev-client-route-snapshot.json +24 -0
  70. package/examples/ios-shim-smoke.json +23 -0
  71. package/examples/ios-smoke.json +9 -0
  72. package/go.work +3 -0
  73. package/npm/agents.mjs +183 -0
  74. package/npm/app-config.mjs +95 -0
  75. package/npm/build-zmr.mjs +21 -0
  76. package/npm/commands.mjs +104 -0
  77. package/npm/generated-files.mjs +50 -0
  78. package/npm/index.mjs +75 -0
  79. package/npm/init-app.mjs +80 -0
  80. package/npm/package-scripts.mjs +72 -0
  81. package/npm/postinstall.mjs +21 -0
  82. package/npm/scaffold.mjs +179 -0
  83. package/npm/scenarios.mjs +93 -0
  84. package/npm/setup.mjs +69 -0
  85. package/npm/wizard.mjs +117 -0
  86. package/npm/zmr.mjs +23 -0
  87. package/package.json +118 -0
  88. package/schemas/README.md +26 -0
  89. package/schemas/action-result.schema.json +27 -0
  90. package/schemas/capabilities-output.schema.json +98 -0
  91. package/schemas/devices-output.schema.json +25 -0
  92. package/schemas/doctor-output.schema.json +51 -0
  93. package/schemas/explain-output.schema.json +51 -0
  94. package/schemas/import-output.schema.json +23 -0
  95. package/schemas/init-output.schema.json +71 -0
  96. package/schemas/json-rpc.schema.json +55 -0
  97. package/schemas/release-manifest.schema.json +43 -0
  98. package/schemas/release-readiness-output.schema.json +127 -0
  99. package/schemas/run-output.schema.json +43 -0
  100. package/schemas/scenario.schema.json +128 -0
  101. package/schemas/schemas-output.schema.json +26 -0
  102. package/schemas/semantic-snapshot.schema.json +116 -0
  103. package/schemas/snapshot.schema.json +60 -0
  104. package/schemas/trace-event.schema.json +14 -0
  105. package/schemas/trace-manifest.schema.json +59 -0
  106. package/schemas/validate-output.schema.json +42 -0
  107. package/schemas/version-output.schema.json +23 -0
  108. package/schemas/zmr-config.schema.json +75 -0
  109. package/scripts/android-emulator.sh +126 -0
  110. package/scripts/assert-ios-physical-ready.sh +213 -0
  111. package/scripts/benchmark-command.sh +307 -0
  112. package/scripts/benchmark.sh +359 -0
  113. package/scripts/benchmark_gate.py +117 -0
  114. package/scripts/benchmark_result_row.py +88 -0
  115. package/scripts/compare-benchmarks.py +288 -0
  116. package/scripts/create-android-demo-app.sh +342 -0
  117. package/scripts/create-ios-demo-app.sh +261 -0
  118. package/scripts/demo-android-real.sh +232 -0
  119. package/scripts/demo-ios-real.sh +270 -0
  120. package/scripts/demo.sh +464 -0
  121. package/scripts/device-matrix.sh +338 -0
  122. package/scripts/ensure-ios-shim-target.rb +237 -0
  123. package/scripts/install-android-shim.sh +281 -0
  124. package/scripts/install-ios-shim.sh +589 -0
  125. package/scripts/pilot-gate.sh +560 -0
  126. package/scripts/release-readiness.py +838 -0
  127. package/scripts/release-readiness.sh +91 -0
  128. package/scripts/run-android-pilot.sh +561 -0
  129. package/scripts/run-ios-pilot.sh +509 -0
  130. package/shims/android/README.md +21 -0
  131. package/shims/android/ZMRShimInstrumentedTest.java +152 -0
  132. package/shims/android/protocol.md +18 -0
  133. package/shims/ios/README.md +50 -0
  134. package/shims/ios/ZMRShim.swift +110 -0
  135. package/shims/ios/ZMRShimUITestCase.swift +518 -0
  136. package/shims/ios/protocol.md +74 -0
  137. package/skills/zmr-mobile-testing/SKILL.md +127 -0
  138. package/src/android.zig +344 -0
  139. package/src/android_device_info.zig +99 -0
  140. package/src/android_emulator.zig +154 -0
  141. package/src/android_screen_recording.zig +112 -0
  142. package/src/android_shell.zig +112 -0
  143. package/src/bundle.zig +124 -0
  144. package/src/bundle_redaction.zig +272 -0
  145. package/src/bundle_tar.zig +123 -0
  146. package/src/cli_devices.zig +97 -0
  147. package/src/cli_doctor.zig +114 -0
  148. package/src/cli_import.zig +70 -0
  149. package/src/cli_info.zig +39 -0
  150. package/src/cli_init.zig +72 -0
  151. package/src/cli_output.zig +467 -0
  152. package/src/cli_run.zig +259 -0
  153. package/src/cli_serve.zig +287 -0
  154. package/src/cli_trace.zig +111 -0
  155. package/src/cli_validate.zig +41 -0
  156. package/src/command.zig +211 -0
  157. package/src/config.zig +305 -0
  158. package/src/config_diagnostics.zig +212 -0
  159. package/src/config_paths.zig +49 -0
  160. package/src/device_registry.zig +37 -0
  161. package/src/doctor.zig +412 -0
  162. package/src/doctor_hints.zig +52 -0
  163. package/src/errors.zig +55 -0
  164. package/src/fake_device.zig +163 -0
  165. package/src/health.zig +28 -0
  166. package/src/importer.zig +343 -0
  167. package/src/importer_json.zig +100 -0
  168. package/src/importer_model.zig +103 -0
  169. package/src/ios.zig +399 -0
  170. package/src/ios_devices.zig +219 -0
  171. package/src/ios_lifecycle.zig +72 -0
  172. package/src/ios_shim.zig +242 -0
  173. package/src/ios_snapshot.zig +20 -0
  174. package/src/json_fields.zig +80 -0
  175. package/src/json_rpc.zig +150 -0
  176. package/src/json_rpc_methods.zig +318 -0
  177. package/src/json_rpc_observation.zig +31 -0
  178. package/src/json_rpc_params.zig +52 -0
  179. package/src/json_rpc_protocol.zig +110 -0
  180. package/src/json_rpc_trace.zig +73 -0
  181. package/src/main.zig +131 -0
  182. package/src/mcp.zig +234 -0
  183. package/src/mcp_protocol.zig +64 -0
  184. package/src/mcp_trace.zig +83 -0
  185. package/src/report.zig +346 -0
  186. package/src/report_html.zig +63 -0
  187. package/src/report_values.zig +27 -0
  188. package/src/run_options.zig +152 -0
  189. package/src/runner.zig +280 -0
  190. package/src/runner_actions.zig +109 -0
  191. package/src/runner_config.zig +6 -0
  192. package/src/runner_diagnostics.zig +268 -0
  193. package/src/runner_events.zig +170 -0
  194. package/src/runner_native.zig +88 -0
  195. package/src/runner_waits.zig +300 -0
  196. package/src/scaffold.zig +472 -0
  197. package/src/scenario.zig +346 -0
  198. package/src/scenario_fields.zig +50 -0
  199. package/src/schema_registry.zig +53 -0
  200. package/src/selector.zig +84 -0
  201. package/src/semantic.zig +171 -0
  202. package/src/trace.zig +315 -0
  203. package/src/trace_json.zig +340 -0
  204. package/src/trace_summary.zig +218 -0
  205. package/src/trace_summary_diagnostic.zig +202 -0
  206. package/src/types.zig +120 -0
  207. package/src/uiautomator.zig +164 -0
  208. package/src/validation.zig +187 -0
  209. package/src/version.zig +22 -0
  210. package/viewer/app.js +373 -0
  211. package/viewer/index.html +126 -0
  212. package/viewer/parser.js +233 -0
  213. package/viewer/styles.css +585 -0
package/docs/demo.md ADDED
@@ -0,0 +1,259 @@
1
+ # Demo
2
+
3
+ Run the local demo with no emulator, simulator, app, or credentials:
4
+
5
+ ```bash
6
+ ./scripts/demo.sh
7
+ ```
8
+
9
+ The script builds `zig-out/bin/zmr`, then runs:
10
+
11
+ - `zmr version`
12
+ - `zmr version --json`
13
+ - `zmr schemas --json`
14
+ - `zmr validate examples/demo-fake.json`
15
+ - `zmr validate examples/demo-failure.json`
16
+ - `zmr validate examples/android-app-onboarding.json`
17
+ - `zmr validate examples/android-app-referral-deep-link.json`
18
+ - `zmr validate examples/android-app-error-state.json`
19
+ - `zmr validate examples/android-shim-smoke.json`
20
+ - `zmr validate examples/ios-smoke.json`
21
+ - `zmr validate examples/ios-dev-client-open-link.json`
22
+ - `zmr validate examples/ios-dev-client-route-snapshot.json`
23
+ - `zmr validate examples/ios-shim-smoke.json`
24
+ - expected-failing `zmr validate --json` output that shows `fieldPath`, `line`,
25
+ and `column` for invalid scenarios covered by `schemas/validate-output.schema.json`
26
+ - `zmr doctor --adb ./tests/fake-adb.sh --xcrun ./tests/fake-xcrun.sh --ios-shim ./tests/fake-ios-shim.sh`
27
+ - `zmr doctor --json` output for a missing Android shim that includes a
28
+ remediation `hint`
29
+ - `zmr doctor --json` output that warns with stable setup `errorCode` values
30
+ when no Android devices, booted iOS simulators, or paired physical iOS
31
+ devices are ready
32
+ - expected-failing `zmr doctor --strict --json` output for the same no-device
33
+ setup, showing how CI can fail without parsing the diagnostics itself
34
+ - `zmr doctor --json --config traces/demo-doctor-config.json` output that
35
+ validates configured smoke scenario files, including an `ios-smoke-scenario` remediation
36
+ for a bad `ios.smokeScenario` and a `zmr validate on the configured Android
37
+ smoke scenario` hint for malformed scenario JSON
38
+ - `zmr doctor --json --config traces/demo-bad-config.json` output that reports
39
+ stable `errorCode` plus `fieldPath` for an invalid app-local config value
40
+ before device setup starts
41
+ - `zmr devices --adb ./tests/fake-adb.sh`
42
+ - `zmr devices --json --adb ./tests/fake-adb.sh`
43
+ - `zmr devices --platform ios --xcrun ./tests/fake-xcrun.sh`
44
+ - `zmr devices --json --platform ios --xcrun ./tests/fake-xcrun.sh`
45
+ - `zmr init --app --json --dir traces/demo-init-app --app-id com.example.demoapp`
46
+ followed by validation and strict config-driven doctor checks from that
47
+ generated app-local workspace
48
+ - `zmr import flow-yaml traces/demo-flow-yaml-flow.yaml --out traces/demo-imported-flow.json --json`
49
+ followed by validation of the generated native ZMR scenario
50
+ - `zmr run examples/demo-fake.json --trace-dir traces/demo-fake-android --json`
51
+ - `scripts/device-matrix.sh --matrix traces/demo-device-matrix.json --trace-root traces/demo-device-matrix`
52
+ - `zmr run examples/demo-failure.json --trace-dir traces/demo-failure --json`
53
+ - `zmr explain traces/demo-failure`
54
+ - `zmr explain traces/demo-failure --json`
55
+ - `zmr serve --transport stdio --trace-dir traces/demo-rpc-session`
56
+ - `node clients/typescript/examples/fake-session.mjs`
57
+ - `python3 clients/python/examples/fake_session.py`
58
+ - `swift run ZMRFakeSession` from `clients/swift`
59
+ - `gradle -p clients/kotlin runFakeSession`
60
+ - `go run ./clients/go/examples/fake-session --zmr ./zig-out/bin/zmr --adb ./tests/fake-adb.sh --trace-dir traces/demo-go-client`
61
+ - `cargo run --manifest-path clients/rust/Cargo.toml --example fake_session -- --zmr ./zig-out/bin/zmr --adb ./tests/fake-adb.sh --trace-dir traces/demo-rust-client`
62
+ - `zmr run examples/ios-smoke.json --platform ios --trace-dir traces/demo-fake-ios`
63
+
64
+ The fake Android flow exercises selector matching and wait/assert trace output.
65
+ The fake device-matrix flow exercises Android, iOS simulator, and physical iOS
66
+ matrix rows without requiring local hardware, producing `matrix.jsonl` and
67
+ `summary.json`.
68
+ The fake failure flow exercises failed trace diagnostics and the terminal
69
+ `zmr explain` summary.
70
+ The fake JSON-RPC flow exercises the agent protocol over stdio, live RPC trace
71
+ recording, `observe.snapshot`, and redacted `trace.export`.
72
+ Doctor output is intentionally structured for setup automation; `--json`
73
+ includes remediation `hint` values for missing or warning checks, and
74
+ `--config` validates app-local smoke scenario files. Add `--strict` when a
75
+ non-`ok` diagnostic should also make the command fail.
76
+ The TypeScript reference client flow exercises the same protocol through the
77
+ client API external agents would use.
78
+ The Python reference client flow verifies the same agent integration path with
79
+ only the Python standard library.
80
+ The Swift and Kotlin reference client flows verify host-side native-language
81
+ agent/test-harness integration for iOS and Android teams.
82
+ The fake Android shim flow exercises shim-backed hierarchy, wait, tap, type,
83
+ hide-keyboard, and snapshot handling.
84
+ The fake iOS flow exercises simulator lifecycle, deep-link opening, screenshot
85
+ artifact capture, log capture, and snapshot trace writing. The fake iOS shim
86
+ flow exercises shim-backed hierarchy, wait, tap, type, hide-keyboard, and
87
+ snapshot handling.
88
+
89
+ Load any generated `.zmrtrace` in `viewer/index.html` to inspect the replay
90
+ timeline, payloads, screenshot, UI tree, selected node details, and raw
91
+ artifacts side-by-side.
92
+
93
+ ## Real Android Pilot Demo
94
+
95
+ Run the Android pilot against a sample app test build:
96
+
97
+ ```bash
98
+ ./scripts/run-android-pilot.sh \
99
+ --app-root /path/to/mobile-app \
100
+ --device emulator-5554
101
+ ```
102
+
103
+ To force a known emulator state, direct `zmr run` supports `--android-avd`,
104
+ `--create-avd-if-missing`, `--avd-system-image`, `--avd-device`,
105
+ `--restore-snapshot`, `--reset-emulator`, and `--wait-emulator`. The pilot
106
+ wrapper accepts the same state controls while also building/installing the app.
107
+ Add `--screen-record` to keep a pilot-level MP4 under the trace root:
108
+
109
+ ```bash
110
+ ./scripts/run-android-pilot.sh \
111
+ --app-root /path/to/mobile-app \
112
+ --device emulator-5554 \
113
+ --avd Small_Phone \
114
+ --reset-emulator \
115
+ --restore-snapshot zmr-clean \
116
+ --screen-record
117
+ ```
118
+
119
+ The script builds `zmr` when needed, validates both sample scenarios, installs the debug test APK, starts the app's test Metro server, and runs:
120
+
121
+ - `examples/android-app-auth-probe.json`
122
+ - `examples/android-app-login-smoke.json`
123
+
124
+ For each single run it writes:
125
+
126
+ - `auth/report.html`
127
+ - `login-smoke/report.html`
128
+ - `auth.zmrtrace`
129
+ - `auth-redacted.zmrtrace`
130
+ - `login-smoke.zmrtrace`
131
+ - `login-smoke-redacted.zmrtrace`
132
+ - `screenrecord.mp4` when pilot `--screen-record`, `zmr run --screen-record`, or `.zmr/config.json` `artifacts.screenRecording` is enabled
133
+
134
+ Use the redacted bundles for demos outside a trusted local machine:
135
+
136
+ ```bash
137
+ open viewer/index.html
138
+ ```
139
+
140
+ Then load `auth-redacted.zmrtrace` or `login-smoke-redacted.zmrtrace`.
141
+
142
+ Inspect the command plan without touching the emulator:
143
+
144
+ ```bash
145
+ ./scripts/run-android-pilot.sh --dry-run --skip-emulator --skip-metro --app-root <android-app-root>
146
+ ```
147
+
148
+ Run repeated benchmark passes:
149
+
150
+ ```bash
151
+ ./scripts/run-android-pilot.sh \
152
+ --app-root <android-app-root> \
153
+ --device emulator-5554 \
154
+ --runs 20 \
155
+ --min-pass-rate 100 \
156
+ --max-failures 0
157
+ ```
158
+
159
+ `<trace-root>/metro.log` may contain sensitive app output from the sample app test environment. Do not publish raw Metro logs.
160
+
161
+ ## Real Android Demo APK
162
+
163
+ To generate a small public native Android app and matching smoke scenario:
164
+
165
+ ```bash
166
+ npx zmr-demo-android --out /tmp/zmr-android-demo --device emulator-5554 --avd <avd-name>
167
+ ```
168
+
169
+ The wrapper builds a signed debug APK with Android SDK command-line tools
170
+ only, boots the named AVD when the requested device is not ready, installs the
171
+ app, and runs the generated smoke scenario. To inspect or customize the
172
+ generated app before running manually:
173
+
174
+ ```bash
175
+ npx zmr-create-android-demo-app --out /tmp/zmr-android-demo
176
+ adb install -r /tmp/zmr-android-demo/build/app-debug.apk
177
+ zmr run /tmp/zmr-android-demo/.zmr/android-smoke.json \
178
+ --device emulator-5554 \
179
+ --app-id com.example.mobiletest \
180
+ --trace-dir /tmp/zmr-android-demo/traces/android-demo
181
+ ```
182
+
183
+ The scenario launches the app, waits for visible text, taps a button, types
184
+ text into a field, and captures a trace-backed snapshot.
185
+
186
+ ## Real iOS Simulator Demo
187
+
188
+ To generate a small public demo app with the ZMR XCTest shim already installed:
189
+
190
+ ```bash
191
+ npx zmr-demo-ios --out /tmp/zmr-ios-demo --device booted --cleanup-build-products
192
+ ```
193
+
194
+ That command creates the demo app, builds it, installs it on the requested
195
+ simulator, runs the plain iOS smoke and selector-grade shim smoke, then writes
196
+ reports and redacted `.zmrtrace` bundles. `--cleanup-build-products` removes
197
+ generated Xcode `DerivedData` after the pilot so repeated demo runs keep their
198
+ footprint small. When `--device booted` is used and no
199
+ simulator is running, the command boots an available iOS simulator first. If
200
+ the first available simulator fails to boot because CoreSimulator cannot start
201
+ `launchd_sim`, the script tries the next available iOS simulator before failing.
202
+
203
+ To inspect or customize the generated app before running the pilot manually:
204
+
205
+ ```bash
206
+ npx zmr-create-ios-demo-app --out /tmp/zmr-ios-demo
207
+ cd /tmp/zmr-ios-demo
208
+ xcodebuild -project ios/ZMRDemo.xcodeproj -scheme ZMRDemo -destination 'generic/platform=iOS Simulator' -derivedDataPath DerivedData build
209
+ ```
210
+
211
+ Then boot a simulator and run from the ZMR repo:
212
+
213
+ ```bash
214
+ scripts/run-ios-pilot.sh \
215
+ --app-root /tmp/zmr-ios-demo \
216
+ --app-path /tmp/zmr-ios-demo/DerivedData/Build/Products/Debug-iphonesimulator/ZMRDemo.app \
217
+ --app-id com.example.mobiletest \
218
+ --device booted \
219
+ --ios-shim /tmp/zmr-ios-demo/.zmr/ios-shim
220
+ ```
221
+
222
+ Build the app for an iOS simulator, boot a simulator, then run:
223
+
224
+ ```bash
225
+ ./scripts/run-ios-pilot.sh \
226
+ --app-root /path/to/mobile-app \
227
+ --app-path /path/to/mobile-app/build/Debug-iphonesimulator/Sample.app \
228
+ --app-id com.example.mobiletest \
229
+ --device booted \
230
+ --ios-shim /path/to/mobile-app/.zmr/ios-shim
231
+ ```
232
+
233
+ For each run it writes:
234
+
235
+ - `ios-smoke/report.html`
236
+ - `ios-smoke.zmrtrace`
237
+ - `ios-smoke-redacted.zmrtrace`
238
+ - `ios-shim-smoke/report.html` when `--ios-shim` is set
239
+ - `ios-shim-smoke.zmrtrace` when `--ios-shim` is set
240
+ - `ios-shim-smoke-redacted.zmrtrace` when `--ios-shim` is set
241
+
242
+ The iOS demo covers simulator install, launch/open-link, screenshot capture,
243
+ log capture, trace export, and viewer inspection. With `--ios-shim`, it also
244
+ runs `examples/ios-shim-smoke.json`, which exercises launch, waitVisible, tap,
245
+ selector-scoped typeText, hideKeyboard, and snapshot through the generated
246
+ XCTest/XCUIAutomation shim command.
247
+
248
+ When an iOS shim is configured, the pilot wrapper prewarms it before scenario
249
+ timing by sending `{"cmd":"appState"}`. That catches Xcode target wiring issues
250
+ early and keeps cold `build-for-testing` cost out of benchmark durations.
251
+ The same app-state check is used as an idempotent launch confirmation when the
252
+ app is already running but `simctl launch` reports a non-zero exit.
253
+
254
+ Simulator demos require a simulator-built `iphonesimulator` `.app`. A signed
255
+ device `.ipa` is for `--ios-device-type physical` only and is rejected early for
256
+ simulator pilots.
257
+
258
+ `clearState` on iOS is best-effort app uninstall by bundle id. Repeating it is
259
+ safe: a simulator where the app is already absent is treated as clean.
@@ -0,0 +1,72 @@
1
+ # Framework Guide
2
+
3
+ ZMR drives the installed mobile app through Android and iOS automation surfaces.
4
+ It does not require a React Native, Expo, Flutter, Swift, Kotlin, or Java test
5
+ SDK inside the app. The app only needs stable selectors and a predictable way to
6
+ reach the screens you want to test.
7
+
8
+ ## React Native
9
+
10
+ Use app-owned selectors for controls that agents need to find:
11
+
12
+ - `testID` for Android resource ids and iOS accessibility identifiers.
13
+ - `accessibilityLabel` for user-facing controls that should be visible to assistive technology.
14
+ - Stable visible text for headings, tabs, and actions that are not localized or data-driven.
15
+ - Deep links for jumping directly to logged-in, onboarding, or error states.
16
+
17
+ Keep generated ZMR files under `.zmr/` and run the wizard from the app repo:
18
+
19
+ ```bash
20
+ npx zmr-wizard --app-id com.example.mobiletest --package-json
21
+ ```
22
+
23
+ ## Expo
24
+
25
+ Expo development builds work like React Native apps once they are installed on a
26
+ simulator, emulator, or device. For dev-client flows, give ZMR the scheme that
27
+ opens your development build:
28
+
29
+ ```bash
30
+ npx zmr-wizard \
31
+ --app-id com.example.mobiletest \
32
+ --expo-dev-client-scheme mobiletest \
33
+ --package-json
34
+ ```
35
+
36
+ The wizard adds Android and iOS dev-client scenarios that open Metro before
37
+ selector assertions run.
38
+
39
+ ## Flutter
40
+
41
+ ZMR supports Flutter apps at the platform level. It can launch the Android or
42
+ iOS app, open deep links, wait for accessibility semantics, tap visible
43
+ controls, type text, take screenshots, collect traces, and export redacted
44
+ artifacts.
45
+
46
+ ZMR does not inspect Flutter widget trees, read Dart state, or replace Flutter's
47
+ own widget/integration test APIs. For reliable ZMR scenarios, expose stable
48
+ selectors through Flutter semantics:
49
+
50
+ ```dart
51
+ Semantics(
52
+ label: 'email',
53
+ textField: true,
54
+ child: TextField(...),
55
+ )
56
+ ```
57
+
58
+ Prefer app-owned semantics labels for form fields, primary buttons, tabs, and
59
+ important states. Deep links are the cleanest way to skip setup screens and reach
60
+ the state an agent needs to inspect.
61
+
62
+ ## Native Android And iOS
63
+
64
+ Native apps should expose:
65
+
66
+ - Android `resourceId` values or content descriptions for important controls.
67
+ - iOS accessibility identifiers or labels for important controls.
68
+ - Deep links for direct navigation into test states.
69
+ - Optional Android and iOS shims when native selector actions and bounded
70
+ hierarchy snapshots are needed.
71
+
72
+ See [app-integration.md](app-integration.md) for the shim setup commands.
@@ -0,0 +1,95 @@
1
+ # Install
2
+
3
+ Most mobile app teams should install ZMR from npm inside the app repository.
4
+ That keeps `.zmr/` config, scenarios, generated package scripts, and traces with
5
+ the app they belong to.
6
+
7
+ ## npm Install
8
+
9
+ ```bash
10
+ npm install --save-dev zeno-mobile-runner
11
+ npx zmr-wizard --app-id com.example.mobiletest --package-json
12
+ npx zmr doctor --strict --json --config .zmr/config.json
13
+ ```
14
+
15
+ The wizard creates `.zmr/config.json`, Android and iOS smoke scenarios,
16
+ `.zmr/device-matrix.json`, and `.zmr/AGENTS.md`. Run the generated validation
17
+ before touching a device:
18
+
19
+ ```bash
20
+ npm run zmr:validate
21
+ ```
22
+
23
+ Common app-local commands:
24
+
25
+ ```bash
26
+ npx zmr-wizard --app-id com.example.mobiletest --android --ios --package-json
27
+ npx zmr-install-android-shim --app-root . --test-package com.example.mobiletest.test
28
+ npx zmr-install-ios-shim --app-root . --scheme SampleUITests --bundle-id com.example.mobiletest
29
+ npx zmr-device-matrix --matrix .zmr/device-matrix.json --trace-root traces/zmr-matrix
30
+ npm run zmr:serve
31
+ npm run zmr:mcp
32
+ ```
33
+
34
+ See [docs/npm.md](npm.md) for the full npm binary list, binary resolution, and
35
+ app-local `.zmr/` setup.
36
+
37
+ ## Homebrew Or Existing Binary
38
+
39
+ Teams that do not use JavaScript can install or build the `zmr` executable once
40
+ and point any language client or script at it:
41
+
42
+ ```bash
43
+ brew install --build-from-source ./dist/homebrew/zmr.rb
44
+ zmr version
45
+ ```
46
+
47
+ ## Build From Source
48
+
49
+ ```bash
50
+ git clone https://github.com/johnmikel/zeno-mobile-runner.git
51
+ cd zeno-mobile-runner
52
+ zig test src/test_harness.zig -target aarch64-macos.15.0
53
+ zig build-exe src/main.zig -target aarch64-macos.15.0 -O ReleaseSafe -femit-bin=zig-out/bin/zmr
54
+ ./zig-out/bin/zmr version
55
+ ```
56
+
57
+ On macOS hosts where Zig can infer the target, `zig build test` and `zig build`
58
+ are also valid.
59
+
60
+ ## First Run Without A Device
61
+
62
+ ```bash
63
+ zmr version --json
64
+ zmr schemas --json
65
+ zmr init zmr-scenario.json --app-id com.example.mobiletest
66
+ zmr init --app --json --dir . --app-id com.example.mobiletest
67
+ zmr validate examples/demo-fake.json
68
+ ./scripts/demo.sh
69
+ ```
70
+
71
+ ## App Codebase Integration
72
+
73
+ ZMR runs outside the app process and points at app build artifacts. For real app
74
+ pilots, pass the app root, app id, target device, and optional shim paths:
75
+
76
+ ```bash
77
+ npx zmr-pilot-gate \
78
+ --android \
79
+ --ios \
80
+ --android-app-root . \
81
+ --android-app-id com.example.mobiletest \
82
+ --android-device emulator-5554 \
83
+ --ios-app-root . \
84
+ --ios-app-path ./build/Debug-iphonesimulator/Sample.app \
85
+ --ios-app-id com.example.mobiletest \
86
+ --ios-device booted \
87
+ --runs 20 \
88
+ --min-pass-rate 100 \
89
+ --max-failures 0 \
90
+ --evidence-out traces/zmr-pilots/evidence.jsonl
91
+ ```
92
+
93
+ See [app-integration.md](app-integration.md), [frameworks.md](frameworks.md),
94
+ and [config.md](config.md) for framework guidance, shim setup, `.zmr/config.json`
95
+ defaults, and CLI override precedence.