Selectors & Nodes
Overview
This chapter covers selector usage and the node info class.
Selector Objects
- Selector objects support cascading selection. When an element cannot be selected directly, select a parent first, then a child.
- Selectors partially support regex matching. See Java regex syntax in this tutorial.
XPath Selection
- XPath selector; see : https://www.jianshu.com/p/c205334122b3 and https://www.runoob.com/xpath/xpath-syntax.html
- Use the IDE node panel to inspect xpath attributes and test xpath
- Requires EC 10.12.0+
- @param value e.g. //node[@text='Sample'] selects nodes with that text
function main() {
// Get selector object
var selector = xpath("//node[@clz='android.widget.TextView']");
let n = selector.getNodeInfo(1000);
logd(JSON.stringify(n))
}
main();
text Attribute Selection
Full Text Match
function main() {
// Get selector object
var selector = text("Settings");
click(selector);
}
main();
Regex Match
function main() {
// Get selector object
var selector = textMatch(".*Settings.*");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
id Attribute Selection
Full Match
function main() {
// Get selector object
var selector = id("com.xx:id/a1");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
Regex Match
function main() {
// Get selector object
var selector = idMatch(".*id8.*");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
clz Attribute Selection
Full Match
function main() {
// Get selector object
var selector = clz("android.widget.TextView");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
Regex Match
function main() {
// Get selector object
var selector = clzMatch(".*TextView.*");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
pkg Attribute Selection
Full Match
function main() {
// Get selector object
var selector = pkg("com.xx");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
Regex Match
function main() {
// Get selector object
var selector = pkgMatch(".*tencent.*");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
desc Text Attribute Selection
Full Match
function main() {
// Get selector object
var selector = desc("My description");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
Regex Match
function main() {
// Get selector object
var selector = descMatch(".*Description.*");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main()
Depth and Drawing Order Matching
drawingOrder
function main() {
// Get selector object
var selector = drawingOrder(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
depth
function main() {
// Get selector object
var selector = depth(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
other Matching Rules
visible Visible Attribute Match
- Match on visible attribute
- @param value string
- @return
{Selector}node selector
function main() {
var node = visible(true).getOneNodeInfo(1000);
logd("node " + node);
}
main();
bounds Bounds Match
- Match on bounds region
- @param left Left bound
- @param top Top bound
- @param right Right bound
- @param bottom Bottom bound
- @return
{Selector}node selector
function main() {
// Get selector object controls within bounds 0–800
var selector = bounds(0, 0, 800, 800);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
checkable
function main() {
// Get selector object
var selector = checkable(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
checked
function main() {
// Get selector object
var selector = checked(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
clickable
function main() {
// Get selector object
var selector = clickable(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
longClickable
function main() {
// Get selector object
var selector = longClickable(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
scrollable
function main() {
// Get selector object
var selector = scrollable(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
focusable
function main() {
// Get selector object
var selector = focusable(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
enabled
function main() {
// Get selector object
var selector = enabled(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
focused
function main() {
// Get selector object
var selector = focused(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
selected
function main() {
// Get selector object
var selector = selected(true);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
index
function main() {
// Get selector object
var selector = index(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
childCount
function main() {
// Get selector object
var selector = childCount(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
row
function main() {
// Get selector object
var selector = row(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
column
function main() {
// Get selector object
var selector = column(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
rowSpan
function main() {
// Get selector object
var selector = rowSpan(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
columnSpan
function main() {
// Get selector object
var selector = columnSpan(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
rowCount
function main() {
// Get selector object
var selector = rowCount(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
columnCount
function main() {
// Get selector object
var selector = columnCount(1);
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
Cascading Matching
function main() {
// Get selector object
// Select children under ScrollView parentclz=android.widget.CheckBox all nodes
var selector = clz("android.widget.ScrollView")
.child()
.clz("android.widget.CheckBox");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
Multi-attribute Matching
function main() {
// Get selector object,
// Select CheckBox elements containing "Selector" with checked=true
var selector = textMatch(".*Selector.*")
.checked(true)
.clz("android.widget.CheckBox");
var result = click(selector);
if (result) {
toast("Click succeeded");
} else {
toast("Click failed");
}
}
main();
Node Info Class
Overview
NodeInfo objects are returned as arrays from getNodeInfo; node fields include:
- id: string — resource ID
- clz: string — view class name, e.g. android.widget.TextView
- pkg: string — package name, e.g. com.xx
- desc: string — content description
- text: string — text content
- checkable: Boolean — whether checkable
- checked: Boolean — whether checked
- clickable: Boolean — whether clickable
- enabled: Boolean — whether enabled
- focusable: Boolean — whether focusable
- focused: Boolean — whether focused
- longClickable: Boolean — whether long-clickable
- scrollable: Boolean — whether scrollable
- selected: Boolean — whether selected
- childCount: int — number of child nodes
- index: int — node index
- depth: int — node depth
- drawingOrder: int — drawing order
- bounds: Rect — bounds object
- top: int — top position
- bottom: int — bottom position
- left: int — left position
- right: int — right position
- visibleBounds: Rect — visible bounds object
- top: int — top position
- bottom: int — bottom position
- left: int — left position
- right: int — right position
Get one node with selector getOneNodeInfo
- Get the first node via selector
- @param timeout Wait time in ms; 0 = no wait
- @return
{NodeInfo}object or null
function main() {
// Get selector object
// Select all CheckBox nodes: clz=android.widget.CheckBox
var node = clz("android.widget.CheckBox").getOneNodeInfo(10000);
if (node) {
var x = node.click();
logd(x);
} else {
toast("No node");
}
}
main();
Get multiple nodes with selector getNodeInfo
- Get node information
- @param timeout Wait time in ms; 0 = no wait
- @return
{array}Collection of NodeInfo nodes
function main() {
// Get selector object
// Select all CheckBox nodes: clz=android.widget.CheckBox
var node = clz("android.widget.CheckBox").getNodeInfo(10000);
// This is an array
for (let i = 0; i < node.length; i++) {
logd(JSON.stringify(node[i]))
}
}
main();
Cascade get one child node getOneNodeInfo
- Get the first node via selector
- @param timeout Wait time in ms; 0 = no wait
- @return
{NodeInfo}object or null
function main() {
// Get selector object
// Select all ViewGroup nodes: clz=android.widget.ViewGroup
var node = clz("android.widget.ViewGroup").getOneNodeInfo(10000);
if (node) {
// Get child nodes
node = node.getOneNodeInfo(text("Ad"), 10000);
if (!node) {
toast("No child nodes");
return;
}
var x = node.click();
logd(x);
} else {
toast("No node");
}
}
main();
Cascade get multiple child nodes getNodeInfo
- Get node information
- @param timeout Wait time in ms; 0 = no wait
- @return
{array}Collection of NodeInfo nodes
function main() {
// Get selector object
// Select all ViewGroup nodes: clz=android.widget.ViewGroup
var node = clz("android.widget.ViewGroup").getNodeInfo(10000);
if (node) {
// Get child nodes
node = node.getNodeInfo(text("Ad").clz("android.widget.TextView"), 10000);
if (!node) {
toast("No child nodes");
return;
}
var x = node.click();
logd(x);
} else {
toast("No node");
}
}
main();
Get parent node
- Parent node of this node
- @return
{NodeInfo}object or null
function main() {
// Get selector object
// Select all CheckBox nodes: clz=android.widget.CheckBox
var node = clz("android.widget.CheckBox").getOneNodeInfo(10000);
if (node) {
var x = node.parent();
logd(x);
} else {
toast("No node");
}
}
main();
Get child node
- Get a single child node
- @param index child node index
- @return
{NodeInfo}object or null
function main() {
// Select all ViewGroup nodes: clz=android.widget.ViewGroup
var node = clz("android.widget.ViewGroup").getOneNodeInfo(10000);
if (node) {
var x = node.child(0);
logd(x);
} else {
toast("No node");
}
}
main();
Get all child nodes
- Get all child nodes
- @return
{NodeInfo}node collection
function main() {
// Select all ViewGroup nodes: clz=android.widget.ViewGroup
var node = clz("android.widget.ViewGroup").getOneNodeInfo(10000);
if (node) {
var x = node.allChildren();
// This is an array
for (let i = 0; i < x.length; i++) {
logd(x[i])
}
} else {
toast("No node");
}
}
main();
All sibling nodes
- All sibling nodes of the current node
- @return
{NodeInfo}node collection
function main() {
// Select all ViewGroup nodes: clz=android.widget.ViewGroup
var node = clz("android.widget.ViewGroup").getOneNodeInfo(10000);
if (node) {
var x = node.siblings();
// This is an array
for (let i = 0; i < x.length; i++) {
logd(x[i])
}
} else {
toast("No node");
}
}
main();
Previous sibling nodes previousSiblings
- Sibling nodes before the current node
- @return
{NodeInfo}node collection
function main() {
// Select all ViewGroup nodes: clz=android.widget.ViewGroup
var node = clz("android.widget.ViewGroup").getOneNodeInfo(10000);
if (node != null) {
let x = node.previousSiblings();
// This is an array
for (let i = 0; i < x.length; i++) {
logd(x[i])
}
} else {
toast("No node");
}
}
main();
Next sibling nodes nextSiblings
- Sibling nodes after the current node
- @return
{NodeInfo}node collection
function main() {
// Select all ViewGroup nodes: clz=android.widget.ViewGroup
var node = clz("android.widget.ViewGroup").getOneNodeInfo(10000);
if (node) {
let x = node.nextSiblings();
// This is an array
for (let i = 0; i < x.length; i++) {
logd(x[i])
}
} else {
toast("No node");
}
}
main();