@appetize/cli 0.17.0 → 0.19.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 +17 -0
- package/cli.js +10 -19
- package/config-D0ukqfLN.js +3 -0
- package/daemon.js +2 -2
- package/package.json +6 -4
- package/skills/appetize/SKILL.md +37 -31
- package/skills/appetize/references/commands.md +38 -20
- package/viewer.html +1 -1
- package/signals-C8NaADLb.js +0 -2
package/skills/appetize/SKILL.md
CHANGED
|
@@ -10,7 +10,7 @@ description: >-
|
|
|
10
10
|
or answering what is currently on screen — even if Appetize is not mentioned
|
|
11
11
|
by name.
|
|
12
12
|
metadata:
|
|
13
|
-
cli-version: '0.
|
|
13
|
+
cli-version: '0.19.0'
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# Appetize
|
|
@@ -31,6 +31,9 @@ Confirm the CLI is installed and note the version:
|
|
|
31
31
|
appetize --version
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
End every command with `--json`, so its result is always JSON. If your tool runs
|
|
35
|
+
commands in a terminal, add `--quiet` too.
|
|
36
|
+
|
|
34
37
|
`APPETIZE_API_TOKEN` must be set for private APIs and session targets. A target
|
|
35
38
|
is an uploaded build's public key, e.g. `app_a1b2c3`. Discover one with
|
|
36
39
|
`appetize build list`, filtering with `--app <appId>` when you know the bundle
|
|
@@ -53,9 +56,9 @@ configured once rather than flagged on every session.
|
|
|
53
56
|
Start a session, naming a device and a target:
|
|
54
57
|
|
|
55
58
|
```bash
|
|
56
|
-
appetize session start iphone15pro app_a1b2c3
|
|
57
|
-
appetize session start pixel7 app_a1b2c3 --device-os-version 14
|
|
58
|
-
appetize session start iphone15pro app_a1b2c3 --open myapp://orders/42
|
|
59
|
+
appetize session start iphone15pro app_a1b2c3 --json
|
|
60
|
+
appetize session start pixel7 app_a1b2c3 --device-os-version 14 --json
|
|
61
|
+
appetize session start iphone15pro app_a1b2c3 --open myapp://orders/42 --json
|
|
59
62
|
```
|
|
60
63
|
|
|
61
64
|
This blocks until the device is ready, then prints the session:
|
|
@@ -108,7 +111,7 @@ jq 'select(.type == "response") | "\(.response.status) \(.request.method) \(.req
|
|
|
108
111
|
Stop the session when you are done, so the device is released:
|
|
109
112
|
|
|
110
113
|
```bash
|
|
111
|
-
appetize session stop
|
|
114
|
+
appetize session stop --json
|
|
112
115
|
```
|
|
113
116
|
|
|
114
117
|
Session state lives in `~/.appetize/cli/sessions/<session-id>/state.json` (or under
|
|
@@ -122,8 +125,8 @@ Video is not captured unless you ask for it — nothing streams from the device
|
|
|
122
125
|
until you start:
|
|
123
126
|
|
|
124
127
|
```bash
|
|
125
|
-
appetize recording start login-flow
|
|
126
|
-
appetize recording stop
|
|
128
|
+
appetize recording start login-flow --json
|
|
129
|
+
appetize recording stop --json
|
|
127
130
|
```
|
|
128
131
|
|
|
129
132
|
`recording start` has the daemon open the video stream and write it to the file
|
|
@@ -144,7 +147,7 @@ Playback is a constant 30fps, so it does not track real time.
|
|
|
144
147
|
### 1. Inspect first
|
|
145
148
|
|
|
146
149
|
```bash
|
|
147
|
-
appetize inspect --select-test-id login-form
|
|
150
|
+
appetize inspect --select-test-id login-form --json
|
|
148
151
|
```
|
|
149
152
|
|
|
150
153
|
`inspect` writes the view hierarchy as JSON to `inspect.json` by default (name
|
|
@@ -164,12 +167,12 @@ not "does not exist".
|
|
|
164
167
|
Prefer matching what an element _is_ over where it happens to sit:
|
|
165
168
|
|
|
166
169
|
```bash
|
|
167
|
-
appetize tap --select-test-id save
|
|
168
|
-
appetize tap --select-text 'Log in'
|
|
169
|
-
appetize tap --select-text '/^item \d+/i' --select-index 2
|
|
170
|
-
appetize type 'user@example.com{Tab}hunter2{Enter}'
|
|
171
|
-
appetize swipe --direction up
|
|
172
|
-
appetize swipe --from-test-id card-3 --to-test-id archive-bin
|
|
170
|
+
appetize tap --select-test-id save --json
|
|
171
|
+
appetize tap --select-text 'Log in' --json
|
|
172
|
+
appetize tap --select-text '/^item \d+/i' --select-index 2 --json
|
|
173
|
+
appetize type 'user@example.com{Tab}hunter2{Enter}' --json
|
|
174
|
+
appetize swipe --direction up --json
|
|
175
|
+
appetize swipe --from-test-id card-3 --to-test-id archive-bin --json
|
|
173
176
|
```
|
|
174
177
|
|
|
175
178
|
`swipe` comes in two shapes. A `--direction` scrolls the screen (add
|
|
@@ -179,8 +182,8 @@ a target. Both ends take the same selectors as `tap`, so a drag can name its
|
|
|
179
182
|
endpoints instead of guessing coordinates:
|
|
180
183
|
|
|
181
184
|
```bash
|
|
182
|
-
appetize swipe --direction left --from-test-id card --from-index 1
|
|
183
|
-
appetize swipe --from-text 'Drag me' --from-y 0.9 --to-test-id drop-zone
|
|
185
|
+
appetize swipe --direction left --from-test-id card --from-index 1 --json
|
|
186
|
+
appetize swipe --from-text 'Drag me' --from-y 0.9 --to-test-id drop-zone --json
|
|
184
187
|
```
|
|
185
188
|
|
|
186
189
|
`--select-test-id` is the most durable, then `--select-text` (an exact string,
|
|
@@ -195,7 +198,7 @@ In `type`, `{...}` names a key: `{Enter}`, `{Tab}`, `{Backspace}`, the arrows.
|
|
|
195
198
|
### 3. Verify
|
|
196
199
|
|
|
197
200
|
```bash
|
|
198
|
-
appetize screenshot after-login
|
|
201
|
+
appetize screenshot after-login --json
|
|
199
202
|
```
|
|
200
203
|
|
|
201
204
|
Screenshot after each meaningful step. A tap that "succeeded" only means the
|
|
@@ -206,7 +209,7 @@ for you.
|
|
|
206
209
|
### 4. Wait by inspecting, not by sleeping
|
|
207
210
|
|
|
208
211
|
```bash
|
|
209
|
-
appetize inspect --select-test-id home-feed --timeout 5000
|
|
212
|
+
appetize inspect --select-test-id home-feed --timeout 5000 --json
|
|
210
213
|
```
|
|
211
214
|
|
|
212
215
|
`--timeout <ms>` makes the command wait for the element and fail with a non-zero
|
|
@@ -236,8 +239,8 @@ workflow, push your change so it runs, then restart the session against the
|
|
|
236
239
|
build id it produced:
|
|
237
240
|
|
|
238
241
|
```bash
|
|
239
|
-
appetize session stop
|
|
240
|
-
appetize session start iphone15pro <new-id>
|
|
242
|
+
appetize session stop --json
|
|
243
|
+
appetize session start iphone15pro <new-id> --json
|
|
241
244
|
```
|
|
242
245
|
|
|
243
246
|
If you cannot tell from the repository's CI configuration how an iOS build
|
|
@@ -257,9 +260,9 @@ When a turn ends with a visual change or a final state that deserves a demo,
|
|
|
257
260
|
record the flow and surface the video the same way:
|
|
258
261
|
|
|
259
262
|
```bash
|
|
260
|
-
appetize recording start demo
|
|
263
|
+
appetize recording start demo --json
|
|
261
264
|
# drive the flow
|
|
262
|
-
appetize recording stop
|
|
265
|
+
appetize recording stop --json
|
|
263
266
|
```
|
|
264
267
|
|
|
265
268
|
Where your environment lets you attach media to a pull request, include the
|
|
@@ -276,10 +279,8 @@ transcript is the record — never commit screenshots or recordings to the repo.
|
|
|
276
279
|
| Element not found | Re-inspect. It is off screen, covered, or the screen changed. |
|
|
277
280
|
| App fails only on network calls | If you started with `--proxy`, retry without it. |
|
|
278
281
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
`session start` is taking a while, that sequence tells you whether you are
|
|
282
|
-
queued for capacity or waiting on an install.
|
|
282
|
+
If `session start` is taking a while, `state.phase` in its `state.json` tells
|
|
283
|
+
you whether you are queued for capacity or waiting on an install.
|
|
283
284
|
|
|
284
285
|
## Dismissing the soft keyboard
|
|
285
286
|
|
|
@@ -290,14 +291,14 @@ if the app wired that up, and many apps do not.
|
|
|
290
291
|
**iOS** — press the return key:
|
|
291
292
|
|
|
292
293
|
```bash
|
|
293
|
-
appetize type '{Enter}'
|
|
294
|
+
appetize type '{Enter}' --json
|
|
294
295
|
```
|
|
295
296
|
|
|
296
297
|
**Android** — press the back button; while the keyboard is up it dismisses
|
|
297
298
|
the keyboard instead of navigating back:
|
|
298
299
|
|
|
299
300
|
```bash
|
|
300
|
-
appetize press back
|
|
301
|
+
appetize press back --json
|
|
301
302
|
```
|
|
302
303
|
|
|
303
304
|
Both leave you on the same screen with the field still focused. Confirm from
|
|
@@ -315,15 +316,20 @@ test id or a dismiss button changes the thing you are supposed to be verifying.
|
|
|
315
316
|
Prefer `open` over navigating screen by screen when a deep link exists:
|
|
316
317
|
|
|
317
318
|
```bash
|
|
318
|
-
appetize open myapp://orders/42
|
|
319
|
-
appetize open https://myapp.com/orders/42
|
|
320
|
-
appetize inspect --select-test-id order-42 --timeout 5000
|
|
319
|
+
appetize open myapp://orders/42 --json
|
|
320
|
+
appetize open https://myapp.com/orders/42 --json
|
|
321
|
+
appetize inspect --select-test-id order-42 --timeout 5000 --json
|
|
321
322
|
```
|
|
322
323
|
|
|
323
324
|
`open` returning only means the URL was delivered, so verify the destination
|
|
324
325
|
screen with `inspect --timeout`. A custom scheme needs its app installed on the
|
|
325
326
|
device. iOS caps URLs at 2048 characters.
|
|
326
327
|
|
|
328
|
+
## Logged-out state
|
|
329
|
+
|
|
330
|
+
On iOS, `appetize keychain clear` clears the entire keychain without restarting
|
|
331
|
+
the session. It has no effect on Android.
|
|
332
|
+
|
|
327
333
|
## Full command reference
|
|
328
334
|
|
|
329
335
|
`references/commands.md` has every command, flag, output shape and exit
|
|
@@ -16,6 +16,7 @@ same flags at the terminal.
|
|
|
16
16
|
- [press](#press)
|
|
17
17
|
- [rotate](#rotate)
|
|
18
18
|
- [open](#open)
|
|
19
|
+
- [keychain clear](#keychain-clear)
|
|
19
20
|
- [screenshot](#screenshot)
|
|
20
21
|
- [recording start](#recording-start)
|
|
21
22
|
- [recording stop](#recording-stop)
|
|
@@ -26,6 +27,11 @@ same flags at the terminal.
|
|
|
26
27
|
|
|
27
28
|
## Global
|
|
28
29
|
|
|
30
|
+
`--json` prints the result as JSON. End every command with it. `--no-json`
|
|
31
|
+
prints text.
|
|
32
|
+
|
|
33
|
+
`--quiet` hides the progress spinner shown on an interactive terminal.
|
|
34
|
+
|
|
29
35
|
`--session-id <id>` is accepted by every command except those marked "Takes
|
|
30
36
|
no session". On
|
|
31
37
|
`session start` it names the session being created; everywhere else it picks
|
|
@@ -55,9 +61,7 @@ once the device is ready; `--no-wait` prints `{ logs, sessionId }` immediately.
|
|
|
55
61
|
available to it: `adb connect <adbSerial>` attaches to the device until the
|
|
56
62
|
session ends. `viewerUrl` opens the local browser viewer. `logs`
|
|
57
63
|
carries a `device` and a `daemon` path, plus a `network` path — the JSONL capture
|
|
58
|
-
of the app's traffic — when started with `--proxy` (or `--proxy intercept`).
|
|
59
|
-
`requesting`, `queued`, `starting`, `downloadingApp`, `installingApp`,
|
|
60
|
-
`launchingApp`, `ready`.
|
|
64
|
+
of the app's traffic — when started with `--proxy` (or `--proxy intercept`).
|
|
61
65
|
|
|
62
66
|
Network traffic can be proxied or intercepted for debugging. `--proxy` (or
|
|
63
67
|
`--proxy intercept`) provisions the intercepting proxy so traffic can be
|
|
@@ -75,7 +79,7 @@ and starting a session with an id already in use fails.
|
|
|
75
79
|
appetize session stop
|
|
76
80
|
```
|
|
77
81
|
|
|
78
|
-
Signals the daemon to shut down and prints `{
|
|
82
|
+
Signals the daemon to shut down and prints `{ sessionId }`. Reports
|
|
79
83
|
the id even if the daemon had already exited, so it is safe to call twice.
|
|
80
84
|
|
|
81
85
|
## build list
|
|
@@ -113,7 +117,7 @@ appetize build upload <file> [options]
|
|
|
113
117
|
|
|
114
118
|
Uploads a `.apk`, `.apks`, `.zip` or `.tar.gz` and prints
|
|
115
119
|
`{ created, id, platform }` on stdout, where `id` is a target `session start`
|
|
116
|
-
takes.
|
|
120
|
+
takes.
|
|
117
121
|
|
|
118
122
|
The extension decides the platform — `.apk` and `.apks` are Android, `.zip`,
|
|
119
123
|
`.tar.gz` and `.tgz` are iOS — and any other file is refused before uploading.
|
|
@@ -172,7 +176,7 @@ appetize tap [options]
|
|
|
172
176
|
| `--select-*` | Element or position to tap — see [Selectors](#selectors) |
|
|
173
177
|
| `--timeout` | Milliseconds to wait for the element |
|
|
174
178
|
|
|
175
|
-
Prints `{
|
|
179
|
+
Prints `{}`. Combining an element selector with `--select-x` /
|
|
176
180
|
`--select-y` taps a point within that element, and values outside `0-1` are
|
|
177
181
|
allowed to reach just beyond its edge (e.g. `--select-x=-0.1`).
|
|
178
182
|
|
|
@@ -191,7 +195,7 @@ appetize swipe [options]
|
|
|
191
195
|
| `--duration` | Milliseconds the gesture travels for |
|
|
192
196
|
| `--timeout` | Milliseconds to wait for any `--from`/`--to` elements |
|
|
193
197
|
|
|
194
|
-
Prints `{
|
|
198
|
+
Prints `{}`. Two shapes are valid: a `--direction` with an
|
|
195
199
|
optional `--from-*` starting point, or both a `--from-*` and a `--to-*` point to
|
|
196
200
|
form a path. Mixing `--direction` with `--to-*` is an error, as is `--distance`
|
|
197
201
|
without `--direction`.
|
|
@@ -206,7 +210,7 @@ appetize type <text> [options]
|
|
|
206
210
|
| --------- | ---------------------------------- |
|
|
207
211
|
| `--delay` | Milliseconds to wait between steps |
|
|
208
212
|
|
|
209
|
-
Prints `{
|
|
213
|
+
Prints `{}`. Bare text is delivered as a string; `{...}` names a
|
|
210
214
|
key delivered as a keystroke. Supported keys: `ArrowDown`, `ArrowLeft`,
|
|
211
215
|
`ArrowRight`, `ArrowUp`, `Backspace`, `Enter`, `Tab`. A token may carry a repeat
|
|
212
216
|
count as in `{Backspace>16/}`, and `{{` types a literal `{`. An unclosed token
|
|
@@ -220,7 +224,7 @@ Typing does not focus a field — tap it first.
|
|
|
220
224
|
appetize press <button>
|
|
221
225
|
```
|
|
222
226
|
|
|
223
|
-
Prints `{
|
|
227
|
+
Prints `{}`. Buttons: `home` and `lock` on both platforms;
|
|
224
228
|
`back`, `menu`, `unlock`, `volumeUp` and `volumeDown` on Android only. Calling
|
|
225
229
|
an Android-only button on iOS fails.
|
|
226
230
|
|
|
@@ -233,7 +237,7 @@ main page.
|
|
|
233
237
|
appetize rotate <orientation>
|
|
234
238
|
```
|
|
235
239
|
|
|
236
|
-
Prints
|
|
240
|
+
Prints `{}`. Orientations: `portrait`, `landscapeLeft`,
|
|
237
241
|
`landscapeRight`, `upsideDown`.
|
|
238
242
|
|
|
239
243
|
## open
|
|
@@ -242,9 +246,18 @@ Prints the resulting orientation. Orientations: `portrait`, `landscapeLeft`,
|
|
|
242
246
|
appetize open <url>
|
|
243
247
|
```
|
|
244
248
|
|
|
245
|
-
Prints `{
|
|
249
|
+
Prints `{}`. `<url>` is a deep link (`myapp://orders/42`) or an
|
|
246
250
|
http(s) URL. A malformed or scheme-less value is refused.
|
|
247
251
|
|
|
252
|
+
## keychain clear
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
appetize keychain clear
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Prints `{}`. iOS only: clears the entire keychain. No effect on
|
|
259
|
+
Android.
|
|
260
|
+
|
|
248
261
|
## screenshot
|
|
249
262
|
|
|
250
263
|
```
|
|
@@ -252,7 +265,7 @@ appetize screenshot [output]
|
|
|
252
265
|
```
|
|
253
266
|
|
|
254
267
|
`output` defaults to `screenshot`, and an extension matching the image is added
|
|
255
|
-
if you omit one. Writes a PNG and prints `{ bytes,
|
|
268
|
+
if you omit one. Writes a PNG and prints `{ bytes, output }`.
|
|
256
269
|
|
|
257
270
|
## recording start
|
|
258
271
|
|
|
@@ -265,7 +278,7 @@ appetize recording start <output> [options]
|
|
|
265
278
|
| `--force` | Overwrite the file if it already exists |
|
|
266
279
|
|
|
267
280
|
Asks the daemon to open the device video stream and capture it to `output`,
|
|
268
|
-
printing `{ path
|
|
281
|
+
printing `{ path }`. Capture is opt-in — video is lazy
|
|
269
282
|
device-side, so nothing streams until this runs.
|
|
270
283
|
|
|
271
284
|
`output` is required. `.mp4` is added if you omit an extension, any other
|
|
@@ -284,7 +297,7 @@ capture is running.
|
|
|
284
297
|
appetize recording stop
|
|
285
298
|
```
|
|
286
299
|
|
|
287
|
-
Closes the stream and the file, printing `{ path
|
|
300
|
+
Closes the stream and the file, printing `{ path }`. Fails
|
|
288
301
|
with `No video recording in progress` when nothing is recording. Ending the
|
|
289
302
|
session while recording closes the file too, noting it in `daemon.log`.
|
|
290
303
|
|
|
@@ -355,6 +368,7 @@ slider track.
|
|
|
355
368
|
| `APPETIZE_API_TOKEN` | Authorizes private APIs and session targets |
|
|
356
369
|
| `APPETIZE_ENDPOINT` | Appetize URL used when `--endpoint` is omitted |
|
|
357
370
|
| `APPETIZE_CLI_HOME` | Overrides the session state directory |
|
|
371
|
+
| `APPETIZE_OUTPUT` | `json` or `text` when neither flag is passed |
|
|
358
372
|
|
|
359
373
|
Session state is written to `~/.appetize/cli/sessions/<session-id>/state.json`.
|
|
360
374
|
Device logs stream as JSONL to `device.log.jsonl` beside it, and the daemon's
|
|
@@ -362,12 +376,16 @@ own output goes to `daemon.log`.
|
|
|
362
376
|
|
|
363
377
|
## Exit codes and output streams
|
|
364
378
|
|
|
365
|
-
Commands exit `0` on success and non-zero on failure, printing
|
|
366
|
-
|
|
367
|
-
|
|
379
|
+
Commands exit `0` on success and non-zero on failure, printing
|
|
380
|
+
`{ "error": { "message": "…" } }` to stderr (text on a terminal, unless
|
|
381
|
+
`--json`), plus `sessionDir` (the session's
|
|
382
|
+
logs and `state.json`) once a session is found, unless the command was misused.
|
|
383
|
+
A selector `--timeout` that expires is a failure, which is what makes it usable
|
|
384
|
+
as a wait.
|
|
368
385
|
|
|
369
|
-
|
|
370
|
-
stderr
|
|
386
|
+
Results go to stdout as JSON (text on a terminal, unless `--json`) and hold
|
|
387
|
+
only what you could not know beforehand; `{}` means the command ran. stderr
|
|
388
|
+
carries only errors, plus a progress spinner on an interactive terminal.
|
|
371
389
|
|
|
372
390
|
Common failures:
|
|
373
391
|
|
|
@@ -375,4 +393,4 @@ Common failures:
|
|
|
375
393
|
| --------------------------- | --------------------------------------------------------------------------------- |
|
|
376
394
|
| `No active sessions` | `session start` first; if one should be live, its `daemon.log` says why it exited |
|
|
377
395
|
| `No session found for id X` | `endedReason` in the session's `state.json` |
|
|
378
|
-
| `Session is not ready` | `state.phase` in `state.json` says how far it got
|
|
396
|
+
| `Session is not ready` | `state.phase` in `state.json` under `error.sessionDir` says how far it got |
|