XPath is one of the most widely used locator strategies in Selenium for finding elements in a web page. While attributes like id or name are often preferred for their uniqueness, not every application offers consistent or predictable attribute values. In such cases, XPath functions like contains() and text() become crucial for identifying elements by their textual content.
According to W3C standards, XPath expressions allow robust navigation of XML or HTML structures, making them ideal for dynamic test automation.
This article explores how contains(text(), ...) and text() differ, how they can be combined with attributes, and how to use them effectively with real-world Selenium examples.
The contains() function in XPath is used to check whether a node contains a particular string value. In Selenium automation, it becomes handy when dealing with dynamic text or partial matches.
For example, when a button’s label changes depending on context (like “Submit Order” or “Submit Request”), contains() allows you to write a locator that captures both scenarios:
driver.findElement(By.xpath("//button[contains(text(),'Submit')]")).click();
This helps avoid brittle locators that break when text changes slightly.
The text() function retrieves the exact text of an element. When used in an XPath expression, it requires a precise match. Unlike contains(), which allows partial matching, text() is strict.
For example:
//button[text()='Login']
This locator only works if the button text is exactly “Login.” If there’s even a trailing space, it fails. This makes text() more reliable in controlled environments but less flexible for dynamic UIs.
To locate an element using exact text, text() is the best choice. Consider a link that reads “Forgot Password”:
driver.findElement(By.xpath("//a[text()='Forgot Password']")).click();
This approach works well for static content such as navigation menus or labels that do not change over time. However, it is not suitable for dynamic text that changes based on conditions like user state or language settings.
When exact text cannot be guaranteed, contains() is more effective. Suppose a button label includes user-specific values like “Welcome, John!” In such cases, partial matching ensures stability:
driver.findElement(By.xpath("//button[contains(text(),'Welcome')]")).click();
This flexibility reduces maintenance overhead in large test suites.
The strength of XPath lies in its ability to combine multiple conditions. Combining contains() with attributes ensures locators remain unique while allowing for partial text matching. For instance:
driver.findElement(By.xpath("//div[contains(@class,'alert') and contains(text(),'successfully')]"));
Here, the locator checks both the class attribute and the text content, ensuring it targets only success message alerts.
Dynamic applications often generate IDs or labels that vary with each session. In such cases, starts-with() complements contains() by handling string patterns at the beginning of attributes or text values.
For example, if input fields have IDs like user_123 or user_456:
driver.findElement(By.xpath("//input[starts-with(@id,'user_')]"));
Combining the two makes the locator more resilient:
driver.findElement(By.xpath("//button[starts-with(text(),'Save') and contains(@class,'primary')]"));
This strategy ensures flexibility while maintaining uniqueness.
Consider an e-commerce application where product cards have dynamic labels such as “Add to Cart - iPhone 14 Pro.” Using contains(), a single locator can handle all products:
driver.findElement(By.xpath("//button[contains(text(),'Add to Cart')]"));
Another case is handling notifications:
driver.findElement(By.xpath("//div[contains(text(),'Your order has been placed')]"));
These examples show how contains() streamlines automation for dynamic UIs without writing separate locators for every variation.
Several mistakes can occur when writing XPath with text() or contains():
driver.findElement(By.xpath("//button[contains(.,'Sign Up')]"));
To make XPath locators reliable and maintainable:
XPath-based locators can behave inconsistently across environments. Running tests only on a local setup increases the chance of undetected failures. Key reasons to validate on real devices and browsers include:
BrowserStack Automate enables teams to run XPath-based Selenium tests on thousands of real browsers and devices in the cloud. With parallel execution, CI/CD integrations, and built-in debugging tools, it ensures locators are validated under real user conditions, improving test stability and reliability.
XPath functions like text() and contains() are vital for handling complex, dynamic web elements in Selenium automation. While text() ensures precision, contains() offers flexibility for partial matches. By combining them with attributes and functions like starts-with(), testers can build powerful, resilient locators. Validating these strategies on real browsers and devices further enhances test stability and reliability.
Run Selenium Tests on Cloud
Get visual proof, steps to reproduce and technical logs with one click
Continue reading
Try Bird on your next bug - you’ll love it
“Game changer”
Julie, Head of QA
Try Bird later, from your desktop