zeno-mobile-runner 0.1.3 → 0.2.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 +192 -2
- package/FEATURES.md +50 -7
- package/README.md +168 -120
- package/build.zig.zon +3 -3
- package/clients/README.md +60 -3
- package/clients/go/README.md +12 -0
- package/clients/go/zmr/client.go +142 -0
- package/clients/kotlin/README.md +18 -1
- package/clients/kotlin/build.gradle.kts +1 -1
- package/clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt +76 -1
- package/clients/python/README.md +19 -0
- package/clients/python/pyproject.toml +1 -1
- package/clients/python/zmr_client.py +33 -0
- package/clients/rust/Cargo.lock +1 -1
- package/clients/rust/Cargo.toml +1 -1
- package/clients/rust/README.md +25 -1
- package/clients/rust/src/lib.rs +201 -0
- package/clients/swift/README.md +18 -0
- package/clients/swift/Sources/ZMRClient/ZMRClient.swift +82 -0
- package/clients/typescript/README.md +16 -0
- package/clients/typescript/index.d.ts +12 -0
- package/clients/typescript/index.mjs +16 -0
- package/clients/typescript/package.json +1 -1
- package/docs/agent-discovery.md +151 -22
- package/docs/ai-agents.md +99 -11
- package/docs/benchmarking.md +49 -3
- package/docs/benchmarks/2026-06-09-android-workflow.md +73 -0
- package/docs/benchmarks/2026-06-09-android-workflow.results.jsonl +20 -0
- package/docs/benchmarks/2026-06-09-framework-baseline-status.md +32 -0
- package/docs/benchmarks/2026-06-09-ios-appium-comparison.md +115 -0
- package/docs/benchmarks/2026-06-09-ios-appium-comparison.results.jsonl +40 -0
- package/docs/benchmarks/2026-06-09-ios-demo.md +90 -0
- package/docs/benchmarks/2026-06-09-ios-demo.results.jsonl +20 -0
- package/docs/benchmarks/2026-06-09-ios-maestro-comparison.md +128 -0
- package/docs/benchmarks/2026-06-09-ios-maestro-comparison.results.jsonl +40 -0
- package/docs/benchmarks/2026-06-09-ios-workflow-comparison.md +143 -0
- package/docs/benchmarks/2026-06-09-ios-workflow-comparison.results.jsonl +40 -0
- package/docs/benchmarks/2026-06-09-ios-xctest-floor.md +106 -0
- package/docs/benchmarks/2026-06-09-ios-xctest-floor.results.jsonl +40 -0
- package/docs/benchmarks/README.md +36 -0
- package/docs/benchmarks/benchmark-lab-v1.json +155 -0
- package/docs/benchmarks/benchmark-lab-v1.md +95 -0
- package/docs/clients.md +26 -6
- package/docs/demo.md +40 -1
- package/docs/expo-smoke.md +8 -8
- package/docs/frameworks.md +10 -0
- package/docs/install.md +3 -2
- package/docs/npm.md +100 -4
- package/docs/production-readiness.md +123 -0
- package/docs/protocol-fixtures/core-session.responses.jsonl +1 -1
- package/docs/protocol.md +215 -16
- package/docs/scenario-authoring.md +18 -0
- package/docs/trace-privacy.md +9 -0
- package/docs/troubleshooting.md +7 -1
- package/examples/android-workflow.json +79 -0
- package/examples/ios-shim-workflow.json +79 -0
- package/examples/react-native-expo-workflow.json +75 -0
- package/npm/agents.mjs +16 -0
- package/npm/commands.mjs +9 -5
- package/package.json +6 -1
- 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 +4 -0
- package/schemas/discover-output.schema.json +83 -0
- package/schemas/draft-output.schema.json +58 -0
- package/schemas/explore-output.schema.json +94 -0
- package/schemas/inspect-output.schema.json +88 -0
- package/schemas/run-output.schema.json +2 -0
- package/scripts/benchmark-lab.py +253 -0
- package/scripts/create-android-demo-app.sh +324 -29
- package/scripts/create-ios-demo-app.sh +174 -7
- package/scripts/create-react-native-expo-demo-app.sh +727 -0
- package/scripts/demo.sh +3 -0
- package/scripts/install-ios-shim.sh +2 -2
- package/scripts/release-readiness.py +43 -0
- package/scripts/run-android-pilot.sh +35 -9
- package/scripts/run-ios-pilot.sh +11 -4
- package/shims/ios/ZMRShim.swift +10 -0
- package/shims/ios/ZMRShimUITestCase.swift +42 -0
- package/shims/ios/protocol.md +1 -0
- package/skills/zmr-mobile-testing/SKILL.md +28 -3
- package/src/cli_discover.zig +239 -0
- package/src/cli_draft.zig +924 -0
- package/src/cli_explore.zig +136 -0
- package/src/cli_import.zig +31 -15
- package/src/cli_inspect.zig +310 -0
- package/src/cli_output.zig +26 -2
- package/src/cli_run.zig +28 -0
- package/src/cli_trace.zig +45 -15
- package/src/cli_validate.zig +12 -6
- package/src/errors.zig +9 -0
- package/src/ios.zig +49 -12
- package/src/ios_shim.zig +36 -2
- package/src/json_rpc_methods.zig +85 -11
- package/src/json_rpc_params.zig +8 -0
- package/src/json_rpc_protocol.zig +1 -1
- package/src/json_rpc_trace.zig +112 -0
- package/src/main.zig +27 -2
- package/src/mcp.zig +209 -6
- package/src/mcp_protocol.zig +29 -1
- package/src/mcp_trace.zig +126 -4
- package/src/report.zig +186 -0
- package/src/runner.zig +26 -4
- package/src/runner_actions.zig +10 -0
- package/src/runner_diagnostics.zig +31 -1
- package/src/runner_events.zig +70 -7
- package/src/runner_native.zig +17 -1
- package/src/runner_waits.zig +82 -19
- package/src/scaffold.zig +28 -12
- package/src/scenario.zig +32 -4
- package/src/schema_registry.zig +4 -0
- package/src/version.zig +1 -1
- package/viewer/app.js +23 -3
package/docs/protocol.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
ZMR exposes newline-delimited JSON-RPC 2.0 over stdio or localhost TCP in v1. Each request is one JSON object followed by `\n`. Each response is one JSON object followed by `\n`.
|
|
4
4
|
|
|
5
|
-
Current runner version: `0.
|
|
5
|
+
Current runner version: `0.2.0`.
|
|
6
6
|
|
|
7
7
|
Current protocol version: `2026-04-28`.
|
|
8
8
|
|
|
@@ -24,6 +24,10 @@ Public schemas:
|
|
|
24
24
|
- `schemas/capabilities-output.schema.json`
|
|
25
25
|
- `schemas/explain-output.schema.json`
|
|
26
26
|
- `schemas/run-output.schema.json`
|
|
27
|
+
- `schemas/inspect-output.schema.json`
|
|
28
|
+
- `schemas/discover-output.schema.json`
|
|
29
|
+
- `schemas/explore-output.schema.json`
|
|
30
|
+
- `schemas/draft-output.schema.json`
|
|
27
31
|
- `schemas/release-manifest.schema.json`
|
|
28
32
|
- `schemas/release-readiness-output.schema.json`
|
|
29
33
|
- `schemas/schemas-output.schema.json`
|
|
@@ -36,12 +40,74 @@ methods.
|
|
|
36
40
|
form for setup scripts, generated clients, and editor integrations. The
|
|
37
41
|
response is covered by `schemas/schemas-output.schema.json`.
|
|
38
42
|
|
|
43
|
+
`zmr inspect --json` returns a read-only app handoff for humans and agents. It
|
|
44
|
+
reports the app root, config and `.zmr/AGENTS.md` presence, configured Android
|
|
45
|
+
and iOS smoke scenarios, safe next commands, claim limits, and current runner
|
|
46
|
+
and protocol versions. The response is covered by
|
|
47
|
+
`schemas/inspect-output.schema.json`:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{"ok":true,"status":"ready","schemaVersion":1,"runnerVersion":"0.2.0","protocolVersion":"2026-04-28","dir":".","configPath":".zmr/config.json","configExists":true,"agentInstructionsPath":".zmr/AGENTS.md","agentInstructionsExists":true,"platforms":[{"name":"android","enabled":true,"defaultDevice":"emulator-5554","smokeScenario":".zmr/android-smoke.json","smokeScenarioExists":true,"traceDir":"traces/zmr-android"},{"name":"ios","enabled":true,"defaultDevice":"booted","smokeScenario":".zmr/ios-smoke.json","smokeScenarioExists":true,"traceDir":"traces/zmr-ios"}],"recommendedCommands":["zmr doctor --strict --json --config .zmr/config.json","zmr schemas --json","zmr validate --json .zmr/android-smoke.json","zmr validate --json .zmr/ios-smoke.json","zmr serve --transport stdio --config .zmr/config.json --trace-dir traces/zmr-agent","zmr mcp --config .zmr/config.json --trace-dir traces/zmr-agent"],"claimsPolicy":["verify runs with trace evidence before making readiness claims","do not claim Flutter widget-tree inspection"],"limitations":["inspect is read-only and does not launch devices","autonomous crawling is not shipped; generate or edit scenarios for human review"]}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`zmr discover --from-trace <trace-dir> --out <scenario.json> --validate --json`
|
|
54
|
+
is the public trace-to-test handoff for agents. It reads the trace manifest and
|
|
55
|
+
latest snapshot artifact, writes a reviewable scenario, and optionally validates
|
|
56
|
+
that generated scenario before returning. With `--include-actions`, it replays
|
|
57
|
+
only successful supported trace actions that contain stable replay data. It is
|
|
58
|
+
offline and review-first: it does not start a device session, crawl the app,
|
|
59
|
+
invent credentials, or commit files. The response is covered by
|
|
60
|
+
`schemas/discover-output.schema.json`:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{"ok":true,"mode":"discover","schemaVersion":1,"runnerVersion":"0.2.0","protocolVersion":"2026-04-28","out":".zmr/discovered/replay-smoke.json","traceDir":"traces/zmr-agent","sourceSnapshot":"traces/zmr-agent/artifacts/snapshot-2.json","name":"draft from login smoke","appId":"com.example.mobiletest","selectorCount":2,"stepCount":6,"replay":{"enabled":true,"eventCount":4,"stepCount":3,"skippedEventCount":1},"warnings":["draft requires human review before commit"],"validated":true,"validation":{"ok":true,"path":".zmr/discovered/replay-smoke.json","name":"draft from login smoke","appId":"com.example.mobiletest","stepCount":6},"nextCommands":["zmr validate --json .zmr/discovered/replay-smoke.json","zmr run .zmr/discovered/replay-smoke.json --json --trace-dir traces/zmr-agent"]}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`zmr explore --from-trace <trace-dir> --out <scenario.json> --goal <goal>
|
|
67
|
+
--include-actions --validate --json` is the review-first exploration handoff
|
|
68
|
+
for CLI agents. It uses the same trace-backed scenario writer as `discover`,
|
|
69
|
+
but carries the agent goal and explicit guardrails in the response. It does not
|
|
70
|
+
launch devices, crawl the app, invent missing actions, discover credentials, or
|
|
71
|
+
commit files. The response is covered by `schemas/explore-output.schema.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{"ok":true,"mode":"explore","schemaVersion":1,"runnerVersion":"0.2.0","protocolVersion":"2026-04-28","goal":"find a stable login smoke","autonomous":false,"reviewRequired":true,"guardrails":["writes from existing trace evidence only","does not crawl the app","does not discover credentials or secrets","requires human review before commit"],"out":".zmr/discovered/login-smoke.json","traceDir":"traces/zmr-agent","sourceSnapshot":"traces/zmr-agent/artifacts/snapshot-2.json","name":"draft from login smoke","appId":"com.example.mobiletest","selectorCount":2,"stepCount":6,"replay":{"enabled":true,"eventCount":4,"stepCount":3,"skippedEventCount":1},"warnings":["draft requires human review before commit"],"validated":true,"validation":{"ok":true,"path":".zmr/discovered/login-smoke.json","name":"draft from login smoke","appId":"com.example.mobiletest","stepCount":6},"nextCommands":["zmr validate --json .zmr/discovered/login-smoke.json","zmr run .zmr/discovered/login-smoke.json --json --trace-dir traces/zmr-agent"]}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`zmr draft --from-trace <trace-dir> --out <scenario.json> --json` is the lower
|
|
78
|
+
level scenario-writing primitive used by `discover`. It reads the
|
|
79
|
+
trace manifest and latest semantic snapshot artifact, then writes a reviewable
|
|
80
|
+
surface-smoke scenario. The generated scenario starts with `launch` and
|
|
81
|
+
`snapshot`, then adds `assertVisible` steps for a small set of visible stable
|
|
82
|
+
selectors. It does not start a device session, crawl the app, tap controls, type
|
|
83
|
+
into fields, or commit files. The response is covered by
|
|
84
|
+
`schemas/draft-output.schema.json`:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{"ok":true,"mode":"draft","schemaVersion":1,"runnerVersion":"0.2.0","protocolVersion":"2026-04-28","out":".zmr/discovered/surface-smoke.json","traceDir":"traces/zmr-agent","sourceSnapshot":"traces/zmr-agent/artifacts/snapshot-2.json","name":"draft from login smoke","appId":"com.example.mobiletest","selectorCount":2,"stepCount":4,"replay":{"enabled":false,"eventCount":0,"stepCount":0,"skippedEventCount":0},"warnings":["draft requires human review before commit"],"nextCommands":["zmr validate --json .zmr/discovered/surface-smoke.json","zmr run .zmr/discovered/surface-smoke.json --json --trace-dir traces/zmr-agent"]}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`zmr draft --include-actions` additionally parses `events.jsonl` and prepends
|
|
91
|
+
successful supported replay steps before the final snapshot assertions. Replay
|
|
92
|
+
drafts currently include app launch, deep links, selector taps, selector text
|
|
93
|
+
entry, selector erase, selector/timeout-preserving visible/not-visible waits,
|
|
94
|
+
matched wait-any events as `waitVisible`, back, keyboard hiding,
|
|
95
|
+
coordinate-complete swipes, direction/timeout-preserving selector scrolls, and
|
|
96
|
+
selector/timeout-preserving `assertVisible` and `assertNotVisible`,
|
|
97
|
+
`assertNoneVisible` selector arrays plus timed `assertHealthy` checks. Events
|
|
98
|
+
without enough replay data, failed events, diagnostics, underspecified swipes,
|
|
99
|
+
and control events are skipped with warnings rather than guessed. Text entry
|
|
100
|
+
events redacted from the trace are skipped.
|
|
101
|
+
The `replay` object in draft and discover JSON reports whether action replay
|
|
102
|
+
was enabled, how many trace action events were considered, how many replay
|
|
103
|
+
steps were generated, and how many events were skipped.
|
|
104
|
+
|
|
39
105
|
`zmr-release-readiness --json` checks one or more repeated app/device evidence
|
|
40
106
|
files and emits a machine-readable readiness summary. The output is covered by
|
|
41
107
|
`schemas/release-readiness-output.schema.json`:
|
|
42
108
|
|
|
43
109
|
```json
|
|
44
|
-
{"ok":false,"target":"production","status":"blocked","evidence":"traces/zmr-pilots/evidence.jsonl","evidenceFiles":["traces/zmr-pilots/evidence.jsonl"],"passed":["Android emulator
|
|
110
|
+
{"ok":false,"target":"production","status":"blocked","evidence":"traces/zmr-pilots/evidence.jsonl","evidenceFiles":["traces/zmr-pilots/evidence.jsonl"],"passed":["local release gate","public Android emulator demo","public iOS simulator demo"],"satisfied":["local release gate","public Android demo","public iOS simulator demo","agent workflow smoke"],"failed":[],"planned":[],"missing":["physical iOS readiness","Android hardware pilot","iOS simulator hardware pilot","iOS physical hardware pilot"],"insufficient":[],"blocked":["physical iOS readiness","Android hardware pilot","iOS simulator hardware pilot","iOS physical hardware pilot"],"requirements":[{"name":"local release gate","status":"satisfied","evidenceName":"local release gate"},{"name":"public Android demo","status":"satisfied","evidenceName":"public Android emulator demo"},{"name":"public iOS simulator demo","status":"satisfied","evidenceName":"public iOS simulator demo"},{"name":"agent workflow smoke","status":"satisfied","evidenceName":"local release gate"},{"name":"physical iOS readiness","status":"missing","reason":"no matching passed evidence row"},{"name":"Android hardware pilot","status":"missing","reason":"no matching passed evidence row"},{"name":"iOS simulator hardware pilot","status":"missing","reason":"no matching passed evidence row"},{"name":"iOS physical hardware pilot","status":"missing","reason":"no matching passed evidence row"}],"nextSteps":[{"requirement":"Android hardware pilot + iOS simulator hardware pilot","command":"zmr-pilot-gate --android --ios --android-app-root /path/to/mobile-app --android-app-id <android-app-id> --android-device <android-serial> --ios-app-root /path/to/mobile-app --ios-app-path /path/to/mobile-app/build/Debug-iphonesimulator/Sample.app --ios-app-id <ios-app-id> --ios-device booted --ios-shim /path/to/mobile-app/.zmr/ios-shim --runs 20 --min-pass-rate 100 --max-failures 0 --evidence-out /path/to/mobile-app/traces/zmr-pilots/evidence.jsonl","commands":["zmr-pilot-gate --android --ios --android-app-root /path/to/mobile-app --android-app-id <android-app-id> --android-device <android-serial> --ios-app-root /path/to/mobile-app --ios-app-path /path/to/mobile-app/build/Debug-iphonesimulator/Sample.app --ios-app-id <ios-app-id> --ios-device booted --ios-shim /path/to/mobile-app/.zmr/ios-shim --runs 20 --min-pass-rate 100 --max-failures 0 --evidence-out /path/to/mobile-app/traces/zmr-pilots/evidence.jsonl"],"covers":["Android hardware pilot","iOS simulator hardware pilot"]},{"requirement":"physical iOS readiness + iOS physical hardware pilot","command":"zmr-pilot-gate --ios --ios-device-type physical --ios-device <physical-device-id> --ios-app-root /path/to/mobile-app --ios-app-path /path/to/mobile-app/build/Release-iphoneos/Sample.ipa --ios-app-id <ios-app-id> --ios-shim /path/to/mobile-app/.zmr/ios-shim --runs 20 --min-pass-rate 100 --max-failures 0 --evidence-out /path/to/mobile-app/traces/zmr-pilots/evidence.jsonl","commands":["zmr-pilot-gate --ios --ios-device-type physical --ios-device <physical-device-id> --ios-app-root /path/to/mobile-app --ios-app-path /path/to/mobile-app/build/Release-iphoneos/Sample.ipa --ios-app-id <ios-app-id> --ios-shim /path/to/mobile-app/.zmr/ios-shim --runs 20 --min-pass-rate 100 --max-failures 0 --evidence-out /path/to/mobile-app/traces/zmr-pilots/evidence.jsonl"],"covers":["physical iOS readiness","iOS physical hardware pilot"]}],"recommendedWording":"Do not publish the production claim yet. Missing evidence: physical iOS readiness, Android hardware pilot, iOS simulator hardware pilot, iOS physical hardware pilot.","claimLimitations":["missing evidence"]}
|
|
45
111
|
```
|
|
46
112
|
|
|
47
113
|
Zero-dependency TypeScript, standard-library Python, standard-library Go, and
|
|
@@ -54,6 +120,12 @@ Rust reference clients live under `clients/typescript/`, `clients/python/`,
|
|
|
54
120
|
|
|
55
121
|
`trace.json` is the stable bundle entrypoint for agents and viewers. It includes `schemaVersion`, `runnerVersion`, `protocolVersion`, `scenarioName`, `appId`, `status`, start/end/duration timestamps, failure metadata, `eventsPath`, `artifactsDir`, event/snapshot counts, partial failure count, and `reportPath` when `zmr report` has generated a single-trace HTML report.
|
|
56
122
|
|
|
123
|
+
`zmr report <trace-or-benchmark-dir> --out <report.html> --junit <report.xml>`
|
|
124
|
+
writes the local HTML report and a CI-friendly JUnit XML file. For trace
|
|
125
|
+
directories, the XML contains one testcase for the scenario. For benchmark
|
|
126
|
+
directories with `results.jsonl`, the XML contains one testcase per benchmark
|
|
127
|
+
row.
|
|
128
|
+
|
|
57
129
|
`zmr export <trace-dir> --out <bundle.zmrtrace>` writes a deterministic tar archive with relative paths only. V1 bundles include `trace.json`, `events.jsonl`, optional `report.html`, and every regular file under `artifacts/`.
|
|
58
130
|
|
|
59
131
|
`zmr export <trace-dir> --out <bundle.zmrtrace> --redact` writes a shareable bundle without mutating the local trace directory. Redacted bundles replace PNG screenshots with placeholder frames, omit screen recording artifacts, scrub text artifacts for emails/tokens/sensitive JSON values, and add `redaction` metadata to the bundled `trace.json`. Add `--omit-screenshots` when the bundle should contain no screenshot artifacts at all.
|
|
@@ -81,14 +153,23 @@ Clients should read the last `scenario.end` event as the authoritative trace out
|
|
|
81
153
|
scenario completes. For traced runs it mirrors the authoritative `trace.json`
|
|
82
154
|
terminal fields, including trace paths, event/snapshot counts, failed step, and
|
|
83
155
|
stable error name. Traced summaries also include `nextCommands` so agents can
|
|
84
|
-
immediately render
|
|
85
|
-
|
|
86
|
-
summary. The response is
|
|
156
|
+
immediately render HTML and JUnit reports, explain the failure, generate a
|
|
157
|
+
reviewable scenario from the trace, or export a redacted trace bundle. Failed
|
|
158
|
+
scenarios still exit non-zero after writing the JSON summary. The response is
|
|
159
|
+
covered by `schemas/run-output.schema.json`:
|
|
87
160
|
|
|
88
161
|
```json
|
|
89
|
-
{"ok":false,"status":"failed","scenario":"login smoke","appId":"com.example.mobiletest","traceDir":"traces/login-smoke","eventsPath":"events.jsonl","artifactsDir":"artifacts","durationMs":100,"eventCount":4,"snapshotCount":1,"failedStepIndex":2,"error":"WaitTimeout","nextCommands":["zmr report traces/login-smoke --out traces/login-smoke/report.html","zmr explain traces/login-smoke --json","zmr export traces/login-smoke --out traces/login-smoke.zmrtrace --redact"]}
|
|
162
|
+
{"ok":false,"status":"failed","scenario":"login smoke","appId":"com.example.mobiletest","traceDir":"traces/login-smoke","eventsPath":"events.jsonl","artifactsDir":"artifacts","durationMs":100,"eventCount":4,"snapshotCount":1,"failedStepIndex":2,"error":"WaitTimeout","nextCommands":["zmr report traces/login-smoke --out traces/login-smoke/report.html --junit traces/login-smoke/junit.xml","zmr explain traces/login-smoke --json","zmr discover --from-trace traces/login-smoke --out .zmr/discovered/replay-smoke.json --include-actions --validate --force --json","zmr export traces/login-smoke --out traces/login-smoke.zmrtrace --redact"]}
|
|
90
163
|
```
|
|
91
164
|
|
|
165
|
+
`zmr run <scenario.json> --trace-dir <trace-dir> --discover-out
|
|
166
|
+
<scenario.json> --json` runs the same trace-backed discover engine before
|
|
167
|
+
printing the run summary. The response includes `discovery` with the
|
|
168
|
+
`zmr discover --json` payload, including validation results and next commands.
|
|
169
|
+
If discovery cannot run, the run summary remains authoritative and includes
|
|
170
|
+
`discoveryError` with the stable error name. `--discover-out` requires an
|
|
171
|
+
effective `--trace-dir`, either passed directly or resolved from `.zmr/config.json`.
|
|
172
|
+
|
|
92
173
|
When a run captures useful artifacts but a non-terminal enrichment fails, such
|
|
93
174
|
as an iOS screenshot succeeding while XCTest hierarchy extraction fails, the
|
|
94
175
|
terminal status is `partial` and `partialFailureCount` is greater than zero.
|
|
@@ -114,12 +195,12 @@ The text summary includes the terminal status, failed step, stable error, last d
|
|
|
114
195
|
|
|
115
196
|
`zmr explain <trace-dir> --json` or `zmr explain --json <trace-dir>` returns
|
|
116
197
|
the same failure triage fields in a stable machine-readable shape for agents
|
|
117
|
-
and CI. It also includes `traceDir` and `nextCommands` for rendering
|
|
118
|
-
|
|
198
|
+
and CI. It also includes `traceDir` and `nextCommands` for rendering HTML and
|
|
199
|
+
JUnit reports or exporting a redacted bundle. The response is covered by
|
|
119
200
|
`schemas/explain-output.schema.json`:
|
|
120
201
|
|
|
121
202
|
```json
|
|
122
|
-
{"ok":true,"traceDir":"traces/login-smoke","scenario":"login smoke","status":"failed","appId":"com.example.mobiletest","durationMs":100,"eventCount":4,"snapshotCount":1,"failedStepIndex":2,"error":"WaitTimeout","diagnostic":{"kind":"wait.visible","status":"timeout","snapshotId":"snapshot-7","activePackage":"com.example.mobiletest","activeActivity":".MainActivity","visibleTexts":["Sign in","Try again"],"nearestTextMatches":["Dashboards (score 1)"]},"lastEvent":"scenario.end","nextCommands":["zmr report traces/login-smoke --out traces/login-smoke/report.html","zmr export traces/login-smoke --out traces/login-smoke.zmrtrace --redact"]}
|
|
203
|
+
{"ok":true,"traceDir":"traces/login-smoke","scenario":"login smoke","status":"failed","appId":"com.example.mobiletest","durationMs":100,"eventCount":4,"snapshotCount":1,"failedStepIndex":2,"error":"WaitTimeout","diagnostic":{"kind":"wait.visible","status":"timeout","snapshotId":"snapshot-7","activePackage":"com.example.mobiletest","activeActivity":".MainActivity","visibleTexts":["Sign in","Try again"],"nearestTextMatches":["Dashboards (score 1)"]},"lastEvent":"scenario.end","nextCommands":["zmr report traces/login-smoke --out traces/login-smoke/report.html --junit traces/login-smoke/junit.xml","zmr export traces/login-smoke --out traces/login-smoke.zmrtrace --redact"]}
|
|
123
204
|
```
|
|
124
205
|
|
|
125
206
|
For partial visual captures, `diagnostic.kind` is
|
|
@@ -133,7 +214,7 @@ installers, setup scripts, and generated clients. The response is covered by
|
|
|
133
214
|
`schemas/version-output.schema.json`:
|
|
134
215
|
|
|
135
216
|
```json
|
|
136
|
-
{"name":"zmr","version":"0.
|
|
217
|
+
{"name":"zmr","version":"0.2.0","protocolVersion":"2026-04-28","minimumCompatibleProtocolVersion":"2026-04-28","stability":"dev-preview","breakingChangePolicy":"version-and-changelog"}
|
|
137
218
|
```
|
|
138
219
|
|
|
139
220
|
## Capabilities Output Contract
|
|
@@ -145,7 +226,7 @@ and method inventory for JSON-RPC clients. The result object is covered by
|
|
|
145
226
|
iOS simulator, or physical iOS workflows are available.
|
|
146
227
|
|
|
147
228
|
```json
|
|
148
|
-
{"name":"zmr","version":"0.
|
|
229
|
+
{"name":"zmr","version":"0.2.0","protocolVersion":"2026-04-28","protocol":{"version":"2026-04-28","minimumCompatibleVersion":"2026-04-28","stability":"dev-preview","breakingChangePolicy":"version-and-changelog"},"platforms":["android","ios"],"platformSupport":{"android":{"status":"supported","deviceTypes":["emulator","physical"],"automation":["adb","uiautomator","android-shim"]},"ios":{"status":"supported","deviceTypes":["simulator","physical"],"automation":["simctl","devicectl","xctest-shim"],"physicalDevices":true}},"iosPreview":false,"transports":["stdio","tcp"],"methods":["runner.capabilities","device.list","session.create","session.close","app.install","app.launch","app.stop","app.openLink","app.clearState","observe.snapshot","observe.semanticSnapshot","ui.tap","ui.type","ui.eraseText","ui.hideKeyboard","ui.swipe","ui.pressBack","ui.scrollUntilVisible","wait.until","wait.any","wait.gone","assert.visible","assert.notVisible","assert.healthy","scenario.validate","trace.events","trace.explore","trace.discover","trace.explain","trace.export"]}
|
|
149
230
|
```
|
|
150
231
|
|
|
151
232
|
## Doctor Output Contract
|
|
@@ -307,7 +388,11 @@ zmr mcp --config .zmr/config.json --trace-dir traces/mcp-agent-session
|
|
|
307
388
|
- `assert.visible`
|
|
308
389
|
- `assert.notVisible`
|
|
309
390
|
- `assert.healthy`
|
|
391
|
+
- `scenario.validate`
|
|
310
392
|
- `trace.events`
|
|
393
|
+
- `trace.explore`
|
|
394
|
+
- `trace.discover`
|
|
395
|
+
- `trace.explain`
|
|
311
396
|
- `trace.export`
|
|
312
397
|
|
|
313
398
|
`runner.capabilities` returns both legacy `protocolVersion` and a structured `protocol` object. Clients should treat `protocol.version` as the compatibility key for method and payload shape, and should reject servers older than `protocol.minimumCompatibleVersion` unless they intentionally support that older shape. Before `v1.0.0`, `protocol.stability` is `dev-preview` and breaking changes require both a protocol version bump and changelog entry.
|
|
@@ -347,7 +432,7 @@ Request:
|
|
|
347
432
|
Response:
|
|
348
433
|
|
|
349
434
|
```json
|
|
350
|
-
{"jsonrpc":"2.0","id":1,"result":{"name":"zmr","version":"0.
|
|
435
|
+
{"jsonrpc":"2.0","id":1,"result":{"name":"zmr","version":"0.2.0","protocolVersion":"2026-04-28","protocol":{"version":"2026-04-28","minimumCompatibleVersion":"2026-04-28","stability":"dev-preview","breakingChangePolicy":"version-and-changelog"},"platforms":["android","ios"],"platformSupport":{"android":{"status":"supported","deviceTypes":["emulator","physical"],"automation":["adb","uiautomator","android-shim"]},"ios":{"status":"supported","deviceTypes":["simulator","physical"],"automation":["simctl","devicectl","xctest-shim"],"physicalDevices":true}},"iosPreview":false,"transports":["stdio","tcp"],"methods":["runner.capabilities","device.list","session.create","session.close","app.install","app.launch","app.stop","app.openLink","app.clearState","observe.snapshot","observe.semanticSnapshot","ui.tap","ui.type","ui.eraseText","ui.hideKeyboard","ui.swipe","ui.pressBack","ui.scrollUntilVisible","wait.until","wait.any","wait.gone","assert.visible","assert.notVisible","assert.healthy","scenario.validate","trace.events","trace.explore","trace.discover","trace.explain","trace.export"]}}
|
|
351
436
|
```
|
|
352
437
|
|
|
353
438
|
### `trace.events`
|
|
@@ -373,6 +458,90 @@ Response:
|
|
|
373
458
|
server-side event counter; `nextSeq` is the last returned event and can be
|
|
374
459
|
passed back as `afterSeq`.
|
|
375
460
|
|
|
461
|
+
### `trace.explain`
|
|
462
|
+
|
|
463
|
+
Summarizes the active live trace with the same JSON shape as
|
|
464
|
+
`zmr explain <trace-dir> --json`. Use it when an agent needs the current trace
|
|
465
|
+
status, failure diagnostic, last event, and next commands without leaving the
|
|
466
|
+
JSON-RPC session.
|
|
467
|
+
|
|
468
|
+
Request:
|
|
469
|
+
|
|
470
|
+
```json
|
|
471
|
+
{"jsonrpc":"2.0","id":26,"method":"trace.explain","params":{}}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
Response:
|
|
475
|
+
|
|
476
|
+
```json
|
|
477
|
+
{"jsonrpc":"2.0","id":26,"result":{"ok":true,"traceDir":"traces/agent-session","scenario":"json-rpc session","status":"failed","appId":"com.example.mobiletest","durationMs":100,"eventCount":4,"snapshotCount":1,"failedStepIndex":2,"error":"WaitTimeout","diagnostic":{"kind":"wait.visible","status":"timeout","snapshotId":"snapshot-7","visibleTexts":["Sign in","Try again"]},"lastEvent":"scenario.end","nextCommands":["zmr report traces/agent-session --out traces/agent-session/report.html --junit traces/agent-session/junit.xml","zmr export traces/agent-session --out traces/agent-session.zmrtrace --redact"]}}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
Without `--trace-dir`, it returns a result with `traceDir: null` and a message
|
|
481
|
+
explaining how to enable live trace explanation.
|
|
482
|
+
|
|
483
|
+
### `scenario.validate`
|
|
484
|
+
|
|
485
|
+
Validates a ZMR scenario file and returns the same structured payload as
|
|
486
|
+
`zmr validate --json`, including field paths and source locations for invalid
|
|
487
|
+
files.
|
|
488
|
+
|
|
489
|
+
Request:
|
|
490
|
+
|
|
491
|
+
```json
|
|
492
|
+
{"jsonrpc":"2.0","id":23,"method":"scenario.validate","params":{"path":".zmr/discovered/agent-smoke.json"}}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Response:
|
|
496
|
+
|
|
497
|
+
```json
|
|
498
|
+
{"jsonrpc":"2.0","id":23,"result":{"ok":true,"path":".zmr/discovered/agent-smoke.json","name":"agent smoke","appId":"com.example.mobiletest","stepCount":4,"nextCommands":["zmr run .zmr/discovered/agent-smoke.json --json --trace-dir traces/zmr-run"]}}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### `trace.discover`
|
|
502
|
+
|
|
503
|
+
Generates a reviewable scenario candidate from the active live trace. It uses
|
|
504
|
+
the same engine as `zmr discover --from-trace`, so it can include supported
|
|
505
|
+
successful replay actions, add final snapshot assertions, and optionally
|
|
506
|
+
validate the generated scenario before returning.
|
|
507
|
+
|
|
508
|
+
Request:
|
|
509
|
+
|
|
510
|
+
```json
|
|
511
|
+
{"jsonrpc":"2.0","id":25,"method":"trace.discover","params":{"out":".zmr/discovered/agent-smoke.json","includeActions":true,"validate":true,"force":true,"name":"agent smoke"}}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Response:
|
|
515
|
+
|
|
516
|
+
```json
|
|
517
|
+
{"jsonrpc":"2.0","id":25,"result":{"ok":true,"mode":"discover","schemaVersion":1,"runnerVersion":"0.2.0","protocolVersion":"2026-04-28","out":".zmr/discovered/agent-smoke.json","traceDir":"traces/agent-session","sourceSnapshot":"traces/agent-session/artifacts/snapshot-1.json","name":"agent smoke","appId":"com.example.mobiletest","selectorCount":1,"stepCount":4,"replay":{"enabled":true,"eventCount":2,"stepCount":1,"skippedEventCount":1},"warnings":["draft requires human review before commit"],"validated":true,"validation":{"ok":true,"path":".zmr/discovered/agent-smoke.json","name":"agent smoke","appId":"com.example.mobiletest","stepCount":4},"nextCommands":["zmr validate --json .zmr/discovered/agent-smoke.json","zmr run .zmr/discovered/agent-smoke.json --json --trace-dir traces/agent-session"]}}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Without `--trace-dir`, it returns `ok: false` with `traceDir: null`. Generated
|
|
521
|
+
scenarios remain review-first: ZMR does not crawl, invent credentials, or
|
|
522
|
+
commit tests.
|
|
523
|
+
|
|
524
|
+
### `trace.explore`
|
|
525
|
+
|
|
526
|
+
Generates a review-required scenario candidate from the active live trace for a
|
|
527
|
+
stated goal. It uses the same trace-backed engine as `zmr explore --from-trace`:
|
|
528
|
+
the runner writes from existing trace evidence only, does not crawl the app,
|
|
529
|
+
does not discover credentials or secrets, and returns `reviewRequired: true`.
|
|
530
|
+
|
|
531
|
+
Request:
|
|
532
|
+
|
|
533
|
+
```json
|
|
534
|
+
{"jsonrpc":"2.0","id":27,"method":"trace.explore","params":{"out":".zmr/discovered/agent-goal.json","goal":"find a stable login smoke","includeActions":true,"validate":true,"force":true,"name":"agent goal smoke"}}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
Response:
|
|
538
|
+
|
|
539
|
+
```json
|
|
540
|
+
{"jsonrpc":"2.0","id":27,"result":{"ok":true,"mode":"explore","schemaVersion":1,"runnerVersion":"0.2.0","protocolVersion":"2026-04-28","out":".zmr/discovered/agent-goal.json","traceDir":"traces/agent-session","sourceSnapshot":"traces/agent-session/artifacts/snapshot-1.json","name":"agent goal smoke","appId":"com.example.mobiletest","selectorCount":1,"stepCount":4,"replay":{"enabled":true,"eventCount":2,"stepCount":1,"skippedEventCount":1},"warnings":["draft requires human review before commit"],"validated":true,"validation":{"ok":true,"path":".zmr/discovered/agent-goal.json","name":"agent goal smoke","appId":"com.example.mobiletest","stepCount":4},"nextCommands":["zmr validate --json .zmr/discovered/agent-goal.json","zmr run .zmr/discovered/agent-goal.json --json --trace-dir traces/agent-session"],"goal":"find a stable login smoke","autonomous":false,"reviewRequired":true,"guardrails":["writes from existing trace evidence only","does not crawl the app","does not discover credentials or secrets","requires human review before commit"]}}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Without `--trace-dir`, it returns `ok: false` with `traceDir: null`.
|
|
544
|
+
|
|
376
545
|
### `device.list`
|
|
377
546
|
|
|
378
547
|
Response:
|
|
@@ -432,10 +601,14 @@ exposes tool calls for agent runtimes that prefer MCP over raw JSON-RPC.
|
|
|
432
601
|
zmr mcp --config .zmr/config.json --trace-dir traces/mcp-agent
|
|
433
602
|
```
|
|
434
603
|
|
|
435
|
-
Core tools are `snapshot`, `semantic_snapshot`, `
|
|
436
|
-
`
|
|
437
|
-
|
|
438
|
-
|
|
604
|
+
Core tools are `snapshot`, `semantic_snapshot`, `install_app`, `launch_app`,
|
|
605
|
+
`stop_app`, `clear_state`, `tap`, `type`, `erase_text`, `hide_keyboard`,
|
|
606
|
+
`swipe`, `press_back`, `open_link`, `wait_visible`, `wait_not_visible`,
|
|
607
|
+
`wait_any`, `scroll_until_visible`, `assert_visible`, `assert_not_visible`,
|
|
608
|
+
`assert_healthy`, `scenario_validate`, `trace_events`, `trace_explain`,
|
|
609
|
+
`trace_explore`, `trace_discover`, and `trace_export`. The MCP protocol handshake is
|
|
610
|
+
intentionally standard, while the tool names and payloads are versioned with
|
|
611
|
+
the ZMR runner and public schemas.
|
|
439
612
|
|
|
440
613
|
### `ui.tap`
|
|
441
614
|
|
|
@@ -466,6 +639,32 @@ Request:
|
|
|
466
639
|
{"jsonrpc":"2.0","id":7,"method":"assert.notVisible","params":{"selector":{"textContains":"Loading"},"timeoutMs":5000}}
|
|
467
640
|
```
|
|
468
641
|
|
|
642
|
+
### MCP `trace_discover`
|
|
643
|
+
|
|
644
|
+
`trace_discover` mirrors JSON-RPC `trace.discover` for MCP agents. Required
|
|
645
|
+
argument: `out`. Optional arguments: `includeActions`, `validate`, `force`,
|
|
646
|
+
`name`, and `appId`. The tool response text is the same discover JSON payload.
|
|
647
|
+
|
|
648
|
+
### MCP `trace_explore`
|
|
649
|
+
|
|
650
|
+
`trace_explore` mirrors JSON-RPC `trace.explore` for MCP agents. Required
|
|
651
|
+
arguments: `out` and `goal`. Optional arguments: `includeActions`, `validate`,
|
|
652
|
+
`force`, `name`, and `appId`. The tool response text is the same guarded
|
|
653
|
+
explore JSON payload, including `autonomous:false`, `reviewRequired:true`, and
|
|
654
|
+
`guardrails`.
|
|
655
|
+
|
|
656
|
+
### MCP `trace_explain`
|
|
657
|
+
|
|
658
|
+
`trace_explain` mirrors JSON-RPC `trace.explain` for MCP agents. It takes no
|
|
659
|
+
arguments. The tool response text is the same explanation JSON payload returned
|
|
660
|
+
by `zmr explain --json`.
|
|
661
|
+
|
|
662
|
+
### MCP `scenario_validate`
|
|
663
|
+
|
|
664
|
+
`scenario_validate` mirrors JSON-RPC `scenario.validate` for MCP agents.
|
|
665
|
+
Required argument: `path`. The tool response text is the same validation JSON
|
|
666
|
+
payload returned by `zmr validate --json`.
|
|
667
|
+
|
|
469
668
|
### `trace.export`
|
|
470
669
|
|
|
471
670
|
When `zmr serve` is started with `--trace-dir`, live JSON-RPC sessions use the
|
|
@@ -4,6 +4,19 @@ ZMR scenarios are JSON so agents can generate and mutate them without a second
|
|
|
4
4
|
DSL. JSON is strict, schema-validatable, and easy for agents and code generators
|
|
5
5
|
to emit. Keep scenarios explicit, short, and biased toward stable selectors.
|
|
6
6
|
|
|
7
|
+
Scenarios can be written by hand, or generated review-first from the trace of
|
|
8
|
+
a live session:
|
|
9
|
+
|
|
10
|
+
```mermaid
|
|
11
|
+
flowchart LR
|
|
12
|
+
SESSION["Live agent session<br/>or zmr run"] --> TRACE["Trace directory"]
|
|
13
|
+
TRACE --> DISCOVER["zmr discover / draft / explore<br/>--from-trace"]
|
|
14
|
+
DISCOVER --> CANDIDATE["Scenario candidate<br/>.zmr/discovered/*.json"]
|
|
15
|
+
CANDIDATE --> REVIEW["Human / agent review"]
|
|
16
|
+
REVIEW --> VALIDATE["zmr validate --json"]
|
|
17
|
+
VALIDATE --> CI["zmr run in CI<br/>report.html · junit.xml"]
|
|
18
|
+
```
|
|
19
|
+
|
|
7
20
|
## Selector Strategy
|
|
8
21
|
|
|
9
22
|
Prefer selectors in this order:
|
|
@@ -71,6 +84,9 @@ The importer supports the common subset needed for smoke scenarios:
|
|
|
71
84
|
generated JSON before committing it; native `.zmr/*.json` scenarios remain the
|
|
72
85
|
runtime contract for agents and CI.
|
|
73
86
|
|
|
87
|
+
`assertVisible` and `assertNotVisible` accept the same `timeoutMs` field as
|
|
88
|
+
waits when a scenario needs assertion-specific timing.
|
|
89
|
+
|
|
74
90
|
## Example Templates
|
|
75
91
|
|
|
76
92
|
The example directory includes templates for common app flows:
|
|
@@ -80,8 +96,10 @@ The example directory includes templates for common app flows:
|
|
|
80
96
|
- `examples/android-app-onboarding.json`
|
|
81
97
|
- `examples/android-app-referral-deep-link.json`
|
|
82
98
|
- `examples/android-app-error-state.json`
|
|
99
|
+
- `examples/android-workflow.json`
|
|
83
100
|
- `examples/ios-dev-client-open-link.json`
|
|
84
101
|
- `examples/ios-dev-client-route-snapshot.json`
|
|
102
|
+
- `examples/ios-shim-workflow.json`
|
|
85
103
|
|
|
86
104
|
Run `zmr validate --json <scenario.json>` before touching a device. Invalid
|
|
87
105
|
scenarios report `fieldPath`, `line`, and `column` when ZMR can identify the
|
package/docs/trace-privacy.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
ZMR traces are debugging artifacts. They can contain sensitive app state even
|
|
4
4
|
when scenario files are generic.
|
|
5
5
|
|
|
6
|
+
```mermaid
|
|
7
|
+
flowchart LR
|
|
8
|
+
RUN["zmr run / live session"] --> DIR["Trace directory<br/>events.jsonl · screenshots ·<br/>UI trees · logs · timings"]
|
|
9
|
+
DIR --> REPORT["zmr report<br/>report.html · junit.xml"]
|
|
10
|
+
DIR --> EXPLAIN["zmr explain<br/>failure diagnosis"]
|
|
11
|
+
DIR --> EXPORT["zmr export --redact<br/>.zmrtrace bundle"]
|
|
12
|
+
EXPORT --> VIEWER["Static trace viewer<br/>or shared evidence"]
|
|
13
|
+
```
|
|
14
|
+
|
|
6
15
|
Raw trace directories may include:
|
|
7
16
|
|
|
8
17
|
- screenshots
|
package/docs/troubleshooting.md
CHANGED
|
@@ -188,6 +188,12 @@ app targets. Pass `--project` explicitly for still-ambiguous multi-project
|
|
|
188
188
|
workspaces. Run with `--ios-shim ./.zmr/ios-shim` or set
|
|
189
189
|
`tools.iosShimPath` in `.zmr/config.json`.
|
|
190
190
|
|
|
191
|
+
A clean prebuild can push the shim's first `build-for-testing` through a full
|
|
192
|
+
native dependency compile. ZMR waits up to 90 minutes by default; on slower CI
|
|
193
|
+
hardware, raise the ceiling with the `ZMR_IOS_SHIM_TIMEOUT_MS` environment
|
|
194
|
+
variable (milliseconds), for example `ZMR_IOS_SHIM_TIMEOUT_MS=10800000` for
|
|
195
|
+
three hours.
|
|
196
|
+
|
|
191
197
|
If a real iOS run fails with CoreSimulator or Xcode cache errors such as
|
|
192
198
|
`Operation not permitted`, `CoreSimulatorService connection became invalid`, or
|
|
193
199
|
an unexpected workspace/build database error, rerun from a normal terminal or CI
|
|
@@ -228,7 +234,7 @@ When a run fails, do not rerun blindly. Inspect the recorded failure:
|
|
|
228
234
|
|
|
229
235
|
```bash
|
|
230
236
|
zmr explain traces/zmr-android
|
|
231
|
-
zmr report traces/zmr-android --out traces/zmr-android/report.html
|
|
237
|
+
zmr report traces/zmr-android --out traces/zmr-android/report.html --junit traces/zmr-android/junit.xml
|
|
232
238
|
```
|
|
233
239
|
|
|
234
240
|
Timeout diagnostics include the active package/activity, visible text, hidden or
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ZMR Android workflow demo",
|
|
3
|
+
"appId": "com.example.mobiletest",
|
|
4
|
+
"steps": [
|
|
5
|
+
{ "action": "stop" },
|
|
6
|
+
{ "action": "launch" },
|
|
7
|
+
{
|
|
8
|
+
"action": "waitVisible",
|
|
9
|
+
"selector": { "text": "ZMR Android Demo" },
|
|
10
|
+
"timeoutMs": 30000
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"action": "tap",
|
|
14
|
+
"selector": { "resourceId": "com.example.mobiletest:id/continue_button" }
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"action": "waitVisible",
|
|
18
|
+
"selector": { "text": "Profile" },
|
|
19
|
+
"timeoutMs": 10000
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"action": "typeText",
|
|
23
|
+
"selector": { "resourceId": "com.example.mobiletest:id/profile_name_input" },
|
|
24
|
+
"text": "Riley"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"action": "typeText",
|
|
28
|
+
"selector": { "resourceId": "com.example.mobiletest:id/profile_email_input" },
|
|
29
|
+
"text": "riley@example.test"
|
|
30
|
+
},
|
|
31
|
+
{ "action": "hideKeyboard" },
|
|
32
|
+
{
|
|
33
|
+
"action": "tap",
|
|
34
|
+
"selector": { "resourceId": "com.example.mobiletest:id/save_profile_button" }
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"action": "waitVisible",
|
|
38
|
+
"selector": { "text": "Catalog" },
|
|
39
|
+
"timeoutMs": 10000
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"action": "scrollUntilVisible",
|
|
43
|
+
"selector": { "resourceId": "com.example.mobiletest:id/catalog_item_north_ridge_pack" },
|
|
44
|
+
"direction": "down",
|
|
45
|
+
"timeoutMs": 10000
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"action": "tap",
|
|
49
|
+
"selector": { "resourceId": "com.example.mobiletest:id/catalog_item_north_ridge_pack" }
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"action": "waitVisible",
|
|
53
|
+
"selector": { "text": "North Ridge Pack" },
|
|
54
|
+
"timeoutMs": 10000
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"action": "tap",
|
|
58
|
+
"selector": { "resourceId": "com.example.mobiletest:id/detail_save_button" }
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"action": "waitVisible",
|
|
62
|
+
"selector": { "text": "Saved North Ridge Pack" },
|
|
63
|
+
"timeoutMs": 10000
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"action": "tap",
|
|
67
|
+
"selector": { "resourceId": "com.example.mobiletest:id/review_button" }
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"action": "assertVisible",
|
|
71
|
+
"selector": {
|
|
72
|
+
"resourceId": "com.example.mobiletest:id/workflow_status",
|
|
73
|
+
"text": "Workflow complete"
|
|
74
|
+
},
|
|
75
|
+
"timeoutMs": 10000
|
|
76
|
+
},
|
|
77
|
+
{ "action": "snapshot" }
|
|
78
|
+
]
|
|
79
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ZMR iOS shim workflow demo",
|
|
3
|
+
"appId": "com.example.mobiletest",
|
|
4
|
+
"steps": [
|
|
5
|
+
{ "action": "stop" },
|
|
6
|
+
{ "action": "launch" },
|
|
7
|
+
{
|
|
8
|
+
"action": "waitVisible",
|
|
9
|
+
"selector": { "text": "ZMR iOS Demo" },
|
|
10
|
+
"timeoutMs": 30000
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"action": "tap",
|
|
14
|
+
"selector": { "resourceId": "continue_button" }
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"action": "waitVisible",
|
|
18
|
+
"selector": { "text": "Profile" },
|
|
19
|
+
"timeoutMs": 10000
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"action": "typeText",
|
|
23
|
+
"selector": { "resourceId": "profile_name_input" },
|
|
24
|
+
"text": "Riley"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"action": "typeText",
|
|
28
|
+
"selector": { "resourceId": "profile_email_input" },
|
|
29
|
+
"text": "riley@example.test"
|
|
30
|
+
},
|
|
31
|
+
{ "action": "hideKeyboard" },
|
|
32
|
+
{
|
|
33
|
+
"action": "tap",
|
|
34
|
+
"selector": { "resourceId": "save_profile_button" }
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"action": "waitVisible",
|
|
38
|
+
"selector": { "text": "Catalog" },
|
|
39
|
+
"timeoutMs": 10000
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"action": "scrollUntilVisible",
|
|
43
|
+
"selector": { "resourceId": "catalog_item_north_ridge_pack" },
|
|
44
|
+
"direction": "down",
|
|
45
|
+
"timeoutMs": 10000
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"action": "tap",
|
|
49
|
+
"selector": { "resourceId": "catalog_item_north_ridge_pack" }
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"action": "waitVisible",
|
|
53
|
+
"selector": { "text": "North Ridge Pack" },
|
|
54
|
+
"timeoutMs": 10000
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"action": "tap",
|
|
58
|
+
"selector": { "resourceId": "detail_save_button" }
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"action": "waitVisible",
|
|
62
|
+
"selector": { "text": "Saved North Ridge Pack" },
|
|
63
|
+
"timeoutMs": 10000
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"action": "tap",
|
|
67
|
+
"selector": { "resourceId": "review_button" }
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"action": "assertVisible",
|
|
71
|
+
"selector": {
|
|
72
|
+
"resourceId": "workflow_status",
|
|
73
|
+
"text": "Workflow complete"
|
|
74
|
+
},
|
|
75
|
+
"timeoutMs": 10000
|
|
76
|
+
},
|
|
77
|
+
{ "action": "snapshot" }
|
|
78
|
+
]
|
|
79
|
+
}
|