Web Selectors
The web driver finds elements using a multi-stage cascade. Only one selector is used per step — the first match in this priority order:
- CSS (
css) — direct DOM query, most precise - Attribute selectors —
testId>name>placeholder>href>alt>title(in order) - Role (
role) — ARIA role via Accessibility Tree (can combine withtext) - ID (
id) — cascading lookup across multiple attributes (see below) - Text (
text) — AX tree search with JS fallback - Text partial (
textContains) — partial text match via AX tree - Text regex (
textRegex) — regex match via AX tree
Standard Selectors
| Selector | Description | Example |
|---|---|---|
text |
Match by visible text (default) | - tapOn: "Login" |
id |
Match by element ID (cascading) | - tapOn: { id: submit-btn } |
css |
CSS selector (DOM query) | - tapOn: { css: "button.primary" } |
Web-Only Selectors
| Selector | HTML Attribute | Example |
|---|---|---|
testId |
data-testid |
- tapOn: { testId: login-btn } |
placeholder |
placeholder |
- tapOn: { placeholder: "Enter email" } |
name |
name |
- tapOn: { name: email } |
role |
ARIA role | - tapOn: { role: button } |
href |
href (links, tries exact then contains) |
- tapOn: { href: "/about" } |
alt |
alt (images) |
- assertVisible: { alt: "Logo" } |
title |
title (tooltips) |
- tapOn: { title: "Close dialog" } |
textContains |
Partial text match | - tapOn: { textContains: "Sign" } |
textRegex |
Regex text match | - assertVisible: { textRegex: "Order #\\d+" } |
nth |
Pick Nth match (0-based: 0 = first, 1 = second, 2 = third) |
- tapOn: { css: ".item", nth: 2 } |
Selecting by HTML type Attribute
There is no dedicated type selector. Use css to select by the HTML type attribute:
# Submit button
- tapOn:
css: "button[type=submit]"
# Email input
- inputText:
text: "[email protected]"
css: "input[type=email]"
# Password input
- inputText:
text: "secret123"
css: "input[type=password]"
# File input
- uploadFile:
css: "input[type=file]"
path: "photo.jpg"
# Checkbox
- tapOn:
css: "input[type=checkbox]"
# Radio button
- tapOn:
css: "input[type=radio][value=option1]"
How id Selector Works
The id selector tries a cascade of CSS selectors, returning the first match:
#id— exact HTMLidattribute[data-testid="id"]—data-testidattribute[id*="id"]— partialidmatch (contains)[name="id"]—nameattribute[aria-label="id"]—aria-labelattribute
This makes id a "fuzzy" selector. For exact matching, use testId, name, or css instead.
How Text Matching Works
When you use text (or the scalar shorthand like - tapOn: "Login"), the driver searches in this order:
- AX tree — clickable roles first:
button,link,menuitem,tab,checkbox,radio - AX tree — input roles next:
textbox,combobox,searchbox,spinbutton - AX tree — all roles (no role filter)
- Page search (handles Shadow DOM via
DOMPerformSearch) - JS fallback (searches
textContent,aria-label,placeholder— deepest matching element preferred, walks up to nearest interactive ancestor)
This means clicking "Login" will prefer a <button>Login</button> over a <p>Login</p>.
Auto-regex detection: If your text contains regex metacharacters (*, +, ?, [, ], {, }, |, (, ), ^ at start, $ at end), it's automatically treated as a regex pattern.
# These are equivalent:
- assertVisible: "Order #\\d+"
- assertVisible: { textRegex: "Order #\\d+" }
State Filters
Filter elements by their interactive state:
# Only enabled buttons
- tapOn:
text: "Submit"
enabled: true
# Checked checkbox
- assertVisible:
css: "input[type=checkbox]"
checked: true
# Focused input
- assertVisible:
css: "input"
focused: true
# Selected option
- assertVisible:
css: "option"
selected: true
| Filter | Type | Description |
|---|---|---|
enabled |
bool | Element is enabled (not disabled) |
checked |
bool | Checkbox/radio is checked |
selected |
bool | Option/tab is selected |
focused |
bool | Element has focus |
State filters can be combined with any selector.
Relative Selectors (Not Supported on Web)
The following relative selectors are supported on Android/iOS but not on web: childOf, below, above, leftOf, rightOf, containsChild, containsDescendants, insideOf. On web, use CSS selectors for structural queries instead:
# Instead of childOf, use CSS descendant/child selectors:
- tapOn:
css: "#parent-form > button.submit"
# Instead of containsChild:
- tapOn:
css: ".card:has(.badge)"
Combining Selectors
# testId + state filter
- tapOn:
testId: submit-btn
enabled: true
# CSS + nth (pick 3rd match)
- tapOn:
css: ".list-item"
nth: 2
# role + text (button with specific accessible name)
# This queries the AX tree for role="button" AND name="Submit"
- tapOn:
role: button
text: "Submit"
# placeholder + specific input
- inputText:
text: "[email protected]"
placeholder: "Email address"