Testing Tools appium mobile android ios

XPath in Appium (Mobile)

XPath on Android and iOS: the native class names, the attributes that exist, why it is slow on mobile, and the accessibility-id strategy you should reach for first.

XPath in Appium (Mobile)

Appium exposes a native app’s view hierarchy as XML and lets you query it with XPath. The syntax is the same XPath 1.0 you use on the web. The document is completely different: no HTML tags, no classes, no ids in the web sense, and a performance profile that makes XPath the locator of last resort.

The mobile “DOM”

On Android (UiAutomator2), element names are widget class names and the attributes come from the accessibility node:

<android.widget.EditText resource-id="com.example:id/email" text="" content-desc="Email field" clickable="true" />
<android.widget.Button resource-id="com.example:id/login" text="LOG IN" content-desc="Log in" enabled="true" />

On iOS (XCUITest), names are XCUIElementType* and attributes come from the accessibility API:

<XCUIElementTypeTextField name="email" label="Email" value="" enabled="true" visible="true" />
<XCUIElementTypeButton name="login" label="Log in" enabled="true" />

Get the actual tree with driver.getPageSource() or Appium Inspector. Do not guess attribute names; they differ between platforms and versions.

XPath examples

Android

//android.widget.Button[@text='LOG IN']
//android.widget.Button[@content-desc='Log in']
//android.widget.EditText[@resource-id='com.example:id/email']
//*[@resource-id='com.example:id/email']
//android.widget.TextView[contains(@text, 'Welcome')]
//android.widget.ListView//android.widget.TextView[@text='Settings']
//*[@text='Settings']/parent::*//android.widget.Switch

iOS

//XCUIElementTypeButton[@name='login']
//XCUIElementTypeButton[@label='Log in']
//XCUIElementTypeTextField[@name='email']
//XCUIElementTypeStaticText[contains(@label, 'Welcome')]
//XCUIElementTypeCell[.//XCUIElementTypeStaticText[@label='Settings']]//XCUIElementTypeSwitch
//*[@name='Settings']/ancestor::XCUIElementTypeCell[1]

All the web patterns apply: normalize-space() for text, contains() for partial, ancestor:: and following-sibling:: for structure, [.//x] for “row that contains”.

Why XPath is slow on mobile

Every XPath query forces Appium to serialise the entire view hierarchy to XML, transfer it, evaluate the expression, then map the result back to a native element. On a complex screen that can take hundreds of milliseconds to seconds, and it happens on every findElement. On iOS in particular, snapshotting the accessibility tree is the dominant cost.

Native locator strategies query the platform’s accessibility service directly and skip the serialisation.

The strategy order for mobile

  1. Accessibility id: content-desc on Android, name on iOS. Set explicitly by developers, cross-platform, fast.
  2. Resource id (Android) or name/label (iOS) via id / -ios predicate string.
  3. Class chain (iOS, -ios class chain) or UiAutomator (Android, -android uiautomator): native query languages, fast, structural.
  4. XPath: when you need text plus structure and nothing else works.
// preferred
driver.findElement(AppiumBy.accessibilityId("Log in"));
driver.findElement(AppiumBy.id("com.example:id/email"));
driver.findElement(AppiumBy.iOSClassChain("**/XCUIElementTypeButton[`label == 'Log in'`]"));
driver.findElement(AppiumBy.androidUIAutomator("new UiSelector().text(\"LOG IN\")"));

// fallback
driver.findElement(AppiumBy.xpath("//android.widget.Button[@text='LOG IN']"));
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "Log in")
driver.find_element(AppiumBy.XPATH, "//android.widget.Button[@text='LOG IN']")

Making XPath faster when you must use it

  • Avoid //*. Name the class. //android.widget.Button[...] prunes the search massively.
  • Avoid deep // chains. Each descendant scan walks the tree again.
  • Cache the page source for read-only checks and evaluate several XPaths against it locally with lxml or the JDK’s XPath API, rather than round-tripping to the device per query.
  • Scope with a container you already hold: container.findElement(AppiumBy.xpath(".//android.widget.TextView")).
  • Prefer index-free predicates. Indexes on mobile lists are unstable because off-screen items may not be in the hierarchy at all.

Hybrid apps and webviews

In a webview context (driver.context("WEBVIEW_...")) you are back in a browser and normal HTML XPath applies, with all the web patterns. Switch contexts with driver.getContextHandles() and driver.context(...).

Flutter, React Native, and others

React Native maps testID to content-desc (Android) and name (iOS), so accessibility id works. Flutter renders its own widgets and needs the Flutter driver or appium-flutter-driver; the accessibility tree is sparse, so XPath is rarely useful there.

Next Steps

  1. Anchoring to Stable Context - The same discipline, different tree
  2. Performance and Efficiency - The web-side view of locator cost
  3. XPath Interview Questions - Mobile locator questions come up in automation interviews