Locator Strategy
Locator Strategy Identify and interact with UI elements using locator strategies for web and mobile test automation with Selenium and Appium
Testing Quest #30 Intermediate

Locator Strategy

Identify and interact with UI elements using locator strategies for web and mobile test automation with Selenium and Appium

testinglocatorsseleniumappiumxpathaccessibility-idautomation
Download as:

What is a Locator Strategy?

A locator is a way to identify elements on a page or screen. It is the argument passed to find_element methods in Selenium and Appium. The locator tells the driver how to find the element (by ID, by name, by XPath, etc.) and what value to match.

Choosing the right locator strategy is critical for writing tests that are reliable, readable, and resistant to UI changes.

Prerequisites

Locator Types

Web Locators (Selenium)

StrategyBy ConstantExampleReliability
IDBy.ID"login-btn"High
NameBy.NAME"username"High
CSS SelectorBy.CSS_SELECTOR".btn-primary"High
Class NameBy.CLASS_NAME"submit-button"Medium
Link TextBy.LINK_TEXT"Sign In"Medium
Partial Link TextBy.PARTIAL_LINK_TEXT"Sign"Low
Tag NameBy.TAG_NAME"input"Low
XPathBy.XPATH"//input[@id='user']"Low

Mobile Locators (Appium)

StrategyAppiumBy ConstantExampleReliability
Accessibility IDAppiumBy.ACCESSIBILITY_ID"login_button"Highest
ID (resource-id)AppiumBy.ID"com.app:id/login"High
Class NameAppiumBy.CLASS_NAME"android.widget.Button"Medium
iOS Class ChainAppiumBy.IOS_CLASS_CHAIN"**/XCUIElementTypeButton"Medium
iOS PredicateAppiumBy.IOS_PREDICATE"label == 'Login'"Medium
Android UIAutomatorAppiumBy.ANDROID_UIAUTOMATOR"new UiSelector().text(\"Login\")"Medium
XPathAppiumBy.XPATH"//XCUIElementTypeButton"Low

Use the most reliable locator strategy available. Fall back to less reliable strategies only when necessary:

  1. Accessibility ID β€” Best for mobile; works cross-platform (iOS + Android)
  2. ID β€” Best for web; unique and fast
  3. CSS Selector β€” Flexible and performant for web
  4. iOS Class Chain / Predicate β€” iOS-specific, more reliable than XPath
  5. Android UIAutomator β€” Android-specific, more reliable than XPath
  6. Class Name β€” Useful when combined with index or other filters
  7. XPath β€” Last resort; fragile and slow

Avoid XPath whenever possible. XPath locators are tightly coupled to the DOM/element hierarchy. Any structural change in the UI will break them. Ask your development team to add unique accessibility IDs to elements instead.

Defining Locators

Tuple Approach

The standard way to define locators in Selenium and Appium is as a tuple of (By, value):

from selenium.webdriver.common.by import By
from appium.webdriver.common.appiumby import AppiumBy

# web
username_input = (By.ID, "username")
submit_button = (By.CSS_SELECTOR, "button[type='submit']")

# mobile
login_button = (AppiumBy.ACCESSIBILITY_ID, "login_button")
email_field = (AppiumBy.ID, "com.example.app:id/email")

Use the tuple with find_element:

element = driver.find_element(*username_input)
element.send_keys("user123")

Data Class Approach

For larger test suites, a data class provides better readability and debugging information:

from dataclasses import dataclass
from selenium.webdriver.common.by import By


@dataclass
class LocatorDefinition:
    by: str
    locator: str
    description: str = ""

Usage:

from appium.webdriver.common.appiumby import AppiumBy

# web
username = LocatorDefinition(
    by=By.ID,
    locator="username",
    description="Username input on the login page",
)

# mobile
login_btn = LocatorDefinition(
    by=AppiumBy.ACCESSIBILITY_ID,
    locator="login_button",
    description="Login button on the login screen",
)

Use with find_element:

element = driver.find_element(username.by, username.locator)

The data class approach adds a description field that makes debugging easier β€” when a test fails, you can see exactly which element on which page/screen was not found.

Finding Locators

Web Elements

Right-click on any element in a browser and select Inspect (or press F12). The developer tools will open and highlight the element in the DOM.

To copy a locator:

  1. Right-click the highlighted element in the DOM tree
  2. Select Copy
  3. Choose the locator type: Copy selector (CSS), Copy XPath, Copy JS path, etc.

Mobile Elements

Use the Appium Inspector application to inspect elements on a mobile device or simulator:

  1. Start an Appium server
  2. Open Appium testing
  3. Configure the desired capabilities for your device
  4. Start a session
  5. Click on any element to view its properties (accessibility ID, resource-id, class, text, XPath, etc.)

The Appium Inspector shows all available attributes for each element, making it easy to choose the best locator strategy.

Platform-Specific Locators

iOS Class Chain

iOS Class Chain queries are faster and more reliable than XPath for iOS:

from appium.webdriver.common.appiumby import AppiumBy

# find a button by label
button = (AppiumBy.IOS_CLASS_CHAIN, "**/XCUIElementTypeButton[`label == 'Login'`]")

# find the third cell in a table
cell = (AppiumBy.IOS_CLASS_CHAIN, "**/XCUIElementTypeCell[3]")

# find a text field inside a specific view
field = (AppiumBy.IOS_CLASS_CHAIN, "**/XCUIElementTypeTextField[`value == 'Email'`]")

iOS Predicate String

iOS Predicate strings use NSPredicate syntax for attribute matching:

# exact match
button = (AppiumBy.IOS_PREDICATE, "label == 'Login'")

# contains
field = (AppiumBy.IOS_PREDICATE, "name CONTAINS 'email'")

# begins with
header = (AppiumBy.IOS_PREDICATE, "label BEGINSWITH 'Welcome'")

# combine conditions
element = (AppiumBy.IOS_PREDICATE, "type == 'XCUIElementTypeButton' AND label == 'Submit'")

Android UIAutomator

UIAutomator selectors use Android’s UiSelector API:

# find by text
button = (AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Login")')

# find by content-description (accessibility ID)
icon = (AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().description("settings_icon")')

# find by resource-id
field = (AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().resourceId("com.app:id/email")')

# scrollable container
item = (AppiumBy.ANDROID_UIAUTOMATOR,
    'new UiScrollable(new UiSelector().scrollable(true))'
    '.scrollIntoView(new UiSelector().text("Item Name"))')

Page Object Example

Putting it all together in a page object:

from appium.webdriver.common.appiumby import AppiumBy


class LoginScreen:

    USERNAME_INPUT = (AppiumBy.ACCESSIBILITY_ID, "username_field")
    PASSWORD_INPUT = (AppiumBy.ACCESSIBILITY_ID, "password_field")
    LOGIN_BUTTON = (AppiumBy.ACCESSIBILITY_ID, "login_button")
    ERROR_MESSAGE = (AppiumBy.ACCESSIBILITY_ID, "error_label")

    def __init__(self, driver):
        self.driver = driver

    def enter_username(self, username: str):
        self.driver.find_element(*self.USERNAME_INPUT).send_keys(username)

    def enter_password(self, password: str):
        self.driver.find_element(*self.PASSWORD_INPUT).send_keys(password)

    def tap_login(self):
        self.driver.find_element(*self.LOGIN_BUTTON).click()

    def get_error_message(self) -> str:
        return self.driver.find_element(*self.ERROR_MESSAGE).text

Good to Know

Work With Your Development Team

The most effective way to improve test reliability is to ask developers to add accessibility identifiers to all interactive elements. This benefits both test automation and real accessibility for users with assistive technologies.

Avoid Dynamic Locators

Locators that change between app builds or sessions are unreliable:

# bad -- auto-generated IDs change between builds
button = (By.ID, "button-a1b2c3d4")

# good -- stable, meaningful ID
button = (By.ID, "submit-order-button")

Multiple Elements

To find all matching elements (e.g., list items), use find_elements (plural):

from appium.webdriver.common.appiumby import AppiumBy

items = driver.find_elements(AppiumBy.CLASS_NAME, "XCUIElementTypeCell")
for item in items:
    print(item.text)

Troubleshooting

Element Not Found

  1. Verify the locator value in Appium Inspector or browser DevTools
  2. Add an explicit wait before the find_element call
  3. Check if the element is inside an iframe (web) or a different context (mobile webview)
  4. Ensure the page/screen has fully loaded

XPath Is Fragile

If your XPath locators break frequently:

  1. Switch to Accessibility ID or ID locators
  2. Use shorter, attribute-based XPath instead of positional XPath:
    # bad -- positional XPath
    (By.XPATH, "/html/body/div[3]/form/div[2]/input")
    
    # better -- attribute-based XPath
    (By.XPATH, "//input[@name='username']")
    
    # best -- use ID or Accessibility ID instead
    (By.ID, "username")

iOS Class Chain Not Working

Ensure you are using backticks (`) for predicate expressions within class chain queries, not single or double quotes:

# correct
(AppiumBy.IOS_CLASS_CHAIN, "**/XCUIElementTypeButton[`label == 'Login'`]")

# incorrect
(AppiumBy.IOS_CLASS_CHAIN, "**/XCUIElementTypeButton[label == 'Login']")

Resources

πŸ”—
Selenium Locator Strategies selenium.dev

Official Selenium documentation on all available locator strategies

πŸ”—
Migrating to Appium 3 appium.io

Official migration guide for upgrading from Appium 2.x to 3.x

πŸ”—
Appium Inspector github.com

Cross-platform GUI inspector for mobile apps to find element locators

πŸ”—
XCUIElementQuery (Apple) developer.apple.com

Apple's documentation on querying UI elements in XCUITest