zig-mobile-runner 0.1.0

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 (225) hide show
  1. package/CHANGELOG.md +484 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/FEATURES.md +112 -0
  4. package/LICENSE +21 -0
  5. package/README.md +255 -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 +144 -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 +156 -0
  43. package/docs/app-integration.md +316 -0
  44. package/docs/benchmarking.md +275 -0
  45. package/docs/client-installation.md +141 -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/dsl.md +57 -0
  50. package/docs/install.md +233 -0
  51. package/docs/market-positioning.md +70 -0
  52. package/docs/npm.md +359 -0
  53. package/docs/protocol-fixtures/README.md +8 -0
  54. package/docs/protocol-fixtures/core-session.requests.jsonl +8 -0
  55. package/docs/protocol-fixtures/core-session.responses.jsonl +8 -0
  56. package/docs/protocol-versioning.md +65 -0
  57. package/docs/protocol.md +560 -0
  58. package/docs/publication.md +77 -0
  59. package/docs/release-audit.md +99 -0
  60. package/docs/release-candidate.md +111 -0
  61. package/docs/release-evidence.md +188 -0
  62. package/docs/release-notes-template.md +58 -0
  63. package/docs/roadmap.md +334 -0
  64. package/docs/scenario-authoring.md +88 -0
  65. package/docs/shipping.md +170 -0
  66. package/docs/trace-privacy.md +88 -0
  67. package/docs/troubleshooting.md +256 -0
  68. package/examples/android-app-auth-probe.json +89 -0
  69. package/examples/android-app-error-state.json +13 -0
  70. package/examples/android-app-login-smoke.json +192 -0
  71. package/examples/android-app-onboarding.json +12 -0
  72. package/examples/android-app-referral-deep-link.json +12 -0
  73. package/examples/android-shim-smoke.json +19 -0
  74. package/examples/demo-failure.json +12 -0
  75. package/examples/demo-fake.json +14 -0
  76. package/examples/ios-dev-client-open-link.json +26 -0
  77. package/examples/ios-dev-client-route-snapshot.json +24 -0
  78. package/examples/ios-shim-smoke.json +23 -0
  79. package/examples/ios-smoke.json +9 -0
  80. package/go.work +3 -0
  81. package/npm/agents.mjs +183 -0
  82. package/npm/app-config.mjs +95 -0
  83. package/npm/build-zmr.mjs +21 -0
  84. package/npm/commands.mjs +104 -0
  85. package/npm/generated-files.mjs +50 -0
  86. package/npm/index.mjs +75 -0
  87. package/npm/init-app.mjs +80 -0
  88. package/npm/package-scripts.mjs +72 -0
  89. package/npm/postinstall.mjs +21 -0
  90. package/npm/scaffold.mjs +179 -0
  91. package/npm/scenarios.mjs +93 -0
  92. package/npm/setup.mjs +69 -0
  93. package/npm/wizard.mjs +117 -0
  94. package/npm/zmr.mjs +23 -0
  95. package/package.json +114 -0
  96. package/prebuilds/darwin-arm64/zmr +0 -0
  97. package/prebuilds/darwin-x64/zmr +0 -0
  98. package/prebuilds/linux-arm64/zmr +0 -0
  99. package/prebuilds/linux-x64/zmr +0 -0
  100. package/schemas/README.md +26 -0
  101. package/schemas/action-result.schema.json +27 -0
  102. package/schemas/capabilities-output.schema.json +98 -0
  103. package/schemas/devices-output.schema.json +25 -0
  104. package/schemas/doctor-output.schema.json +51 -0
  105. package/schemas/explain-output.schema.json +51 -0
  106. package/schemas/import-output.schema.json +23 -0
  107. package/schemas/init-output.schema.json +71 -0
  108. package/schemas/json-rpc.schema.json +55 -0
  109. package/schemas/release-manifest.schema.json +43 -0
  110. package/schemas/release-readiness-output.schema.json +127 -0
  111. package/schemas/run-output.schema.json +43 -0
  112. package/schemas/scenario.schema.json +128 -0
  113. package/schemas/schemas-output.schema.json +26 -0
  114. package/schemas/semantic-snapshot.schema.json +116 -0
  115. package/schemas/snapshot.schema.json +60 -0
  116. package/schemas/trace-event.schema.json +14 -0
  117. package/schemas/trace-manifest.schema.json +59 -0
  118. package/schemas/validate-output.schema.json +42 -0
  119. package/schemas/version-output.schema.json +23 -0
  120. package/schemas/zmr-config.schema.json +75 -0
  121. package/scripts/android-emulator.sh +126 -0
  122. package/scripts/assert-ios-physical-ready.sh +213 -0
  123. package/scripts/benchmark-command.sh +307 -0
  124. package/scripts/benchmark.sh +359 -0
  125. package/scripts/benchmark_gate.py +117 -0
  126. package/scripts/benchmark_result_row.py +88 -0
  127. package/scripts/compare-benchmarks.py +288 -0
  128. package/scripts/create-android-demo-app.sh +342 -0
  129. package/scripts/create-ios-demo-app.sh +261 -0
  130. package/scripts/demo-android-real.sh +232 -0
  131. package/scripts/demo-ios-real.sh +270 -0
  132. package/scripts/demo.sh +464 -0
  133. package/scripts/device-matrix.sh +338 -0
  134. package/scripts/ensure-ios-shim-target.rb +237 -0
  135. package/scripts/install-android-shim.sh +281 -0
  136. package/scripts/install-ios-shim.sh +589 -0
  137. package/scripts/pilot-gate.sh +560 -0
  138. package/scripts/release-readiness.py +838 -0
  139. package/scripts/release-readiness.sh +91 -0
  140. package/scripts/run-android-pilot.sh +561 -0
  141. package/scripts/run-ios-pilot.sh +509 -0
  142. package/shims/android/README.md +21 -0
  143. package/shims/android/ZMRShimInstrumentedTest.java +152 -0
  144. package/shims/android/protocol.md +18 -0
  145. package/shims/ios/README.md +50 -0
  146. package/shims/ios/ZMRShim.swift +110 -0
  147. package/shims/ios/ZMRShimUITestCase.swift +475 -0
  148. package/shims/ios/protocol.md +74 -0
  149. package/skills/zmr-mobile-testing/SKILL.md +127 -0
  150. package/src/android.zig +344 -0
  151. package/src/android_device_info.zig +99 -0
  152. package/src/android_emulator.zig +154 -0
  153. package/src/android_screen_recording.zig +112 -0
  154. package/src/android_shell.zig +112 -0
  155. package/src/bundle.zig +124 -0
  156. package/src/bundle_redaction.zig +272 -0
  157. package/src/bundle_tar.zig +123 -0
  158. package/src/cli_devices.zig +97 -0
  159. package/src/cli_doctor.zig +114 -0
  160. package/src/cli_import.zig +70 -0
  161. package/src/cli_info.zig +39 -0
  162. package/src/cli_init.zig +72 -0
  163. package/src/cli_output.zig +467 -0
  164. package/src/cli_run.zig +259 -0
  165. package/src/cli_serve.zig +287 -0
  166. package/src/cli_trace.zig +111 -0
  167. package/src/cli_validate.zig +41 -0
  168. package/src/command.zig +211 -0
  169. package/src/config.zig +305 -0
  170. package/src/config_diagnostics.zig +212 -0
  171. package/src/config_paths.zig +49 -0
  172. package/src/device_registry.zig +37 -0
  173. package/src/doctor.zig +412 -0
  174. package/src/doctor_hints.zig +52 -0
  175. package/src/errors.zig +55 -0
  176. package/src/fake_device.zig +163 -0
  177. package/src/health.zig +28 -0
  178. package/src/importer.zig +343 -0
  179. package/src/importer_json.zig +100 -0
  180. package/src/importer_model.zig +103 -0
  181. package/src/ios.zig +399 -0
  182. package/src/ios_devices.zig +219 -0
  183. package/src/ios_lifecycle.zig +72 -0
  184. package/src/ios_shim.zig +242 -0
  185. package/src/ios_snapshot.zig +20 -0
  186. package/src/json_fields.zig +80 -0
  187. package/src/json_rpc.zig +150 -0
  188. package/src/json_rpc_methods.zig +318 -0
  189. package/src/json_rpc_observation.zig +31 -0
  190. package/src/json_rpc_params.zig +52 -0
  191. package/src/json_rpc_protocol.zig +110 -0
  192. package/src/json_rpc_trace.zig +73 -0
  193. package/src/main.zig +135 -0
  194. package/src/mcp.zig +234 -0
  195. package/src/mcp_protocol.zig +64 -0
  196. package/src/mcp_trace.zig +83 -0
  197. package/src/report.zig +346 -0
  198. package/src/report_html.zig +63 -0
  199. package/src/report_values.zig +27 -0
  200. package/src/run_options.zig +152 -0
  201. package/src/runner.zig +280 -0
  202. package/src/runner_actions.zig +109 -0
  203. package/src/runner_config.zig +6 -0
  204. package/src/runner_diagnostics.zig +268 -0
  205. package/src/runner_events.zig +170 -0
  206. package/src/runner_native.zig +88 -0
  207. package/src/runner_waits.zig +300 -0
  208. package/src/scaffold.zig +472 -0
  209. package/src/scenario.zig +346 -0
  210. package/src/scenario_fields.zig +50 -0
  211. package/src/schema_registry.zig +53 -0
  212. package/src/selector.zig +84 -0
  213. package/src/semantic.zig +171 -0
  214. package/src/trace.zig +315 -0
  215. package/src/trace_json.zig +340 -0
  216. package/src/trace_summary.zig +218 -0
  217. package/src/trace_summary_diagnostic.zig +202 -0
  218. package/src/types.zig +120 -0
  219. package/src/uiautomator.zig +164 -0
  220. package/src/validation.zig +187 -0
  221. package/src/version.zig +22 -0
  222. package/viewer/app.js +373 -0
  223. package/viewer/index.html +126 -0
  224. package/viewer/parser.js +233 -0
  225. package/viewer/styles.css +585 -0
@@ -0,0 +1,256 @@
1
+ # Troubleshooting
2
+
3
+ Start with structured diagnostics instead of reading terminal output by hand:
4
+
5
+ ```bash
6
+ zmr doctor --json
7
+ zmr doctor --strict --json
8
+ zmr validate --json .zmr/android-smoke.json
9
+ zmr explain traces/zmr-android
10
+ ./scripts/release-gate.sh --dry-run
11
+ ```
12
+
13
+ `zmr doctor --json` is the first command to run when setup is unclear. It
14
+ reports Zig, ADB, Android device count, `xcrun`, iOS simulator state, physical
15
+ iOS device state, and configured Android/iOS shim command paths in a
16
+ machine-readable shape that scripts and agents can inspect. Device readiness
17
+ checks report `warning` when ADB sees zero devices, `xcrun` sees zero booted
18
+ iOS simulators, `devicectl` sees zero paired physical iOS devices, or all
19
+ listed physical devices are disconnected/unavailable, with stable
20
+ `setup.android.no_devices`, `setup.ios.no_booted_simulators`,
21
+ `setup.ios.no_physical_devices`, and
22
+ `setup.ios.no_ready_physical_devices` error codes.
23
+ Missing tool and shim checks also include stable setup codes such as
24
+ `setup.adb.not_found` and `setup.android_shim.not_found`.
25
+ By default `doctor` exits zero after printing diagnostics so interactive setup
26
+ can keep going; add `--strict` when CI or install scripts should exit non-zero
27
+ for any warning or missing check.
28
+ When run with `--config .zmr/config.json`, it
29
+ first reports whether the config file itself loaded, then validates configured
30
+ smoke scenario files from `android.smokeScenario` and
31
+ `ios.smokeScenario` so app-local setup mistakes fail before device orchestration
32
+ starts. Config files with wrong types, such as string values for boolean
33
+ artifact controls, unknown fields, such as misspelled `smokeScenario`, or empty strings
34
+ where paths/app ids/script commands are required are reported as `config` warnings.
35
+ Those warnings include `fieldPath` in JSON mode when ZMR can identify the
36
+ invalid `.zmr/config.json` key, plus stable `errorCode` values for setup
37
+ automation.
38
+ Missing scenario files are reported as `missing`; malformed scenario files are
39
+ reported as `warning` with a hint to run `zmr validate` on the configured file.
40
+ Non-`ok` checks include a `"hint"` field with the next concrete remediation
41
+ step. The JSON contract is published at
42
+ `schemas/doctor-output.schema.json`.
43
+
44
+ Top-level CLI failures use stable public error codes instead of Zig stack
45
+ traces. For example, `error[device.command_failed]: device command failed`
46
+ means a platform command such as ADB or `xcrun` failed before ZMR could collect
47
+ a device response; run `zmr doctor --json` next for setup details. An
48
+ `error[cli.unknown_command]: unknown command` response means the command name
49
+ was not recognized; run `zmr help` to inspect the supported CLI surface.
50
+
51
+ The real Android and iOS pilot wrappers run setup preflights before expensive
52
+ install or benchmark work. `scripts/run-android-pilot.sh --skip-emulator`
53
+ reports `no Android device found: <serial>` plus `setup.android.no_devices`
54
+ when the requested serial is not attached. `scripts/run-ios-pilot.sh` reports
55
+ `no booted iOS simulator found` plus `setup.ios.no_booted_simulators` when
56
+ `--device booted` has no target. Physical iOS pilot runs report
57
+ `setup.ios.physical_device_required`, `setup.ios.physical_device_not_found`, or
58
+ `setup.ios.physical_device_not_ready` for invalid or disconnected physical
59
+ device identifiers. Use the `serial` value from `zmr devices --json --platform
60
+ ios --ios-device-type physical`. The not-ready preflight also prints the
61
+ matched device state, such as
62
+ `state: disconnected`, while `zmr doctor --json` reports the broader
63
+ `ios-physical-devices` check with
64
+ `setup.ios.no_physical_devices` when no physical devices are listed, or
65
+ `setup.ios.no_ready_physical_devices` when only disconnected/unavailable
66
+ devices are listed. The no-ready detail includes a state breakdown such as
67
+ `disconnected=1, unavailable=1`. When at least one physical device is ready but
68
+ other devices are listed in unusable states, `doctor` keeps the check `ok` and
69
+ still includes the broader breakdown, for example
70
+ `1 ready physical iOS device(s); 3 listed (disconnected=1, unavailable=1)`.
71
+ In both cases the wrapper also prints the matching `zmr doctor --json` output
72
+ so CI logs contain the next remediation.
73
+ The JSON output also includes numeric `count` and `readyCount` fields on
74
+ device checks, so agents and scripts can branch without parsing the human
75
+ `detail` string.
76
+
77
+ ## Install Or Binary Issues
78
+
79
+ If `zmr` is not found from an app repo, check the npm wrapper resolution order:
80
+
81
+ ```bash
82
+ node -e 'import("zig-mobile-runner").then(m => console.log(m.resolveBinary()))'
83
+ npx zmr version
84
+ ```
85
+
86
+ The npm wrapper resolves `ZMR_BIN`, then bundled prebuilds, then
87
+ `zig-out/bin/zmr`. If none exist, install Zig and run:
88
+
89
+ ```bash
90
+ npm run build:zmr
91
+ ```
92
+
93
+ For source checkouts on this macOS host, use the explicit macOS 15 target shown
94
+ in the README:
95
+
96
+ ```bash
97
+ zig test src/main.zig -target aarch64-macos.15.0
98
+ zig build-exe src/main.zig -target aarch64-macos.15.0 -O Debug -femit-bin=zig-out/bin/zmr
99
+ ```
100
+
101
+ ## Scenario Issues
102
+
103
+ Validate scenarios before touching a device:
104
+
105
+ ```bash
106
+ zmr validate --json .zmr/android-smoke.json
107
+ ```
108
+
109
+ The JSON output includes `errorCode`, `fieldPath`, `line`, and `column` when ZMR
110
+ can locate the source. Fix schema and selector mistakes there first; device
111
+ state debugging is slower and less reliable when the scenario itself is invalid.
112
+
113
+ ## Android Device Issues
114
+
115
+ For a real emulator run, confirm that ADB sees exactly the device you intend to
116
+ use:
117
+
118
+ ```bash
119
+ adb devices
120
+ zmr doctor --adb adb
121
+ ```
122
+
123
+ If repeated local runs need a known state, prefer ZMR's emulator lifecycle flags
124
+ or the Android pilot wrapper:
125
+
126
+ ```bash
127
+ zmr run .zmr/android-smoke.json \
128
+ --android-avd Small_Phone \
129
+ --create-avd-if-missing \
130
+ --avd-system-image 'system-images;android-35;google_apis;arm64-v8a' \
131
+ --avd-device pixel_6 \
132
+ --restore-snapshot zmr-clean \
133
+ --wait-emulator \
134
+ --device emulator-5554
135
+ ```
136
+
137
+ If selector actions are slow or flaky through shell/UI Automator, install the
138
+ Android shim in the app repo:
139
+
140
+ ```bash
141
+ npx zmr-install-android-shim \
142
+ --app-root . \
143
+ --test-package com.example.mobiletest.test \
144
+ --android-module android/app \
145
+ --gradle-file android/app/build.gradle
146
+ ```
147
+
148
+ Then run with `--android-shim ./.zmr/android-shim` or set
149
+ `tools.androidShimPath` in `.zmr/config.json`.
150
+
151
+ ## iOS Simulator Issues
152
+
153
+ Confirm that `xcrun` sees a booted simulator:
154
+
155
+ ```bash
156
+ xcrun simctl list devices booted
157
+ zmr doctor --xcrun xcrun
158
+ ```
159
+
160
+ The simulator `.app` must be built and installed before launch/open-link flows.
161
+ A device `.ipa` is not simulator-compatible; `scripts/run-ios-pilot.sh` rejects
162
+ that mismatch with `setup.ios.simulator_app_required`. Build an
163
+ `iphonesimulator` `.app` for simulator pilots, or pass `--ios-device-type
164
+ physical` with a signed device artifact and a real physical device identifier.
165
+
166
+ On iOS, `clearState` is best-effort uninstall by bundle id; if the app is
167
+ already missing, ZMR treats the simulator as clean and continues. Simulator
168
+ `launch` is also idempotent when an XCTest shim is configured: if `simctl
169
+ launch` reports an error but `{"cmd":"appState"}` shows the app is already
170
+ running, ZMR treats the app as usable instead of failing the scenario.
171
+
172
+ Selector-grade iOS actions require an XCTest/XCUIAutomation shim command:
173
+
174
+ ```bash
175
+ npx zmr-install-ios-shim \
176
+ --app-root . \
177
+ --scheme SampleUITests \
178
+ --workspace ios/Sample.xcworkspace \
179
+ --app-target SampleApp \
180
+ --bundle-id com.example.mobiletest \
181
+ --patch-xcodeproj
182
+ ```
183
+
184
+ The generated `.zmr/ensure-ios-shim-target.sh` helper resolves the referenced
185
+ `.xcodeproj` from the workspace when there is one project, or when exactly one
186
+ project contains `--app-target`, or when `--bundle-id` disambiguates matching
187
+ app targets. Pass `--project` explicitly for still-ambiguous multi-project
188
+ workspaces. Run with `--ios-shim ./.zmr/ios-shim` or set
189
+ `tools.iosShimPath` in `.zmr/config.json`.
190
+
191
+ If a real iOS run fails with CoreSimulator or Xcode cache errors such as
192
+ `Operation not permitted`, `CoreSimulatorService connection became invalid`, or
193
+ an unexpected workspace/build database error, rerun from a normal terminal or CI
194
+ worker that has access to the user's Xcode, simulator, and DerivedData paths.
195
+ These errors usually mean the host process is sandboxed away from Apple's local
196
+ developer services, not that the scenario JSON is malformed.
197
+ For the generated public iOS demo, `scripts/demo-ios-real.sh --device booted`
198
+ tries available iOS simulators in order when no simulator is already booted.
199
+ This avoids failing the whole demo when one local simulator cannot start
200
+ `launchd_sim`, while still surfacing a setup error if every available simulator
201
+ fails to boot.
202
+
203
+ If a previous Xcode build was interrupted, remove only the app-local ZMR derived
204
+ data path configured for the shim, then rerun the shim once to prewarm it:
205
+
206
+ ```bash
207
+ rm -rf ios/build/ZMRDerivedData
208
+ printf '{"cmd":"appState"}\n' | ./.zmr/ios-shim
209
+ ```
210
+
211
+ Cold shim builds can take several minutes on large apps. Warm runs should use
212
+ the cached `build-for-testing` output and respond much faster.
213
+ `scripts/run-ios-pilot.sh` performs this prewarm automatically when
214
+ `--ios-shim` is set; pass `--skip-shim-prewarm` only when debugging cold-start
215
+ timing.
216
+
217
+ If a freshly booted simulator reports `iOS shim server exited before it became
218
+ ready`, `Early unexpected exit`, or `operation never finished bootstrapping`,
219
+ ZMR retries the shim command once because XCTest can miss its first server
220
+ bootstrap immediately after CoreSimulator startup. Persistent failures after
221
+ that retry should be treated as setup failures: run `xcrun simctl bootstatus
222
+ booted -b`, inspect `.zmr/ios-shim-state/xcodebuild.log`, and prewarm the shim
223
+ with the `appState` command above.
224
+
225
+ ## Trace And Failure Issues
226
+
227
+ When a run fails, do not rerun blindly. Inspect the recorded failure:
228
+
229
+ ```bash
230
+ zmr explain traces/zmr-android
231
+ zmr report traces/zmr-android --out traces/zmr-android/report.html
232
+ ```
233
+
234
+ Timeout diagnostics include the active package/activity, visible text, hidden or
235
+ disabled exact selector candidates, offscreen candidates, and nearest text
236
+ matches from the last snapshot. Redacted bundles replace PNG screenshots with
237
+ placeholder frames and omit screen recordings, so use them for sharing:
238
+
239
+ ```bash
240
+ zmr export traces/zmr-android --out traces/zmr-android-redacted.zmrtrace --redact
241
+ ```
242
+
243
+ ## Release Gate Issues
244
+
245
+ To see exactly what the local release gate will run:
246
+
247
+ ```bash
248
+ ./scripts/release-gate.sh --dry-run
249
+ ```
250
+
251
+ The gate intentionally prints real Android and iOS pilot commands at the end
252
+ instead of running them by default. Those pilots need app builds and devices, so
253
+ run them explicitly before publishing reliability or performance claims. Use
254
+ `zmr-pilot-gate --dry-run` with the same app path flags from an app repo or
255
+ release machine to inspect the combined Android+iOS external gate command
256
+ before starting the real runs.
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "Sample App auth probe",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ {
6
+ "action": "stop"
7
+ },
8
+ {
9
+ "action": "openLink",
10
+ "url": "exampleapp:///e2e-auth?probe=1"
11
+ },
12
+ {
13
+ "action": "waitAny",
14
+ "selectors": [
15
+ {
16
+ "text": "E2E auth probe"
17
+ },
18
+ {
19
+ "text": "Deep link received:"
20
+ },
21
+ {
22
+ "text": "Development servers"
23
+ }
24
+ ],
25
+ "timeoutMs": 60000
26
+ },
27
+ {
28
+ "action": "whenVisible",
29
+ "selector": {
30
+ "text": "Deep link received:"
31
+ },
32
+ "steps": [
33
+ {
34
+ "action": "tap",
35
+ "selector": {
36
+ "contentDescContains": "Sample App Test on"
37
+ },
38
+ "optional": true
39
+ },
40
+ {
41
+ "action": "tap",
42
+ "selector": {
43
+ "contentDesc": "Sample App Test"
44
+ },
45
+ "optional": true
46
+ }
47
+ ]
48
+ },
49
+ {
50
+ "action": "whenVisible",
51
+ "selector": {
52
+ "text": "Development servers"
53
+ },
54
+ "steps": [
55
+ {
56
+ "action": "tap",
57
+ "selector": {
58
+ "contentDescContains": "Sample App Test on"
59
+ },
60
+ "optional": true
61
+ },
62
+ {
63
+ "action": "tap",
64
+ "selector": {
65
+ "contentDesc": "Sample App Test, http://10.0.2.2:8081"
66
+ },
67
+ "optional": true
68
+ },
69
+ {
70
+ "action": "tap",
71
+ "selector": {
72
+ "text": "http://10.0.2.2:8081"
73
+ },
74
+ "optional": true
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ "action": "waitVisible",
80
+ "selector": {
81
+ "text": "E2E auth probe"
82
+ },
83
+ "timeoutMs": 120000
84
+ },
85
+ {
86
+ "action": "snapshot"
87
+ }
88
+ ]
89
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Android app error-state smoke",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "launch" },
6
+ { "action": "openLink", "url": "exampleapp://error-demo?mode=offline" },
7
+ { "action": "waitAny", "selectors": [{ "textContains": "Try again" }, { "textContains": "offline" }, { "textContains": "Something went wrong" }], "timeoutMs": 15000 },
8
+ { "action": "snapshot" },
9
+ { "action": "tap", "selector": { "textContains": "Try again" }, "optional": true },
10
+ { "action": "waitNotVisible", "selector": { "textContains": "Loading" }, "timeoutMs": 10000 },
11
+ { "action": "assertHealthy" }
12
+ ]
13
+ }
@@ -0,0 +1,192 @@
1
+ {
2
+ "name": "Sample App email login and referral smoke",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ {
6
+ "action": "stop"
7
+ },
8
+ {
9
+ "action": "clearState"
10
+ },
11
+ {
12
+ "action": "launch"
13
+ },
14
+ {
15
+ "action": "waitAny",
16
+ "selectors": [
17
+ { "textContains": "Development servers" },
18
+ { "textContains": "Downloading 100%" },
19
+ { "text": "Or sign up via email here" },
20
+ { "text": "Sign in with email" },
21
+ { "textContains": "Dashboard" },
22
+ { "textContains": "Request a feature" },
23
+ { "textContains": "Earn points" },
24
+ { "textContains": "Spend points" },
25
+ { "textContains": "points" }
26
+ ],
27
+ "timeoutMs": 60000
28
+ },
29
+ {
30
+ "action": "whenVisible",
31
+ "selector": { "textContains": "Development servers" },
32
+ "steps": [
33
+ {
34
+ "action": "tap",
35
+ "selector": { "contentDescContains": "Sample App Test on" },
36
+ "optional": true
37
+ },
38
+ {
39
+ "action": "tap",
40
+ "selector": { "contentDesc": "Sample App Test, http://10.0.2.2:8081" },
41
+ "optional": true
42
+ },
43
+ {
44
+ "action": "tap",
45
+ "selector": { "text": "http://10.0.2.2:8081" },
46
+ "optional": true
47
+ },
48
+ {
49
+ "action": "waitNotVisible",
50
+ "selector": { "textContains": "Development servers" },
51
+ "timeoutMs": 60000,
52
+ "optional": true
53
+ }
54
+ ]
55
+ },
56
+ {
57
+ "action": "whenVisible",
58
+ "selector": { "text": "Continue" },
59
+ "timeoutMs": 120000,
60
+ "steps": [
61
+ {
62
+ "action": "tap",
63
+ "selector": { "text": "Continue" }
64
+ },
65
+ {
66
+ "action": "whenVisible",
67
+ "selector": { "textContains": "Connected to:" },
68
+ "steps": [
69
+ {
70
+ "action": "pressBack"
71
+ }
72
+ ]
73
+ }
74
+ ]
75
+ },
76
+ {
77
+ "action": "whenVisible",
78
+ "selector": { "textContains": "Connected to:" },
79
+ "timeoutMs": 10000,
80
+ "steps": [
81
+ {
82
+ "action": "pressBack"
83
+ }
84
+ ]
85
+ },
86
+ {
87
+ "action": "waitAny",
88
+ "selectors": [
89
+ { "id": "email-login-email-input" },
90
+ { "contentDesc": "Open email sign up" },
91
+ { "text": "Or sign up via email here" },
92
+ { "textContains": "Welcome" },
93
+ { "textContains": "Sample landing" },
94
+ { "text": "Sign in with email" },
95
+ { "textContains": "Dashboard" },
96
+ { "textContains": "Request a feature" },
97
+ { "textContains": "Earn points" },
98
+ { "textContains": "Spend points" },
99
+ { "textContains": "points" }
100
+ ],
101
+ "timeoutMs": 60000
102
+ },
103
+ {
104
+ "action": "whenVisible",
105
+ "selector": { "textContains": "Downloading 100%" },
106
+ "steps": [
107
+ {
108
+ "action": "waitNotVisible",
109
+ "selector": { "textContains": "Downloading 100%" },
110
+ "timeoutMs": 180000
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ "action": "whenVisible",
116
+ "selector": { "contentDesc": "Use E2E sign in" },
117
+ "steps": [
118
+ {
119
+ "action": "tap",
120
+ "selector": { "contentDesc": "Use E2E sign in" }
121
+ },
122
+ {
123
+ "action": "waitAny",
124
+ "selectors": [
125
+ { "textContains": "Signing in to your account" },
126
+ { "textContains": "Requesting test token" },
127
+ { "textContains": "Bootstrapping session" },
128
+ { "textContains": "Routing to app" },
129
+ { "textContains": "Dashboard" },
130
+ { "textContains": "Request a feature" },
131
+ { "textContains": "Invite teammates" },
132
+ { "textContains": "Earn points" },
133
+ { "textContains": "Spend points" },
134
+ { "textContains": "points" }
135
+ ],
136
+ "timeoutMs": 45000
137
+ }
138
+ ]
139
+ },
140
+ {
141
+ "action": "waitAny",
142
+ "selectors": [
143
+ { "textContains": "Dashboard" },
144
+ { "textContains": "Request a feature" },
145
+ { "textContains": "Invite teammates" },
146
+ { "textContains": "Earn points" },
147
+ { "textContains": "Spend points" },
148
+ { "textContains": "points" }
149
+ ],
150
+ "timeoutMs": 90000
151
+ },
152
+ {
153
+ "action": "openLink",
154
+ "url": "exampleapp:///referrals/invite"
155
+ },
156
+ {
157
+ "action": "waitAny",
158
+ "selectors": [
159
+ { "textContains": "Invite a teammate and both earn" },
160
+ { "textContains": "Share my link" },
161
+ { "textContains": "Your Referral Code" },
162
+ { "textContains": "No referrals yet" },
163
+ { "text": "Retry" },
164
+ { "textContains": "Request timed out" }
165
+ ],
166
+ "timeoutMs": 20000
167
+ },
168
+ {
169
+ "action": "whenVisible",
170
+ "selector": { "text": "Retry" },
171
+ "steps": [
172
+ {
173
+ "action": "tap",
174
+ "selector": { "text": "Retry" }
175
+ },
176
+ {
177
+ "action": "waitAny",
178
+ "selectors": [
179
+ { "textContains": "Invite a teammate and both earn" },
180
+ { "textContains": "Share my link" },
181
+ { "textContains": "Your Referral Code" },
182
+ { "textContains": "No referrals yet" }
183
+ ],
184
+ "timeoutMs": 60000
185
+ }
186
+ ]
187
+ },
188
+ {
189
+ "action": "snapshot"
190
+ }
191
+ ]
192
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "Android app onboarding smoke",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "clearState" },
6
+ { "action": "launch" },
7
+ { "action": "waitVisible", "selector": { "textContains": "Welcome" }, "timeoutMs": 15000 },
8
+ { "action": "tap", "selector": { "textContains": "Get started" } },
9
+ { "action": "waitAny", "selectors": [{ "textContains": "Home" }, { "textContains": "Sign in" }], "timeoutMs": 15000 },
10
+ { "action": "snapshot" }
11
+ ]
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "Android referral deep link smoke",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "clearState" },
6
+ { "action": "openLink", "url": "exampleapp://invite?code=DEMO-CODE" },
7
+ { "action": "waitVisible", "selector": { "textContains": "Invite" }, "timeoutMs": 15000 },
8
+ { "action": "scrollUntilVisible", "selector": { "id": "invite-card" }, "direction": "down", "timeoutMs": 10000 },
9
+ { "action": "assertVisible", "selector": { "id": "invite-card" } },
10
+ { "action": "snapshot" }
11
+ ]
12
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "ZMR Android shim selector demo",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "launch" },
6
+ {
7
+ "action": "waitVisible",
8
+ "selector": { "text": "Continue" },
9
+ "timeoutMs": 1000
10
+ },
11
+ {
12
+ "action": "tap",
13
+ "selector": { "resourceId": "continue_button" }
14
+ },
15
+ { "action": "typeText", "text": "hello" },
16
+ { "action": "hideKeyboard" },
17
+ { "action": "snapshot" }
18
+ ]
19
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "ZMR fake failure explanation demo",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "launch" },
6
+ {
7
+ "action": "waitVisible",
8
+ "selector": { "text": "Never appears" },
9
+ "timeoutMs": 0
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "ZMR fake Android auth probe demo",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "launch" },
6
+ { "action": "openLink", "url": "exampleapp://e2e-auth?probe=1" },
7
+ {
8
+ "action": "waitVisible",
9
+ "selector": { "text": "E2E auth probe" },
10
+ "timeoutMs": 1000
11
+ },
12
+ { "action": "snapshot" }
13
+ ]
14
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "iOS Expo dev-client open-link smoke",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "stop" },
6
+ {
7
+ "action": "openLink",
8
+ "url": "exp+mobiletest://expo-development-client/?url=http%3A%2F%2F127.0.0.1%3A8081"
9
+ },
10
+ {
11
+ "action": "waitAny",
12
+ "selectors": [
13
+ { "textContains": "Downloading" },
14
+ { "textContains": "Connected to:" },
15
+ { "textContains": "Reload" },
16
+ { "textContains": "Continue" },
17
+ { "textContains": "Sign in" },
18
+ { "textContains": "Home" },
19
+ { "textContains": "Unable to load" }
20
+ ],
21
+ "timeoutMs": 120000
22
+ },
23
+ { "action": "assertHealthy" },
24
+ { "action": "snapshot" }
25
+ ]
26
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "iOS Expo dev-client route snapshot",
3
+ "appId": "com.example.mobiletest",
4
+ "steps": [
5
+ { "action": "stop" },
6
+ {
7
+ "action": "openLink",
8
+ "url": "exampleapp:///settings?mode=manage&source=zmr"
9
+ },
10
+ {
11
+ "action": "waitAny",
12
+ "selectors": [
13
+ { "textContains": "Settings" },
14
+ { "textContains": "Manage" },
15
+ { "textContains": "Home" },
16
+ { "textContains": "Sign in" },
17
+ { "textContains": "Unable to load" }
18
+ ],
19
+ "timeoutMs": 60000
20
+ },
21
+ { "action": "assertHealthy" },
22
+ { "action": "snapshot" }
23
+ ]
24
+ }