dusk:tap
Synthesise a tap at the widget identified by a snapshot ref token. dusk:tap is the primary action command: every interactive flow in an agent-driven test starts with a dusk:snap (to obtain eN refs) followed by one or more dusk:tap --ref= calls.
The handler routes through the actionability gate (enabled, zero-rect, off-viewport) before the pointer event leaves the VM. A gate failure throws DuskActionabilityException and surfaces as a structured error; the agent re-snaps or re-finds rather than silently retrying.
Table of contents
Synopsis
dart run fluttersdk_dusk dusk:tap --ref=
[--includeSnapshot]
[--[no-]checkStable]
[--[no-]checkReceivesEvents]
[--verify]
[--until=]
[--untilTimeoutMs=]
dusk:tap requires a running Flutter session (CommandBoot.connected). It dials the VM Service URI, calls ext.dusk.tap, and prints either a one-line success or the post-tap JSON depending on --includeSnapshot / --verify.
The pointer is dispatched at the target's LIVE center: the handler re-resolves the element's current bounding rect immediately after the actionability gate passes (falling back to the cached snapshot rect only for slivers / detached render objects), so a tap still lands on a button whose host rebuilt it into a shifted slot between dusk:snap and dusk:tap.
Arguments
| Option | Type | Default | Required | Description |
|---|---|---|---|---|
--ref |
string | (none) | yes (mandatory: true) |
Snapshot ref token (e.g. e1 from a prior dusk:snap, or q1 from a prior dusk:find). Empty values trigger a CLI-side error with exit code 1 before the VM Service call is made. |
--includeSnapshot |
flag | false |
no | Embed the post-tap snapshot YAML in the response. Useful when the tap is expected to trigger a navigation or modal and the next agent step needs the fresh tree. |
--checkStable |
flag | true |
no | Run the Stable (2-frame rect-unchanged) actionability gate. Disable when targeting an animating widget that intentionally rebuilds across frames. |
--checkReceivesEvents |
flag | true |
no | Run the Receives-Events (front-most hit-test) actionability gate. Disable when targeting a widget that is intentionally occluded by an overlay you also want to interact with. |
--verify |
flag | false |
no | Capture a target-scoped before/after signal (the nearest enclosing route name plus a hash of the target element's own semantics subtree) and add a changed boolean to the response reporting whether the tap produced an observable effect on the target. Off by default, which keeps the response shape unchanged. Enabling --verify always prints the JSON envelope (so the changed field is visible) regardless of --includeSnapshot. |
--until |
string | (none) | no | After the tap settles, poll the live element tree (same loop as dusk:wait) for a Text whose data equals this value, up to the --untilTimeoutMs timeout (default 3000ms), and add an untilMatched boolean to the response reporting whether it appeared. Use to confirm a navigation / state change in one call instead of a separate dusk:wait. Off by default, which keeps the response shape unchanged. Setting --until always prints the JSON envelope (so untilMatched is visible) regardless of --includeSnapshot. |
--untilTimeoutMs |
int | 3000 |
no | Timeout in milliseconds for the --until poll. Ignored when --until is not set. |
The two check* flags default to true. Disable them with the inverted form (--no-checkStable, --no-checkReceivesEvents) when the target genuinely should not be subject to that precondition.
Returns
dusk:tap returns an integer exit code via Future:
Success envelope (default, --includeSnapshot off):
[ok] Tapped e2
Success envelope (--includeSnapshot on):
{
"snapshot": "[ref=e1] role=text label=\"Welcome\" ...",
"ref": "e2"
}
Success envelope (--verify on):
{
"ref": "e2",
"changed": true
}
changed is true when the target's route or semantics subtree differed after the tap, false when nothing observable changed (a false-success signal the agent can branch on). The changed field is omitted entirely when --verify is off.
Error envelope (actionability gate failure):
The message format is Widget ref= is not actionable: where is one of defunct (...), not enabled, zero rect, off-viewport (rect=..., viewport=...), not stable (rect changed by Xpx), or obscured by other widget (top=...). The agent branches by substring-matching on ; the full vocabulary is documented under Reference: Actionability gate.
Actionability gate
The actionability gate runs six preconditions in order: defunct (Step 0, preflight: render-object still attached), enabled (Tristate.isFalse fails), zero-rect (zero width or height), off-viewport (auto-showOnScreen first when a Scrollable ancestor exists), stable (2-frame rect drift ≤ 0.5px; opt out via --no-checkStable), and receives-events (hit-test path includes the target or descendant; opt out via --no-checkReceivesEvents). The full reference lives at Reference: Actionability gate.
Two further checks layer on top when their CLI flags are enabled:
checkStable; the rect is unchanged across two consecutive frames.checkReceivesEvents; the hit-test at the rect center resolves to the target widget (i.e. no overlay is intercepting the tap).
See Reference: Actionability gate for the full ordering rationale and how new preconditions can be appended without breaking pinned agent prompts.
Examples
1. Tap a button by its snapshot ref
dart run fluttersdk_dusk dusk:snap > /tmp/snap.yaml
# locate the button's eN in /tmp/snap.yaml
dart run fluttersdk_dusk dusk:tap --ref=e2
Expected output (illustrative):
[ok] Tapped e2
2. Tap and capture the post-tap tree in one round trip
dart run fluttersdk_dusk dusk:tap --ref=e2 --includeSnapshot
Expected output (illustrative; abbreviated):
{"snapshot":"[ref=e1] role=text label=\"Detail page\" ...","ref":"e2"}
3. Tap an intentionally-animating widget
dart run fluttersdk_dusk dusk:tap --ref=e5 --no-checkStable
Skips the 2-frame stable check for an animating loader / shimmer / spinner that the agent legitimately wants to interact with.
4. Tap and verify the tap had an observable effect
dart run fluttersdk_dusk dusk:tap --ref=e2 --verify
Expected output (illustrative):
{"ref":"e2","changed":true}
changed:false flags a tap that the gate accepted but that produced no observable effect on the target (the classic false-success: a button that looks tappable but whose onTap never fired). Use it as a post-condition assertion in agent-driven flows.
5. Tap and wait for the expected text to appear
dart run fluttersdk_dusk dusk:tap --ref=e2 --until="Welcome back"
Expected output (illustrative):
{"ref":"e2","untilMatched":true}
After the tap, the handler polls the element tree for a Text("Welcome back") up to 3000ms. untilMatched:false means the text never appeared within the window (the tap did not produce the expected navigation / state change). This folds a dusk:wait --text=... into the tap call so the agent confirms the outcome in one round trip.
See also
- dusk:snap: produce the
eNrefs thatdusk:tapconsumes. - dusk:find: mint a re-resolvable
qNhandle that survives rebuilds; pass it as--ref=q1. - dusk:observe: structured candidate list when the agent needs more than the raw Semantics tree.
- Reference: Actionability gate: full ordering and message format the agent branches on.