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 elementMatching 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
});| Option | What it does |
|---|---|
exact | Match the whole value, not part of it. |
startsWith | Match from the beginning. |
regex | Treat the value as a regular expression. |
index | Which match to use when several fit. 1 is the first, top to bottom. |
clickable / enabled / editable / checked | Only 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 optionsThe 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 });
}