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.
- package/CHANGELOG.md +484 -0
- package/CONTRIBUTING.md +42 -0
- package/FEATURES.md +112 -0
- package/LICENSE +21 -0
- package/README.md +255 -0
- package/SECURITY.md +34 -0
- package/build.zig +38 -0
- package/build.zig.zon +7 -0
- package/clients/README.md +144 -0
- package/clients/go/README.md +24 -0
- package/clients/go/examples/fake-session/main.go +93 -0
- package/clients/go/go.mod +3 -0
- package/clients/go/zmr/client.go +432 -0
- package/clients/kotlin/README.md +35 -0
- package/clients/kotlin/build.gradle.kts +35 -0
- package/clients/kotlin/settings.gradle.kts +15 -0
- package/clients/kotlin/src/main/kotlin/dev/zmr/FakeSession.kt +86 -0
- package/clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt +67 -0
- package/clients/python/README.md +29 -0
- package/clients/python/examples/fake_session.py +48 -0
- package/clients/python/pyproject.toml +13 -0
- package/clients/python/zmr_client.py +202 -0
- package/clients/rust/Cargo.lock +107 -0
- package/clients/rust/Cargo.toml +10 -0
- package/clients/rust/README.md +19 -0
- package/clients/rust/examples/fake_session.rs +70 -0
- package/clients/rust/src/lib.rs +461 -0
- package/clients/swift/Package.swift +16 -0
- package/clients/swift/README.md +36 -0
- package/clients/swift/Sources/ZMRClient/ZMRClient.swift +114 -0
- package/clients/swift/Sources/ZMRFakeSession/main.swift +86 -0
- package/clients/typescript/README.md +34 -0
- package/clients/typescript/examples/fake-session.mjs +36 -0
- package/clients/typescript/index.d.ts +144 -0
- package/clients/typescript/index.mjs +192 -0
- package/clients/typescript/package.json +8 -0
- package/docs/adr/0001-agent-native-runner-boundary.md +31 -0
- package/docs/adr/0002-app-local-zmr-contract.md +39 -0
- package/docs/adr/0003-ios-simulator-xctest-shim.md +41 -0
- package/docs/adr/0004-benchmark-claims-and-baseline-collection.md +37 -0
- package/docs/adr/README.md +12 -0
- package/docs/ai-agents.md +156 -0
- package/docs/app-integration.md +316 -0
- package/docs/benchmarking.md +275 -0
- package/docs/client-installation.md +141 -0
- package/docs/clients.md +98 -0
- package/docs/config.md +175 -0
- package/docs/demo.md +259 -0
- package/docs/dsl.md +57 -0
- package/docs/install.md +233 -0
- package/docs/market-positioning.md +70 -0
- package/docs/npm.md +359 -0
- package/docs/protocol-fixtures/README.md +8 -0
- package/docs/protocol-fixtures/core-session.requests.jsonl +8 -0
- package/docs/protocol-fixtures/core-session.responses.jsonl +8 -0
- package/docs/protocol-versioning.md +65 -0
- package/docs/protocol.md +560 -0
- package/docs/publication.md +77 -0
- package/docs/release-audit.md +99 -0
- package/docs/release-candidate.md +111 -0
- package/docs/release-evidence.md +188 -0
- package/docs/release-notes-template.md +58 -0
- package/docs/roadmap.md +334 -0
- package/docs/scenario-authoring.md +88 -0
- package/docs/shipping.md +170 -0
- package/docs/trace-privacy.md +88 -0
- package/docs/troubleshooting.md +256 -0
- package/examples/android-app-auth-probe.json +89 -0
- package/examples/android-app-error-state.json +13 -0
- package/examples/android-app-login-smoke.json +192 -0
- package/examples/android-app-onboarding.json +12 -0
- package/examples/android-app-referral-deep-link.json +12 -0
- package/examples/android-shim-smoke.json +19 -0
- package/examples/demo-failure.json +12 -0
- package/examples/demo-fake.json +14 -0
- package/examples/ios-dev-client-open-link.json +26 -0
- package/examples/ios-dev-client-route-snapshot.json +24 -0
- package/examples/ios-shim-smoke.json +23 -0
- package/examples/ios-smoke.json +9 -0
- package/go.work +3 -0
- package/npm/agents.mjs +183 -0
- package/npm/app-config.mjs +95 -0
- package/npm/build-zmr.mjs +21 -0
- package/npm/commands.mjs +104 -0
- package/npm/generated-files.mjs +50 -0
- package/npm/index.mjs +75 -0
- package/npm/init-app.mjs +80 -0
- package/npm/package-scripts.mjs +72 -0
- package/npm/postinstall.mjs +21 -0
- package/npm/scaffold.mjs +179 -0
- package/npm/scenarios.mjs +93 -0
- package/npm/setup.mjs +69 -0
- package/npm/wizard.mjs +117 -0
- package/npm/zmr.mjs +23 -0
- package/package.json +114 -0
- package/prebuilds/darwin-arm64/zmr +0 -0
- package/prebuilds/darwin-x64/zmr +0 -0
- package/prebuilds/linux-arm64/zmr +0 -0
- package/prebuilds/linux-x64/zmr +0 -0
- package/schemas/README.md +26 -0
- package/schemas/action-result.schema.json +27 -0
- package/schemas/capabilities-output.schema.json +98 -0
- package/schemas/devices-output.schema.json +25 -0
- package/schemas/doctor-output.schema.json +51 -0
- package/schemas/explain-output.schema.json +51 -0
- package/schemas/import-output.schema.json +23 -0
- package/schemas/init-output.schema.json +71 -0
- package/schemas/json-rpc.schema.json +55 -0
- package/schemas/release-manifest.schema.json +43 -0
- package/schemas/release-readiness-output.schema.json +127 -0
- package/schemas/run-output.schema.json +43 -0
- package/schemas/scenario.schema.json +128 -0
- package/schemas/schemas-output.schema.json +26 -0
- package/schemas/semantic-snapshot.schema.json +116 -0
- package/schemas/snapshot.schema.json +60 -0
- package/schemas/trace-event.schema.json +14 -0
- package/schemas/trace-manifest.schema.json +59 -0
- package/schemas/validate-output.schema.json +42 -0
- package/schemas/version-output.schema.json +23 -0
- package/schemas/zmr-config.schema.json +75 -0
- package/scripts/android-emulator.sh +126 -0
- package/scripts/assert-ios-physical-ready.sh +213 -0
- package/scripts/benchmark-command.sh +307 -0
- package/scripts/benchmark.sh +359 -0
- package/scripts/benchmark_gate.py +117 -0
- package/scripts/benchmark_result_row.py +88 -0
- package/scripts/compare-benchmarks.py +288 -0
- package/scripts/create-android-demo-app.sh +342 -0
- package/scripts/create-ios-demo-app.sh +261 -0
- package/scripts/demo-android-real.sh +232 -0
- package/scripts/demo-ios-real.sh +270 -0
- package/scripts/demo.sh +464 -0
- package/scripts/device-matrix.sh +338 -0
- package/scripts/ensure-ios-shim-target.rb +237 -0
- package/scripts/install-android-shim.sh +281 -0
- package/scripts/install-ios-shim.sh +589 -0
- package/scripts/pilot-gate.sh +560 -0
- package/scripts/release-readiness.py +838 -0
- package/scripts/release-readiness.sh +91 -0
- package/scripts/run-android-pilot.sh +561 -0
- package/scripts/run-ios-pilot.sh +509 -0
- package/shims/android/README.md +21 -0
- package/shims/android/ZMRShimInstrumentedTest.java +152 -0
- package/shims/android/protocol.md +18 -0
- package/shims/ios/README.md +50 -0
- package/shims/ios/ZMRShim.swift +110 -0
- package/shims/ios/ZMRShimUITestCase.swift +475 -0
- package/shims/ios/protocol.md +74 -0
- package/skills/zmr-mobile-testing/SKILL.md +127 -0
- package/src/android.zig +344 -0
- package/src/android_device_info.zig +99 -0
- package/src/android_emulator.zig +154 -0
- package/src/android_screen_recording.zig +112 -0
- package/src/android_shell.zig +112 -0
- package/src/bundle.zig +124 -0
- package/src/bundle_redaction.zig +272 -0
- package/src/bundle_tar.zig +123 -0
- package/src/cli_devices.zig +97 -0
- package/src/cli_doctor.zig +114 -0
- package/src/cli_import.zig +70 -0
- package/src/cli_info.zig +39 -0
- package/src/cli_init.zig +72 -0
- package/src/cli_output.zig +467 -0
- package/src/cli_run.zig +259 -0
- package/src/cli_serve.zig +287 -0
- package/src/cli_trace.zig +111 -0
- package/src/cli_validate.zig +41 -0
- package/src/command.zig +211 -0
- package/src/config.zig +305 -0
- package/src/config_diagnostics.zig +212 -0
- package/src/config_paths.zig +49 -0
- package/src/device_registry.zig +37 -0
- package/src/doctor.zig +412 -0
- package/src/doctor_hints.zig +52 -0
- package/src/errors.zig +55 -0
- package/src/fake_device.zig +163 -0
- package/src/health.zig +28 -0
- package/src/importer.zig +343 -0
- package/src/importer_json.zig +100 -0
- package/src/importer_model.zig +103 -0
- package/src/ios.zig +399 -0
- package/src/ios_devices.zig +219 -0
- package/src/ios_lifecycle.zig +72 -0
- package/src/ios_shim.zig +242 -0
- package/src/ios_snapshot.zig +20 -0
- package/src/json_fields.zig +80 -0
- package/src/json_rpc.zig +150 -0
- package/src/json_rpc_methods.zig +318 -0
- package/src/json_rpc_observation.zig +31 -0
- package/src/json_rpc_params.zig +52 -0
- package/src/json_rpc_protocol.zig +110 -0
- package/src/json_rpc_trace.zig +73 -0
- package/src/main.zig +135 -0
- package/src/mcp.zig +234 -0
- package/src/mcp_protocol.zig +64 -0
- package/src/mcp_trace.zig +83 -0
- package/src/report.zig +346 -0
- package/src/report_html.zig +63 -0
- package/src/report_values.zig +27 -0
- package/src/run_options.zig +152 -0
- package/src/runner.zig +280 -0
- package/src/runner_actions.zig +109 -0
- package/src/runner_config.zig +6 -0
- package/src/runner_diagnostics.zig +268 -0
- package/src/runner_events.zig +170 -0
- package/src/runner_native.zig +88 -0
- package/src/runner_waits.zig +300 -0
- package/src/scaffold.zig +472 -0
- package/src/scenario.zig +346 -0
- package/src/scenario_fields.zig +50 -0
- package/src/schema_registry.zig +53 -0
- package/src/selector.zig +84 -0
- package/src/semantic.zig +171 -0
- package/src/trace.zig +315 -0
- package/src/trace_json.zig +340 -0
- package/src/trace_summary.zig +218 -0
- package/src/trace_summary_diagnostic.zig +202 -0
- package/src/types.zig +120 -0
- package/src/uiautomator.zig +164 -0
- package/src/validation.zig +187 -0
- package/src/version.zig +22 -0
- package/viewer/app.js +373 -0
- package/viewer/index.html +126 -0
- package/viewer/parser.js +233 -0
- package/viewer/styles.css +585 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# AI Agent Guide
|
|
2
|
+
|
|
3
|
+
ZMR is built for external agents. The runner provides device state, typed
|
|
4
|
+
actions, waits, assertions, and trace export; the agent decides the next step.
|
|
5
|
+
|
|
6
|
+
## Agent Setup Loop
|
|
7
|
+
|
|
8
|
+
Start inside the app checkout:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
zmr doctor --json --config .zmr/config.json
|
|
12
|
+
zmr validate --json .zmr/android-smoke.json
|
|
13
|
+
zmr validate --json .zmr/ios-smoke.json
|
|
14
|
+
zmr schemas --json
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use `zmr doctor --strict --json` in CI or setup flows that should fail on any
|
|
18
|
+
warning. Prefer JSON output for automation because it includes stable error
|
|
19
|
+
codes, field paths, and remediation hints.
|
|
20
|
+
|
|
21
|
+
## Live JSON-RPC Session
|
|
22
|
+
|
|
23
|
+
Agents should prefer `zmr serve` for interactive work:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
zmr serve --transport stdio --config .zmr/config.json --trace-dir traces/zmr-agent
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Recommended flow:
|
|
30
|
+
|
|
31
|
+
1. Call `runner.capabilities` and check protocol/platform support.
|
|
32
|
+
2. Call `session.create`.
|
|
33
|
+
3. Call `observe.semanticSnapshot` when choosing the next action, or
|
|
34
|
+
`observe.snapshot` when raw adapter details are needed.
|
|
35
|
+
4. Choose one typed action or assertion.
|
|
36
|
+
5. Let ZMR settle, then observe again.
|
|
37
|
+
6. Poll `trace.events` during long runs.
|
|
38
|
+
7. Call `trace.export` with `redact: true` before sharing artifacts.
|
|
39
|
+
8. Call `session.close`.
|
|
40
|
+
|
|
41
|
+
Do not parse screenshots or terminal text when the same fact is available from
|
|
42
|
+
snapshot nodes, action results, CLI JSON, or trace events.
|
|
43
|
+
|
|
44
|
+
If `zmr run --json` returns `status: "partial"`, inspect `partialFailure`.
|
|
45
|
+
For iOS visual captures, `artifactStatus: "captured"` with
|
|
46
|
+
`semanticStatus: "failed"` means screenshot proof exists but accessibility or
|
|
47
|
+
XCTest hierarchy extraction failed. Use `zmr explain --json <trace-dir>` for
|
|
48
|
+
the same diagnostic shape after the run.
|
|
49
|
+
|
|
50
|
+
## MCP Session
|
|
51
|
+
|
|
52
|
+
Agents that support the Model Context Protocol can use ZMR directly as a local
|
|
53
|
+
stdio MCP server:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
zmr mcp --config .zmr/config.json --trace-dir traces/zmr-agent
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The MCP server exposes mobile-specific tools:
|
|
60
|
+
|
|
61
|
+
- `snapshot`: raw ZMR observation JSON
|
|
62
|
+
- `semantic_snapshot`: normalized roles, names, selectors, bounds, and
|
|
63
|
+
recommended actions
|
|
64
|
+
- `tap`, `type`, `press_back`, and `open_link`
|
|
65
|
+
- `wait_visible`
|
|
66
|
+
- `trace_events` and `trace_export`
|
|
67
|
+
|
|
68
|
+
Prefer `semantic_snapshot` for action planning. It avoids forcing an agent to
|
|
69
|
+
infer intent from platform-specific Android/UI Automator or XCTest class names.
|
|
70
|
+
|
|
71
|
+
## Scenario File Workflow
|
|
72
|
+
|
|
73
|
+
For repeatable tests, generate or edit `.zmr/*.json` scenarios:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
zmr validate --json .zmr/login-smoke.json
|
|
77
|
+
zmr run .zmr/login-smoke.json --json --trace-dir traces/zmr-login-smoke
|
|
78
|
+
zmr explain --json traces/zmr-login-smoke
|
|
79
|
+
zmr export traces/zmr-login-smoke --out traces/zmr-login-smoke-redacted.zmrtrace --redact
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Use stable selectors in this order when available:
|
|
83
|
+
|
|
84
|
+
- app accessibility identifiers or resource ids
|
|
85
|
+
- content descriptions or accessibility labels
|
|
86
|
+
- exact visible text for stable product copy
|
|
87
|
+
- `textContains` only when the visible text legitimately varies
|
|
88
|
+
- coordinate actions only as a last resort
|
|
89
|
+
|
|
90
|
+
Use `waitAny` for screens with legitimate branches, and `whenVisible` for
|
|
91
|
+
optional platform or dev-client screens. Keep credentials and app-private data
|
|
92
|
+
in the app repository or environment, not in public scenarios.
|
|
93
|
+
|
|
94
|
+
## Failure Triage
|
|
95
|
+
|
|
96
|
+
When a run fails, inspect:
|
|
97
|
+
|
|
98
|
+
- `zmr run --json` terminal summary
|
|
99
|
+
- `zmr explain --json <trace-dir>`
|
|
100
|
+
- `trace.json`
|
|
101
|
+
- `events.jsonl`
|
|
102
|
+
- the last snapshot JSON
|
|
103
|
+
- the trace viewer report from `zmr report`
|
|
104
|
+
|
|
105
|
+
Selector failures include active app context, visible text, disabled/hidden or
|
|
106
|
+
offscreen exact candidates, and nearest text matches when available. Treat
|
|
107
|
+
those diagnostics as the source of truth before changing a selector.
|
|
108
|
+
|
|
109
|
+
## Benchmarking
|
|
110
|
+
|
|
111
|
+
Use ZMR repeated runs first:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
zmr-benchmark --zmr .zmr/android-smoke.json --platform android --device emulator-5554 --app-id com.example.mobiletest --app-build <build-id-or-artifact> --runs 20 --trace-root traces/zmr-android-reliability --results traces/bench-comparison/results.jsonl --replace --min-pass-rate 100 --max-failures 0
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For a fair comparison with an app-local baseline command, collect normalized
|
|
118
|
+
rows and compare them:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
zmr-benchmark-command --tool baseline --platform android --device emulator-5554 --app-id com.example.mobiletest --scenario .zmr/android-smoke.json --app-build <build-id-or-artifact> --runs 20 --trace-root traces/baseline --results traces/bench-comparison/results.jsonl -- <baseline command>
|
|
122
|
+
zmr-compare-benchmarks --results traces/bench-comparison/results.jsonl --candidate zmr --baseline baseline --min-candidate-pass-rate 100 --max-candidate-failures 0 --min-mean-speedup 1.25 --min-p95-speedup 1.25 --out traces/bench-comparison/comparison.md --evidence-out traces/bench-comparison/evidence.jsonl
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Only publish claims when the candidate and baseline exercise equivalent app
|
|
126
|
+
paths under the same device state. Market-claim evidence must show the same
|
|
127
|
+
benchmark context: `platform`, `device`, `appId`, `scenario`, and `appBuild`.
|
|
128
|
+
It must also include at least 20 candidate rows and at least 20 baseline rows.
|
|
129
|
+
|
|
130
|
+
## Release Claims
|
|
131
|
+
|
|
132
|
+
Before saying a release, production rollout, or market comparison is ready,
|
|
133
|
+
evaluate the collected evidence:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
zmr-release-readiness --json \
|
|
137
|
+
--evidence traces/release-candidate/<run>/evidence.jsonl \
|
|
138
|
+
--target dev-preview
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Use `satisfied` for proven requirements and `blocked`, `missing`,
|
|
142
|
+
`insufficient`, `failed`, and `planned` for remaining work. Use
|
|
143
|
+
`recommendedWording` for the human-facing status and keep
|
|
144
|
+
`claimLimitations` intact; never upgrade a dev-preview result into a
|
|
145
|
+
production-stable or competitive claim. When blocked, run
|
|
146
|
+
`nextSteps[].commands` in order and use `nextSteps[].covers` to map each
|
|
147
|
+
command back to the blocked requirements it resolves.
|
|
148
|
+
|
|
149
|
+
## Safety Rules
|
|
150
|
+
|
|
151
|
+
- Run `tests/public-safety-test.sh` before publishing docs, examples, or traces.
|
|
152
|
+
- Do not commit app-private traces, screenshots, credentials, tokens, bundle
|
|
153
|
+
identifiers, or private app names.
|
|
154
|
+
- Prefer `zmr export --redact`; add `--omit-screenshots` for public bundles
|
|
155
|
+
when visual artifacts may contain sensitive data.
|
|
156
|
+
- Keep app-local state under `.zmr/` and generated run output under `traces/`.
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# App Integration
|
|
2
|
+
|
|
3
|
+
ZMR is intentionally a separate runner. A mobile app repo does not need to vendor ZMR, but it should expose a small, stable test surface so agents can drive the app deterministically.
|
|
4
|
+
|
|
5
|
+
Most app teams should install ZMR as a dev dependency:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --save-dev zig-mobile-runner
|
|
9
|
+
npx zmr-wizard --app-id com.example.mobiletest --package-json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
That keeps scenarios and app scripts in the app repo while the runner remains versioned through npm.
|
|
13
|
+
For Expo development builds, add `--expo-dev-client-scheme <scheme>` to scaffold
|
|
14
|
+
Android and iOS open-link smoke scenarios that load Metro before selector
|
|
15
|
+
assertions run.
|
|
16
|
+
|
|
17
|
+
## What The App Provides
|
|
18
|
+
|
|
19
|
+
For Android:
|
|
20
|
+
|
|
21
|
+
- A debug/test APK.
|
|
22
|
+
- A stable application id, for example `com.example.mobiletest`.
|
|
23
|
+
- Optional deep links for direct navigation into test states.
|
|
24
|
+
- Accessibility labels, text, or resource ids for important controls.
|
|
25
|
+
- A test server or local dev server when the app requires one.
|
|
26
|
+
- Optional Android instrumentation shim command for faster hierarchy and
|
|
27
|
+
selector-grade actions.
|
|
28
|
+
|
|
29
|
+
Create the app-local Android shim command from the ZMR package or checkout:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx zmr-install-android-shim \
|
|
33
|
+
--app-root . \
|
|
34
|
+
--test-package com.example.mobiletest.test \
|
|
35
|
+
--runner androidx.test.runner.AndroidJUnitRunner \
|
|
36
|
+
--android-module android/app \
|
|
37
|
+
--gradle-file android/app/build.gradle
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
With `--android-module`, the installer copies the shim into the app module's
|
|
41
|
+
standard `src/androidTest/java/dev/zmr/shim/` tree. With `--gradle-file`, it
|
|
42
|
+
appends guarded Gradle blocks once for `testInstrumentationRunner` and AndroidX
|
|
43
|
+
Test/UI Automator dependencies. If the Gradle file already declares a custom
|
|
44
|
+
`testInstrumentationRunner` and `--runner` is omitted, the generated shim command
|
|
45
|
+
uses the existing runner. Omit those flags when you prefer to wire source and
|
|
46
|
+
dependencies yourself from the generated `.zmr/ZMRShimInstrumentedTest.java`.
|
|
47
|
+
The generated
|
|
48
|
+
`.zmr/android-shim` executable is the value to pass to `--android-shim` or
|
|
49
|
+
`tools.androidShimPath`.
|
|
50
|
+
|
|
51
|
+
For iOS:
|
|
52
|
+
|
|
53
|
+
- A simulator `.app` build.
|
|
54
|
+
- A stable bundle id, for example `com.example.mobiletest`.
|
|
55
|
+
- Optional deep links for direct navigation into test states.
|
|
56
|
+
- Accessibility labels for important controls.
|
|
57
|
+
- Optional simulator XCTest/XCUIAutomation shim command for hierarchy and
|
|
58
|
+
selector-grade actions.
|
|
59
|
+
|
|
60
|
+
Create the app-local shim command from the ZMR package or checkout:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx zmr-install-ios-shim \
|
|
64
|
+
--app-root . \
|
|
65
|
+
--scheme SampleUITests \
|
|
66
|
+
--test-target SampleUITests \
|
|
67
|
+
--workspace ios/Sample.xcworkspace \
|
|
68
|
+
--app-target SampleApp \
|
|
69
|
+
--derived-data-path ios/build/ZMRDerivedData \
|
|
70
|
+
--bundle-id com.example.mobiletest \
|
|
71
|
+
--patch-xcodeproj
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Run `.zmr/ensure-ios-shim-target.sh` to create/update the UI test target, add
|
|
75
|
+
the generated `.zmr/ZMRShimUITestCase.swift` and
|
|
76
|
+
`.zmr/shims/ios/ZMRShim.swift` files, configure
|
|
77
|
+
`.zmr/ZMRShimUITests-Info.plist`, and write a shared scheme. The helper uses the
|
|
78
|
+
Ruby `xcodeproj` gem. With `--workspace`, it resolves the referenced
|
|
79
|
+
`.xcodeproj` automatically when there is one project, or when exactly one
|
|
80
|
+
project contains `--app-target`, or when `--bundle-id` disambiguates matching
|
|
81
|
+
app targets. Pass `--project ios/Sample.xcodeproj` explicitly for
|
|
82
|
+
still-ambiguous multi-project workspaces or project-only apps.
|
|
83
|
+
|
|
84
|
+
The generated `.zmr/ios-shim` executable is written into
|
|
85
|
+
`tools.iosShimPath` in `.zmr/config.json`, and can still be passed explicitly
|
|
86
|
+
with `--ios-shim`. It caches `build-for-testing` output and uses
|
|
87
|
+
`test-without-building` for selector commands through `.zmr/ios-shim-state/`.
|
|
88
|
+
Set `ZMR_IOS_SHIM_FORCE_REBUILD=1` after app-side target changes, or
|
|
89
|
+
`ZMR_IOS_SHIM_ONESHOT=1` when you need to debug the slower cold-start path.
|
|
90
|
+
|
|
91
|
+
## Recommended App Repo Layout
|
|
92
|
+
|
|
93
|
+
The exact layout is app-specific, but this shape works well:
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
mobile-app/
|
|
97
|
+
android/app/build/outputs/apk/debug/app-debug.apk
|
|
98
|
+
build/Debug-iphonesimulator/Sample.app
|
|
99
|
+
.zmr/
|
|
100
|
+
config.json
|
|
101
|
+
android-auth-probe.json
|
|
102
|
+
android-login-smoke.json
|
|
103
|
+
ios-smoke.json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Keep app-owned scenarios and ZMR defaults in `.zmr/` when they are app-specific. Keep generic examples in the ZMR repo. ZMR auto-discovers `.zmr/config.json` from the app repo; explicit CLI flags still override config defaults.
|
|
107
|
+
|
|
108
|
+
## Android App Pilot Command
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
/path/to/zig-mobile-runner/scripts/run-android-pilot.sh \
|
|
112
|
+
--app-root /path/to/mobile-app \
|
|
113
|
+
--app-id com.example.mobiletest \
|
|
114
|
+
--device emulator-5554
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Use a saved emulator snapshot for repeatability:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
/path/to/zig-mobile-runner/scripts/run-android-pilot.sh \
|
|
121
|
+
--app-root /path/to/mobile-app \
|
|
122
|
+
--app-id com.example.mobiletest \
|
|
123
|
+
--device emulator-5554 \
|
|
124
|
+
--avd Small_Phone \
|
|
125
|
+
--reset-emulator \
|
|
126
|
+
--restore-snapshot zmr-clean \
|
|
127
|
+
--screen-record
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`--screen-record` writes `screenrecord.mp4` under the pilot trace root. For
|
|
131
|
+
direct traced runs, use `zmr run --android-avd Small_Phone
|
|
132
|
+
--create-avd-if-missing --avd-system-image
|
|
133
|
+
'system-images;android-35;google_apis;arm64-v8a' --avd-device pixel_6
|
|
134
|
+
--restore-snapshot zmr-clean --wait-emulator --screen-record`, or set the
|
|
135
|
+
equivalent `android.avdName`, `android.createAvdIfMissing`,
|
|
136
|
+
`android.avdSystemImage`, `android.avdDeviceProfile`,
|
|
137
|
+
`android.restoreSnapshot`, `android.waitReady`, and
|
|
138
|
+
`artifacts.screenRecording` values in `.zmr/config.json`. Treat recordings like
|
|
139
|
+
screenshots: keep them local or share only when the app state is safe.
|
|
140
|
+
|
|
141
|
+
The Android wrapper expects the default APK path under the app root. Override it when needed:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
/path/to/zig-mobile-runner/scripts/run-android-pilot.sh \
|
|
145
|
+
--app-root /path/to/mobile-app \
|
|
146
|
+
--apk /path/to/app-debug.apk \
|
|
147
|
+
--device emulator-5554
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Public Android Demo Command
|
|
151
|
+
|
|
152
|
+
For a generic public Android app:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npx zmr-demo-android --out /tmp/zmr-android-demo --device emulator-5554 --avd <avd-name>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
This writes a signed debug APK plus `.zmr/android-smoke.json` without Gradle or
|
|
159
|
+
network access, then installs and runs it on the requested Android target. For
|
|
160
|
+
manual inspection or customization:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npx zmr-create-android-demo-app --out /tmp/zmr-android-demo
|
|
164
|
+
adb install -r /tmp/zmr-android-demo/build/app-debug.apk
|
|
165
|
+
/path/to/zig-mobile-runner/zig-out/bin/zmr run /tmp/zmr-android-demo/.zmr/android-smoke.json \
|
|
166
|
+
--device emulator-5554 \
|
|
167
|
+
--app-id com.example.mobiletest \
|
|
168
|
+
--trace-dir /tmp/zmr-android-demo/traces/android-demo
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Use this path to prove local Android install, launch, selector action, typing,
|
|
172
|
+
snapshot, and trace capture before wiring ZMR into a private app.
|
|
173
|
+
|
|
174
|
+
## iOS Demo Command
|
|
175
|
+
|
|
176
|
+
For a generic public demo app with the shim already installed:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
npx zmr-demo-ios --out /tmp/zmr-ios-demo --device booted
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
That command creates the demo app, boots an available simulator when needed,
|
|
183
|
+
builds it, runs the iOS pilot, and writes redacted trace bundles. To inspect or
|
|
184
|
+
customize the generated app before running the pilot manually:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npx zmr-create-ios-demo-app --out /tmp/zmr-ios-demo
|
|
188
|
+
cd /tmp/zmr-ios-demo
|
|
189
|
+
xcodebuild -project ios/ZMRDemo.xcodeproj -scheme ZMRDemo -destination 'generic/platform=iOS Simulator' -derivedDataPath DerivedData build
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Then boot a simulator and run:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
/path/to/zig-mobile-runner/scripts/run-ios-pilot.sh \
|
|
196
|
+
--app-root /tmp/zmr-ios-demo \
|
|
197
|
+
--app-path /tmp/zmr-ios-demo/DerivedData/Build/Products/Debug-iphonesimulator/ZMRDemo.app \
|
|
198
|
+
--app-id com.example.mobiletest \
|
|
199
|
+
--device booted \
|
|
200
|
+
--ios-shim /tmp/zmr-ios-demo/.zmr/ios-shim
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Build the app for an iOS simulator, boot a simulator, then run:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
/path/to/zig-mobile-runner/scripts/run-ios-pilot.sh \
|
|
207
|
+
--app-root /path/to/mobile-app \
|
|
208
|
+
--app-path /path/to/mobile-app/build/Debug-iphonesimulator/Sample.app \
|
|
209
|
+
--app-id com.example.mobiletest \
|
|
210
|
+
--device booted \
|
|
211
|
+
--ios-shim /path/to/mobile-app/.zmr/ios-shim
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Without `--ios-shim`, the iOS path is a smoke demo: install, launch/open-link,
|
|
215
|
+
screenshot, logs, trace, report, and redacted export. With `--ios-shim`, ZMR
|
|
216
|
+
also runs `examples/ios-shim-smoke.json`, producing a second report and
|
|
217
|
+
redacted bundle for selector-grade native waits, tap, type, and bounded
|
|
218
|
+
snapshot actions. If a selector wait times out, ZMR records a final XCTest
|
|
219
|
+
snapshot when possible so reports and agents can see the active app context,
|
|
220
|
+
visible labels, hidden/disabled/offscreen candidates, and nearest text matches.
|
|
221
|
+
When the app is already running, ZMR uses the shim `appState` response as an
|
|
222
|
+
idempotent launch confirmation if `simctl launch` itself returns an error.
|
|
223
|
+
|
|
224
|
+
On iOS simulators, `clearState` means best-effort app uninstall by bundle id.
|
|
225
|
+
For physical iOS devices, lifecycle commands go through `devicectl` and
|
|
226
|
+
selector commands go through the same app-local XCTest shim, subject to signing,
|
|
227
|
+
provisioning, Developer Mode, and local Xcode availability. Screenshot
|
|
228
|
+
artifacts use the XCTest shim; log artifact capture is simulator-first in this
|
|
229
|
+
release.
|
|
230
|
+
Use a simulator-built `iphonesimulator` `.app` for simulator runs. A signed
|
|
231
|
+
device `.ipa` must be run with `--ios-device-type physical`; the pilot wrapper
|
|
232
|
+
rejects device IPAs on simulator runs before installing anything.
|
|
233
|
+
Use `--ios-device-type physical` with a concrete device identifier from
|
|
234
|
+
`zmr devices` for physical pilot runs:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
/path/to/zig-mobile-runner/scripts/run-ios-pilot.sh \
|
|
238
|
+
--app-root /path/to/mobile-app \
|
|
239
|
+
--app-path /path/to/mobile-app/build/Release-iphoneos/Sample.ipa \
|
|
240
|
+
--ios-device-type physical \
|
|
241
|
+
--device <physical-device-id> \
|
|
242
|
+
--ios-shim /path/to/mobile-app/.zmr/ios-shim \
|
|
243
|
+
--runs 20 \
|
|
244
|
+
--min-pass-rate 100 \
|
|
245
|
+
--max-failures 0
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
If the app is already missing, ZMR treats the simulator as clean and continues.
|
|
249
|
+
Install the simulator `.app` again before launch/open-link steps that need it.
|
|
250
|
+
|
|
251
|
+
## Direct CLI Use
|
|
252
|
+
|
|
253
|
+
Android:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
zmr run .zmr/android-auth-probe.json \
|
|
257
|
+
--device emulator-5554 \
|
|
258
|
+
--app-id com.example.mobiletest \
|
|
259
|
+
--android-shim ./.zmr/android-shim \
|
|
260
|
+
--trace-dir traces/android-auth
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Or use app-local defaults:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
zmr run --config .zmr/config.json
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
iOS:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
xcrun simctl install booted /path/to/Sample.app
|
|
273
|
+
zmr run .zmr/ios-shim-smoke.json \
|
|
274
|
+
--platform ios \
|
|
275
|
+
--device booted \
|
|
276
|
+
--app-id com.example.mobiletest \
|
|
277
|
+
--ios-shim ./.zmr/ios-shim \
|
|
278
|
+
--trace-dir traces/ios-smoke
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Agent JSON-RPC Use
|
|
282
|
+
|
|
283
|
+
Start a local server next to the device. App repos scaffolded by
|
|
284
|
+
`zmr-wizard --package-json` can use the generated scripts:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
npm run zmr:serve
|
|
288
|
+
npm run zmr:mcp
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
External agents can call:
|
|
292
|
+
|
|
293
|
+
- `runner.capabilities`
|
|
294
|
+
- `session.create`
|
|
295
|
+
- `app.launch`
|
|
296
|
+
- `app.openLink`
|
|
297
|
+
- `observe.snapshot`
|
|
298
|
+
- `observe.semanticSnapshot`
|
|
299
|
+
- `ui.tap`
|
|
300
|
+
- `wait.until`
|
|
301
|
+
- `assert.visible`
|
|
302
|
+
- `trace.export`
|
|
303
|
+
|
|
304
|
+
Use `observe.semanticSnapshot` before choosing actions, and use
|
|
305
|
+
`observe.snapshot` when raw adapter details are needed. Every action should
|
|
306
|
+
settle and observe again. Scenario runs call the adapter-level settle hook after
|
|
307
|
+
mutating actions; native shims can wait for platform idle while shell-only paths
|
|
308
|
+
keep a bounded sleep fallback. Start `serve` with `--trace-dir` so
|
|
309
|
+
`trace.export` can produce a redacted `.zmrtrace` bundle for the whole agent
|
|
310
|
+
session.
|
|
311
|
+
|
|
312
|
+
## Public Artifact Rules
|
|
313
|
+
|
|
314
|
+
- Share `*-redacted.zmrtrace` bundles.
|
|
315
|
+
- Do not publish raw Metro logs, simulator logs, or unredacted screenshot bundles from private apps.
|
|
316
|
+
- Run `bash tests/public-safety-test.sh` before publishing this repo.
|