AndroidNodeFilter
InterfaceBuilder pattern for complex node queries
AndroidNodeFilter provides a fluent builder interface for constructing complex queries to find nodes in the accessibility tree. All methods are chainable and return the filter instance.
// Find a submit buttonconst button = screen.findAdvanced(f => f.isButton().hasText("Submit"));
// Find all editable text fieldsconst inputs = screen.filterAdvanced(f => f.isEditText().isEditable());
// Complex query with multiple conditionsconst node = screen.findAdvanced(f => f.isClickable() .hasPackageName("com.example.app") .anyParent(p => p.hasId("com.example:id/main_container")));Class Matchers
Match nodes based on their Android class type.
isButton()
isButton(): AndroidNodeFilterMatches nodes with className 'android.widget.Button'.
Examples
const buttons = screen.filterAdvanced(f => f.isButton());isText()
isText(): AndroidNodeFilterMatches nodes with className 'android.widget.TextView'.
Examples
const labels = screen.filterAdvanced(f => f.isText());isImage()
isImage(): AndroidNodeFilterMatches nodes with className 'android.widget.ImageView'.
Examples
const images = screen.filterAdvanced(f => f.isImage());isEditText()
isEditText(): AndroidNodeFilterMatches nodes with className 'android.widget.EditText' (text input fields).
Examples
const inputs = screen.filterAdvanced(f => f.isEditText());isCheckBox()
isCheckBox(): AndroidNodeFilterMatches nodes with className 'android.widget.CheckBox'.
Examples
const checkboxes = screen.filterAdvanced(f => f.isCheckBox());isRadioButton()
isRadioButton(): AndroidNodeFilterMatches nodes with className 'android.widget.RadioButton'.
Examples
const radios = screen.filterAdvanced(f => f.isRadioButton());isSwitch()
isSwitch(): AndroidNodeFilterMatches nodes with className 'android.widget.Switch'.
Examples
const switches = screen.filterAdvanced(f => f.isSwitch());isSeekBar()
isSeekBar(): AndroidNodeFilterMatches nodes with className 'android.widget.SeekBar'.
Examples
const sliders = screen.filterAdvanced(f => f.isSeekBar());isViewGroup()
isViewGroup(): AndroidNodeFilterMatches nodes with className 'android.view.ViewGroup' (container elements).
Examples
const containers = screen.filterAdvanced(f => f.isViewGroup());is()
is(className: string): AndroidNodeFilterMatches nodes with a custom className.
Parameters
| Name | Type | Description |
|---|---|---|
className | string | Full Android class name to match |
Examples
const recyclers = screen.filterAdvanced(f => f.is("androidx.recyclerview.widget.RecyclerView"));State Matchers
Match nodes based on their current state.
isClickable()
isClickable(): AndroidNodeFilterMatches nodes that are clickable.
Examples
const clickables = screen.filterAdvanced(f => f.isClickable());isScrollable()
isScrollable(): AndroidNodeFilterMatches nodes that are scrollable.
Examples
const scrollView = screen.findAdvanced(f => f.isScrollable());if (scrollView) { await scrollView.performAction(agent.constants.ACTION_SCROLL_DOWN);}isSelected()
isSelected(): AndroidNodeFilterMatches nodes that are currently selected.
Examples
const selectedItem = screen.findAdvanced(f => f.isSelected());isEditable()
isEditable(): AndroidNodeFilterMatches nodes that allow text editing.
Examples
const editableInputs = screen.filterAdvanced(f => f.isEditText().isEditable());Content Matchers
Match nodes based on their text content.
hasText()
hasText(text: string): AndroidNodeFilterMatches nodes with exact text content.
Parameters
| Name | Type | Description |
|---|---|---|
text | string | Exact text to match |
Examples
const submitBtn = screen.findAdvanced(f => f.isButton().hasText("Submit"));text()
text(condition: (text: string | undefined) => boolean): AndroidNodeFilterMatches nodes based on a custom text condition.
Parameters
| Name | Type | Description |
|---|---|---|
condition | (text: string | undefined) => boolean | Function to test the text |
Examples
const priceNodes = screen.filterAdvanced(f => f.text(t => t?.includes("$") ?? false));const items = screen.filterAdvanced(f => f.text(t => t?.startsWith("Item") ?? false));hasDescription()
hasDescription(description: string): AndroidNodeFilterMatches nodes with exact content description (accessibility label).
Parameters
| Name | Type | Description |
|---|---|---|
description | string | Exact description to match |
Examples
const closeBtn = screen.findAdvanced(f => f.hasDescription("Close"));descriptionContains()
descriptionContains(part: string): AndroidNodeFilterMatches nodes whose description contains the given text.
Parameters
| Name | Type | Description |
|---|---|---|
part | string | Text to search for in description |
Examples
const icons = screen.filterAdvanced(f => f.isImage().descriptionContains("icon"));description()
description(condition: (desc: string | undefined) => boolean): AndroidNodeFilterMatches nodes based on a custom description condition.
Parameters
| Name | Type | Description |
|---|---|---|
condition | (desc: string | undefined) => boolean | Function to test the description |
Examples
const nodes = screen.filterAdvanced(f => f.description(d => d?.toLowerCase().includes("button") ?? false));hasChildWithText()
hasChildWithText(text: string): AndroidNodeFilterMatches nodes that have a direct child with the specified text.
Parameters
| Name | Type | Description |
|---|---|---|
text | string | Text to find in children |
Examples
// Find containers that have a "Settings" label insideconst settingsSection = screen.findAdvanced(f => f.isViewGroup().hasChildWithText("Settings"));Identity Matchers
Match nodes based on their identity attributes.
hasId()
hasId(id: string): AndroidNodeFilterMatches nodes with the specified viewId.
Parameters
| Name | Type | Description |
|---|---|---|
id | string | View ID to match (e.g., 'com.example:id/button') |
Examples
const header = screen.findAdvanced(f => f.hasId("com.example:id/header_title"));hasPackageName()
hasPackageName(packageName: string): AndroidNodeFilterMatches nodes belonging to the specified package.
Parameters
| Name | Type | Description |
|---|---|---|
packageName | string | Package name to match |
Examples
// Only match nodes from a specific appconst appNodes = screen.filterAdvanced(f => f.hasPackageName("com.example.myapp"));hasChildWithId()
hasChildWithId(id: string): AndroidNodeFilterMatches nodes that have a direct child with the specified viewId.
Parameters
| Name | Type | Description |
|---|---|---|
id | string | View ID to find in children |
Examples
// Find containers with specific child elementsconst container = screen.findAdvanced(f => f.hasChildWithId("com.example:id/item_icon"));Logical Operators
Combine multiple conditions using logical operators.
and()
and(filterBuilder: (f: AndroidNodeFilter) => void): AndroidNodeFilterCombines with another filter using AND logic. The node must match both filters.
Parameters
| Name | Type | Description |
|---|---|---|
filterBuilder | (f: AndroidNodeFilter) => void | Function to build the additional filter |
Examples
// Find clickable buttons with specific textconst btn = screen.findAdvanced(f => f.isButton().and(a => a.isClickable().hasText("Submit")));or()
or(filterBuilder: (f: AndroidNodeFilter) => void): AndroidNodeFilterCombines with another filter using OR logic. The node must match either filter.
Parameters
| Name | Type | Description |
|---|---|---|
filterBuilder | (f: AndroidNodeFilter) => void | Function to build the alternative filter |
Examples
const clickables = screen.filterAdvanced(f => f.isButton().or(o => o.isImage().isClickable()));const node = screen.findAdvanced(f => f.hasText("OK").or(o => o.hasText("Confirm")).or(o => o.hasText("Yes")));Hierarchy Matchers
Match nodes based on their position in the node hierarchy.
parent()
parent(filterBuilder: (f: AndroidNodeFilter) => void): AndroidNodeFilterMatches nodes whose immediate parent matches the given filter.
Parameters
| Name | Type | Description |
|---|---|---|
filterBuilder | (f: AndroidNodeFilter) => void | Function to build the parent filter |
Examples
// Find text views inside a specific containerconst labels = screen.filterAdvanced(f => f.isText().parent(p => p.hasId("com.example:id/header")));anyParent()
anyParent(filterBuilder: (f: AndroidNodeFilter) => void): AndroidNodeFilterMatches nodes that have any ancestor matching the given filter.
Parameters
| Name | Type | Description |
|---|---|---|
filterBuilder | (f: AndroidNodeFilter) => void | Function to build the ancestor filter |
Examples
const listItems = screen.filterAdvanced(f => f.isText().anyParent(p => p.hasId("com.example:id/user_list")));const dialogButtons = screen.filterAdvanced(f => f.isClickable().anyParent(p => p.is("android.app.Dialog")));Complex Examples
const loginBtn = screen.findAdvanced(f => f.isButton() .hasText("Login") .isClickable() .anyParent(p => p.hasId("com.example:id/login_form")));const prices = screen.filterAdvanced(f => f.isText() .text(t => /^\$\d+/.test(t || "")) .anyParent(p => p.hasId("com.example:id/product_card")));
for (const price of prices) { console.log("Price:", price.text);}const emptyInput = screen.findAdvanced(f => f.isEditText() .isEditable() .text(t => !t || t.length === 0));
if (emptyInput) { await emptyInput.performAction(agent.constants.ACTION_CLICK); await agent.actions.writeText("Hello");}const confirmBtn = screen.findAdvanced(f => f.isButton() .isClickable() .or(o => o.hasText("OK")) .or(o => o.hasText("Confirm")) .or(o => o.hasText("Yes")) .or(o => o.hasText("Accept")));