Summary: Fragile XPath locators are one of the biggest causes of flaky automation tests. This article shares five proven XPath techniques that help you write stable, readable, and long-lasting locators that can survive UI changes. First, view the XPath tutorial for beginners below. Then, read on.
Introduction
If you work in test automation, you know the frustration well. Tests fail not because the application is broken, but because a small UI change invalidated your locators.
This problem wastes time, increases maintenance effort, and erodes trust in automation. The good news is that most of these failures are avoidable.
Stop thinking of XPath as just a way to locate elements and start treating it as a language for describing elements in a stable and logical way.
Try the free XPath Playbook on GitHub with demo XPaths.
In this post, we will look at five XPath techniques that can turn brittle locators into robust, maintainable ones.
1. Avoid Absolute Paths and Prefer Relative XPath
The first step toward reliable locators is understanding the difference between absolute and relative XPath.
An absolute XPath starts from the root of the document and defines every step along the way. While this may look precise, it is extremely fragile. A single extra container added to the page can break the entire path.
Relative XPath, on the other hand, focuses on the unique characteristics of the target element and ignores irrelevant structural details.
For example, instead of relying on a full path from the root, describe the element based on a stable attribute or relationship. Relative XPath continues to work even when the surrounding structure changes.
Avoid: //html/body/div[2]/div[1]/form/input[2]
Prefer: //form//input[@name='email']
As a rule, absolute XPath has no place in a professional automation framework.
Note: Want to learn XPath in detail? View How to find XPath tutorial.
2. Use XPath Axes to Navigate Smartly
Many testers think XPath only works top to bottom through the DOM. This limited understanding leads to weak locators.
XPath axes allow you to navigate in all directions: up, down, and sideways. This lets you describe an element based on its relationship to another stable element.
Some commonly used axes include ancestor, parent, following-sibling, and preceding-sibling.
This approach is especially powerful when the element you want does not have reliable attributes. Instead of targeting it directly, you anchor your XPath to nearby text or labels that rarely change.
For example, rather than locating an input field directly, you can describe it as the input that follows a specific label. This makes the locator far more resilient.
//label[normalize-space()='Password']/following-sibling::input[1]
//div[contains(@class,'card')]/ancestor::section[1]
3. Handle Messy Text with normalize-space()
Text-based locators often fail because of hidden whitespace. Extra spaces, line breaks, or formatting changes can cause simple text checks to stop working.
The normalize-space() function solves this problem by trimming leading and trailing spaces and collapsing multiple spaces into one.
//button[normalize-space()='Submit']
//h3[normalize-space()='Account Settings']
When you use normalize-space(), your locator becomes immune to minor formatting differences in the UI. This single function can eliminate a surprising number of flaky failures.
If you are locating elements by visible text, normalize-space() should be your default choice.
4. Defeat Dynamic Attributes with Partial Matching
Modern web applications often generate dynamic values for attributes like id and class. Trying to match these values exactly is a common mistake.
XPath provides functions like contains() and starts-with() that allow you to match only the stable portion of an attribute.
Use starts-with() when the predictable part appears at the beginning of the value, and contains() when it can appear anywhere.
//input[starts-with(@id,'user_')]
//div[contains(@class,'item-') and contains(@class,'active')]
This technique is essential for dealing with dynamic IDs, timestamps, and auto-generated class names. It dramatically reduces locator breakage when the UI changes slightly.
5. Combine Conditions for Precise Targeting
Sometimes no single attribute is unique enough to identify an element reliably. In such cases, combining multiple conditions is the best approach.
XPath allows you to use logical operators like and and or to build precise locators. This is similar to using a composite key in a database.
By combining class names, text, and attributes, you can describe exactly the element you want without relying on fragile assumptions.
//a[@role='button' and contains(@href,'/checkout') and normalize-space()='Buy now']
This strategy ensures that your locator is specific without being overly dependent on one fragile attribute.
Conclusion: Write Locators That Survive Change
Stable XPath locators are not about clever tricks. They are about clear thinking and disciplined design.
When you start describing elements based on stable characteristics and relationships, your automation becomes more reliable and easier to maintain.
Adopt a locator-first mindset. Write XPath expressions that anticipate change instead of reacting to it. That mindset is what separates brittle test suites from professional automation.
To get working Selenium/Cypress/Playwright projects for your portfolio (paid service), deep-dive in-person Test Automation and QA Training and XPath resume updates, send me a message using the Contact Us (right pane) or message Inder P Singh (18 years' experience in Test Automation and QA) in LinkedIn at https://www.linkedin.com/in/inderpsingh/


