# `mix mob.smoke`
[🔗](https://github.com/genericjam/mob_dev/blob/master/lib/mix/tasks/mob.smoke.ex#L1)

Replay the `agent-device` flows in `smoke/` on each selected device, then
check the app's own diagnostics agree that nothing broke.

    mix mob.smoke                         # the one connected emulator/simulator
    mix mob.smoke --device emulator-5554
    mix mob.smoke --all-devices --junit _build/smoke.xml

Needs the `agent-device` CLI (`npm i -g agent-device`) and the app installed
and running on the device. Flows are `.ad` scripts recorded by hand; see the
"Smoke flows on devices" section of the README for the recipe.

## What is checked

1. **The device is free.** A device another `agent-device` session holds is
   skipped and reported with that session and workspace. The run fails.
2. **The flows pass.** `agent-device test` runs the `<flows>/*.ad` scripts.
   Its JSON says `"success": true` even when scripts fail, so the counts are
   what is judged: any failed or not-run flow, or none executed, fails.
3. **The app held up** (unless `--no-health`). `Mob.Diag.health/0` is read
   over dist before the first flow and after each one, attaching without
   restarting the app. A store whose `lost` or `resets` rose, or a rise in
   the listener's undeliverable events, fails the run. On mob 0.9.7 or
   later, which receipts native taps, no new receipts during a flow is a
   warning: its taps did not reach this app (on older mob it is a note). An
   unreachable node, or a mob too old for these functions, is a note, and
   those flows are reported as not checked: the summary's health column
   says so and a passing run does not claim the app held up. If the node
   is unreachable at the start, it is awaited once more after the first flow.

The counters belong to the app's BEAM, and a flow that opens with
`--relaunch` starts a new one. So with health on each flow is its own
`agent-device test` run, health is read between flows (waiting up to 15 s
for a relaunched app's node to come back), and a reading from a new BEAM is
compared against zero. Health that cannot be read after a flow is a warning
naming that flow. With `--no-health` the flows run as one suite.

## Options

  * `--device` / `--only` (`-d`) — target a device by serial/udid. Repeatable
  * `--all-devices`  — every emulator and simulator
  * `--all-physical` — every physical device (with `--all-devices`: everything)
  * `--ios-only` / `--android-only` — restrict discovery to one platform
  * `--flows DIR`    — directory of `.ad` flows (default: `smoke`)
  * `--retries N`    — retry each failed flow up to N times (default: 0).
    Always passed to agent-device, so it overrides a script's own
    `context retries=`
  * `--artifacts-dir DIR` — agent-device artifacts under `DIR/<device>/`
    (per flow, `DIR/<device>/<flow>/`; default: `_build/mob_smoke`)
  * `--junit PATH`   — JUnit reports, the device id (and, per flow, the flow
    name) appended to the file name
  * `--no-health`    — skip the `Mob.Diag` comparison
  * `--fail-fast`    — stop a device's flows at the first one that fails the
    run: a failed replay, a non-zero exit, or a health failure
  * `--cookie C`     — dist cookie (default: the app's private cookie)

With no selection flags exactly one emulator/simulator is picked; a lone
phone needs `--device` or `--all-physical`, because the flows drive it.

## Exit status

Non-zero when any device failed a flow, was blocked or could not be
addressed, or had a health failure.

## Android and mobile-mcp

Android allows one UiAutomation client. While mobile-mcp's
`com.mobilenext.mobilecli.DeviceServer` runs on the phone, agent-device
snapshots fail with "Android snapshot helper output could not be parsed".
The report then names the command that stops it; it is not stopped for you.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
