Element

A selector bound to a device. Every method resolves the selector again on the device, so nothing goes stale between calls; mutations require exactly one match.

All I/O methods are suspend and require an owning scope (tapScope/tapTest); derived selectors (descendant, child, first, at, await) only build values, so they stay non-suspend.

Properties

Link copied to clipboard
Link copied to clipboard

Functions

Link copied to clipboard
fun at(index: Int): Element

Accept the index-th match (0-based) in accessibility order. Builds a value; no I/O.

Link copied to clipboard
fun await(timeout: Duration = device.timeouts.wait): ElementWait

An ElementWait on this selector. Builds a value; no I/O, so not suspend.

Link copied to clipboard
fun child(other: Selector): Element

The direct child of this node matching other. Builds a value; no I/O.

Link copied to clipboard
suspend fun clearText(timeout: Duration? = null)

setText with an empty string: ACTION_SET_TEXT on the one matching node, not read back.

Link copied to clipboard
suspend fun count(timeout: Duration? = null): Int

Matches in the selector's scope right now, ignoring its match limit.

Link copied to clipboard

The node matching other somewhere below this one. Builds a value; no I/O.

Link copied to clipboard
suspend fun doubleTap(timeout: Duration? = null)

Two taps at the centre of the one matching node's visible bounds, inside Android's double-tap window.

Link copied to clipboard
suspend fun dragTo(destination: Selector, timeout: Duration? = null)

Presses the one matching node until it is a long press, moves the finger to the centre of the one node matching destination (resolved on the same screen, before any input), holds there briefly and lifts. Nothing is reported about what the app did with the drop.

Link copied to clipboard
suspend fun exists(timeout: Duration? = null): Boolean

True when at least one node matches right now (any number of matches is fine).

Link copied to clipboard
fun first(): Element

Accept the first match in accessibility order instead of requiring exactly one. Builds a value; no I/O.

Link copied to clipboard
suspend fun fling(direction: Direction, timeout: Duration? = null)

One fast swipe across the one matching node towards direction's content edge (as for scroll: DOWN flings towards content below). Returns once the finger lifts; the content may keep moving, so wait for what you need next.

Link copied to clipboard
suspend fun imeAction(timeout: Duration? = null)

Runs the one matching text field's keyboard action (Search, Go, Send, Done, … as the app configured it) exactly as the keyboard's action key does, through accessibility ACTION_IME_ENTER. API 30+: older devices fail with UNSUPPORTED / REQUIRES_API_30 before any input (pressing Enter is not equivalent). The field must have input focus (tap it first): Android offers the action only then, and a node that does not offer it fails with ACTION_REJECTED before any input.

Link copied to clipboard
suspend fun isChecked(timeout: Duration? = null): Boolean

snapshot().checked of the one matching node.

Link copied to clipboard
suspend fun isEnabled(timeout: Duration? = null): Boolean

snapshot().enabled of the one matching node.

Link copied to clipboard
suspend fun longTap(timeout: Duration? = null)

Long click on the one matching node.

Link copied to clipboard
suspend fun performAction(action: StandardAction, timeout: Duration? = null)

Performs a standard accessibility action on the one matching node, as a screen reader does: no touch, so a covered node is no obstacle. The node must offer it (ElementSnapshot.actions); otherwise ACTION_REJECTED / ACTION_NOT_OFFERED before any input. A node that refuses an offered action is ACTION_REJECTED. Only Android's answer is reported: assert what the app did.

Link copied to clipboard
suspend fun performCustomAction(label: String, timeout: Duration? = null)

Performs the custom accessibility action labelled label (exactly) on the one matching node: the "Archive" or "Delete" a list item offers screen reader users instead of a swipe (ElementSnapshot.customActions). Not offered, or offered twice under that label: ACTION_REJECTED / ACTION_NOT_OFFERED before any input.

Link copied to clipboard
suspend fun pinchClose(percent: Int = DEFAULT_GESTURE_PERCENT, timeout: Duration? = null)

Two fingers moving together towards the one matching node's centre, across percent of its size.

Link copied to clipboard
suspend fun pinchOpen(percent: Int = DEFAULT_GESTURE_PERCENT, timeout: Duration? = null)

Two fingers moving apart from the one matching node's centre, across percent of its size.

Link copied to clipboard
suspend fun scroll(direction: Direction, distancePercent: Int = DEFAULT_GESTURE_PERCENT, timeout: Duration? = null)

One scroll gesture on the one matching node towards direction's content edge (UiAutomator semantics: DOWN reveals content below). Nothing is reported about whether content moved; observe that with a query or wait.

Link copied to clipboard
suspend fun scrollUntil(target: Selector, direction: Direction = Direction.DOWN, maxScrolls: Int = 20, distancePercent: Int = DEFAULT_GESTURE_PERCENT, timeout: Duration? = null): Element

Client-side loop: checks whether target exists inside this container (descendant) and, while it does not, scrolls once, up to maxScrolls scrolls within timeout (default the device's wait timeout). Returns the target as a lazy element scoped to this container, so a later action cannot hit a duplicate elsewhere on screen; a container with first()/at() cannot be carried into a relation, and then the bare target is used.

Link copied to clipboard
suspend fun setProgress(value: Float, timeout: Duration? = null)

Sets the one matching range node (SeekBar, Slider, RatingBar) to value in its own units (ElementSnapshot.range) through accessibility ACTION_SET_PROGRESS: exact, where a drag would land on whatever pixel maps to. A node without the action, or a value outside its min..max, is ACTION_REJECTED (ACTION_NOT_OFFERED / OUT_OF_RANGE) before any input; the view is not left to clamp it.

Link copied to clipboard
suspend fun setText(value: String, timeout: Duration? = null)

Accessibility text replacement (ACTION_SET_TEXT) on the one matching node. Fails with ACTION_REJECTED only when the node refuses the action; the field is not read back, so assert the effect yourself with a selector that survives the edit: app.await(res("email")).textEquals("new").

Link copied to clipboard
suspend fun snapshot(timeout: Duration? = null): ElementSnapshot

State of the one matching node at this instant (AMBIGUOUS/NOT_FOUND otherwise).

Link copied to clipboard
suspend fun swipe(direction: Direction, distancePercent: Int = DEFAULT_GESTURE_PERCENT, timeout: Duration? = null)

Finger gesture across the element in direction.

Link copied to clipboard
suspend fun tap(timeout: Duration? = null)

Click at the centre of the one matching node's visible bounds.

Link copied to clipboard
suspend fun text(timeout: Duration? = null): String?

Raw accessibility text of the one matching node, or null when it has none. On API 26+ an empty field reports its hint here; snapshot().showingHint says so.

Link copied to clipboard
open override fun toString(): String
Link copied to clipboard
suspend fun typeText(value: String, awaitFocus: Boolean = true, timeout: Duration? = null)

Taps the one matching node, waits until it reports focus (with awaitFocus; bounded by the wait timeout), then types value as real key events with Device.typeText. Three steps, so a failure says which one failed. Pass awaitFocus = false when focus goes elsewhere (a child or a separate input view), and wait for what that app needs yourself. The field is not read back: assert the effect yourself.