dusk:find
Mint a re-resolvable q handle backed by one or more predicates (text, semanticsLabel, key). Mirrors Playwright's Locator semantics: every action call against a qN handle re-walks the live Semantics tree on each invocation, so the handle survives intermediate widget rebuilds without going stale.
qN and eN token spaces are disjoint. A handle minted by dusk:find is always qN; a handle harvested from dusk:snap is always eN. The dispatcher distinguishes by prefix, but action commands accept either shape via --ref=.
Table of contents
Synopsis
dart run fluttersdk_dusk dusk:find [--text=]
[--contains=]
[--semanticsLabel=]
[--key=]
dusk:find requires a running Flutter session (CommandBoot.connected). It dials the VM Service URI, calls ext.dusk.find with the supplied predicates, and prints the minted handle envelope as pretty-printed JSON.
At least one of the four options must be non-empty; an empty params map returns exit code 1 with a CLI-side error before the VM Service call.
Arguments
| Option | Type | Default | Description |
|---|---|---|---|
--text |
string | unset | Exact match against the widget's visible text label (the Semantics value or rendered Text content). Most common predicate; mirrors Playwright's getByText with exact-match semantics. |
--contains |
string | unset | Substring match against the visible text label or Semantics label (case-sensitive). Use when the label is dynamic (counters, timestamps, plurals) and exact --text is too brittle. |
--semanticsLabel |
string | unset | Exact match against the widget's accessibility label (the explicit Semantics(label: ...) value set by the widget tree). Use when the visible text and the a11y label diverge. |
--key |
string | unset | Match the widget's ValueKey identifier (the Key('signin-button') form). Most precise; survives label and copy changes. |
The predicates compose AND: a dusk:find --text=Sign --key=signin-button call returns the widget that matches both. Use a single predicate when the agent only needs one axis.
The CLI guards an empty params map (Provide at least one of --text / --contains / --semanticsLabel / --key.) so the VM Service handler never sees a zero-predicate call.
Returns
dusk:find returns an integer exit code via Future:
| Exit code | Meaning |
|---|---|
0 |
Handle minted (or re-used; the registry is content-addressed). The handler emits the JSON envelope below. |
1 |
No predicate supplied. The CLI guard fires before the VM Service call. |
| non-zero | VM Service handler returned ServiceExtensionResponse.error. Typical cause: the predicate matched zero widgets (no matches surfaces as a structured failure so the agent knows to broaden the predicate). |
Success envelope (illustrative):
{
"ref": "q1",
"matchCount": 1,
"rect": [120, 400, 240, 48],
"role": "button",
"label": "Sign in"
}
matchCount > 1 indicates the predicate is ambiguous: the handle still resolves to the first match, but the agent should narrow with an extra predicate (typically --key) before acting.
Error envelope:
The VM Service handler propagates errors as ServiceExtensionResponse.error(extensionError, message). The CLI surfaces them via ArtisanContext.callExtension and exits non-zero. Common messages include No widget matched predicates: {...}.
Re-resolution semantics
A qN handle stores the predicate map, not the matched widget. Every action call (dusk:tap --ref=q1, dusk:type --ref=q1, etc.) re-executes the query against the live Semantics tree. Three consequences:
- Widget rebuilds don't invalidate the handle. A
ListViewswap, a navigation transition, or a state-driven rebuild all leave the handle valid as long as the predicates still match something. - The query is re-run on every action. Cheap (a Semantics walk on each call), but emergent if the predicate is broad: prefer
--keyover--textfor hot paths. dusk:finditself is idempotent in the registry. Calling it twice with the same predicate map returns the sameqN; the registry is content-addressed.
eN handles minted by dusk:snap work the opposite way: they freeze the matched widget at snap time and go stale on the next rebuild. Use eN for one-shot reads, qN for any sequence that spans more than one frame.
Examples
1. Mint a handle by visible text
dart run fluttersdk_dusk dusk:find --text="Sign in"
Expected output (illustrative):
{
"ref": "q1",
"matchCount": 1,
"rect": [120, 400, 240, 48],
"role": "button",
"label": "Sign in"
}
Reuse q1 across subsequent action calls:
dart run fluttersdk_dusk dusk:tap --ref=q1
2. Mint a handle by accessibility label
dart run fluttersdk_dusk dusk:find --semanticsLabel="Submit form"
Use when the rendered button text is an icon and the only stable predicate is the a11y label.
3. Mint a handle by widget key (most precise)
dart run fluttersdk_dusk dusk:find --key="signin-submit"
Survives copy changes and a11y-label changes. Pair with a widget-side Key('signin-submit') declaration.
4. Mint a handle by substring (dynamic label)
dart run fluttersdk_dusk dusk:find --contains="pushed the button"
Useful when the visible label is dynamic, e.g. "You have pushed the button 5 times:" (counter changes per tap). --text would only match the exact string at the moment of capture; --contains survives the counter advancing.
5. Compose two predicates to disambiguate
dart run fluttersdk_dusk dusk:find --text="Save" --key="monitor-form-save"
The two predicates AND together; useful when the screen has multiple "Save" buttons but only one with the canonical key.
See also
- dusk:snap: produce
eNrefs for one-shot reads. - dusk:tap: consume the
qNref to synthesise a tap. - dusk:observe: structured candidate list of every interactive widget; useful when the agent doesn't know which predicate to query.