///

Element Class

Element is the action from a script. It targets real app elements rather than pixels, so it only works on regular apps, games expose nothing to match.

Finding an element

Four named finders cover almost everything:

Element.text("Continue") // its visible text Element.label("Search") // its accessibility label Element.id("com.app:id/submit") // its view id, the most stable Element.type("EditText") // the kind of element

Matching is contains by default, the same as the action. Pass options as a second argument:

Element.text("Send", { exact: false, // match the whole value, not part of it startsWith: false, // match from the beginning regex: false, // treat the value as a pattern index: 1, // which match, counted top to bottom then left to right clickable: false, // only match something that can be clicked enabled: false, // only match something not greyed out editable: false, // only match a text field checked: false // only match a switch or checkbox that is on });
OptionWhat it does
exactMatch the whole value, not part of it.
startsWithMatch from the beginning.
regexTreat the value as a regular expression.
indexWhich match to use when several fit. 1 is the first, top to bottom.
clickable / enabled / editable / checkedOnly match an element in that state.

To require several attributes at once, pass an object instead. Every attribute you give must match:

Element({ type: "Button", label: "Notify" }).click(); Element({ text: "Send", exact: true, index: 2 }).click();

The handle re-runs its search on every call, so it stays valid as the screen changes.

Methods

Every method takes an options object. timeout is milliseconds, 0 checks once, which is the default for the read-only calls; the acting ones default to 5000.

.find(opts?)

The match object below. found is false when nothing matched.

let result = .find('demo'); console.log(result);

.exists(opts?)

Whether it is there.

let result = .exists('demo'); console.log(result);

.isPresent(opts?)

Whether it is there.

let result = .isPresent('demo'); console.log(result);

.count()

How many elements match, in the same order match numbers use.

let result = .count(); console.log(result);

.findAll()

Every match, as an array of match objects.

let result = .findAll(); console.log(result);

.waitFor(opts?)

Wait until it appears. Returns whether it did.

.waitFor('demo');

.waitGone(opts?)

Wait until it disappears.

.waitGone('demo');

.read(opts?)

Its text, falling back to its label. null on a miss.

let result = .read('demo'); console.log(result);

.readValue(opts?)

A slider or progress bar's current value.

let result = .readValue('demo'); console.log(result);

.click(opts?)

Click it. Options: method (GESTURE or ACTION), duration, repeat, delay, waitAfter, radius, longPress.

.click('demo');

.longClick(opts?)

Long-press it.

let result = .longClick('demo'); console.log(result);

.type(text, opts?)

Type into it. Options: append, enter.

let result = .type('Daily Reward Ready', 'demo'); console.log(result);

.setValue(n, opts?)

Set a slider or progress bar to n. Returns the value applied.

.setValue('demo', 'demo');

.scrollTo(opts?)

Scroll its list until it is visible. Option direction: AUTO, FORWARD, BACKWARD.

let result = .scrollTo('demo'); console.log(result);

.isChecked(opts?)

State checks.

let result = .isChecked('demo'); console.log(result);

.isEnabled(opts?)

State checks.

let result = .isEnabled('demo'); console.log(result);

.isSelected(opts?)

State checks.

let result = .isSelected('demo'); console.log(result);

GESTURE clicks are a real tap at the element's centre. ACTION fires the element's own click, so it cannot be mis-aimed and works when something covers it, but duration and radius do not apply.

// Every method option, with its default el.find({ timeout: 0 }); el.exists({ timeout: 0 }); el.waitFor({ timeout: 5000 }); el.waitGone({ timeout: 5000 }); el.read({ timeout: 0 }); el.readValue({ timeout: 0 }); el.click({ method: "GESTURE", duration: 50, repeat: 1, delay: 0, waitAfter: 0, radius: 0, longPress: false, timeout: 5000 }); el.longClick({ duration: 50, timeout: 5000 }); el.type("hello", { append: false, enter: false, timeout: 5000 }); el.setValue(50, { timeout: 5000 }); el.scrollTo({ direction: "AUTO", timeout: 5000 }); el.isChecked({ timeout: 0 }); el.isEnabled({ timeout: 0 }); el.isSelected({ timeout: 0 }); el.count(); // no options el.findAll(); // no options

The match object

.find() and .findAll() return:

{ "found": true, "x": 540, "y": 960, "cx": 540, "cy": 960, "left": 300, "top": 920, "right": 780, "bottom": 1000, "w": 480, "h": 80, "text": "Continue", "label": null, "id": "com.app:id/next", "type": "android.widget.Button", "clickable": true, "enabled": true, "checked": false, "selected": false }

On a miss you get { "found": false } and nothing else, so always guard on found.

let row = Element.text("Daily reward").find({ timeout: 3000 }); if (row.found) { console.log(row.text + " at " + row.x + "," + row.y); swipe(row.x, row.y, row.x - 400, row.y, { duration: 300 }); }