Web Selectors

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:

  1. CSS (css) — direct DOM query, most precise
  2. Attribute selectorstestId > name > placeholder > href > alt > title (in order)
  3. Role (role) — ARIA role via Accessibility Tree (can combine with text)
  4. ID (id) — cascading lookup across multiple attributes (see below)
  5. Text (text) — AX tree search with JS fallback
  6. Text partial (textContains) — partial text match via AX tree
  7. 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:

  1. #id — exact HTML id attribute
  2. [data-testid="id"]data-testid attribute
  3. [id*="id"] — partial id match (contains)
  4. [name="id"]name attribute
  5. [aria-label="id"]aria-label attribute

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:

  1. AX tree — clickable roles first: button, link, menuitem, tab, checkbox, radio
  2. AX tree — input roles next: textbox, combobox, searchbox, spinbutton
  3. AX tree — all roles (no role filter)
  4. Page search (handles Shadow DOM via DOMPerformSearch)
  5. 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"