XPathy is a fluent Java library that transforms complex XPath strings into readable, maintainable code. Say goodbye to brittle locators and hello to scalable test automation.
// Before: Brittle and hard to read
String xpath = "//div[@id='main' and contains(text(), 'Hello')]";
// After: Fluent and maintainable
XPathy locator = div.byAttribute(id).equals("main")
.and()
.byText().contains("Hello");
// Get Selenium By object
By by = locator.getLocator();
Transform your Selenium automation with a fluent API that makes XPath expressions readable and maintainable
Chain methods naturally to build complex XPath expressions without juggling strings and brackets
Express intent clearly with method names that describe what you're looking for, not how to find it
Update locators easily as your UI evolves without deciphering cryptic XPath strings
Catch errors at compile time with Java's type system instead of runtime XPath failures
Normalize case, whitespace, and special characters to create robust locators that handle UI variations
Traverse parent, child, sibling, and ancestor relationships with intuitive method chaining
Add XPathy to your project via JitPack with just a few lines
Include the JitPack repository in your pom.xml
Include the XPathy library in your dependencies
Import and start creating fluent XPath expressions
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.Volta-Jebaprashanth</groupId>
<artifactId>xpathy</artifactId>
<version>3.0.1</version>
</dependency>
</dependencies>
Explore real-world examples showcasing XPathy's powerful features
import static com.xpathy.Attribute.*;
// Find element by ID
XPathy locator = id.contains("login-button");
// Result: //*[contains(@id, 'login-button')]
// Find element by class
XPathy locator = class_.equals("active");
// Result: //*[@class='active']
import static com.xpathy.Tag.*;
// Find div by ID
XPathy locator = div.byAttribute(id)
.equals("main-container");
// Result: //div[@id='main-container']
// Find button by data attribute
XPathy locator = button.byAttribute(data_testid)
.startsWith("submit-");
// Result: //button[starts-with(@data-testid, 'submit-')]
import static com.xpathy.Text.*;
// Find by text content
XPathy locator = div.byText()
.contains("Welcome");
// Result: //div[contains(text(), 'Welcome')]
// Global text search
XPathy locator = Text.startsWith("Error");
// Result: //*[starts-with(text(), 'Error')]
// Greater than comparison
XPathy locator = td.byNumber()
.greaterThan(10);
// Result: //td[number(text()) > 10]
// Between range
XPathy locator = span.byNumber()
.between(5, 15);
// Result: //span[number(text()) >= 5 and number(text()) <= 15]
// Find child element
XPathy locator = ul.byAttribute(id).equals("menu")
.$child(li)
.byText().contains("Contact");
// Result: //ul[@id='menu']/child::li[contains(text(), 'Contact')]
// Navigate to parent
XPathy locator = span.byText().equals("$19.99")
.$parent(div)
.byAttribute(class_).equals("product");
// Result: //span[text()='$19.99']/parent::div[@class='product']
// Following sibling
XPathy locator = label.byText().equals("Username")
.$followingSibling(input)
.byAttribute(type).equals("text");
// Result: //label[text()='Username']/following-sibling::input[@type='text']
// Find descendant
XPathy locator = section.byAttribute(id).equals("content")
.$descendant(p)
.byText().contains("Welcome");
// Result: //section[@id='content']/descendant::p[contains(text(), 'Welcome')]
XPathy locator = div.byAttribute(id)
.equals("main-container")
.and()
.byText().contains("Hello World");
// Result: //div[@id='main-container' and contains(text(), 'Hello World')]
XPathy locator = div.byAttribute(id)
.equals("main-container")
.or()
.byText().contains("Hello World");
// Result: //div[@id='main-container' or contains(text(), 'Hello World')]
XPathy locator = div.byText()
.contains("Hello World")
.and()
.byAttribute(id).not().equals("main-container");
// Result: //div[contains(text(), 'Hello World') and not(@id='main-container')]
XPathy locator = button.byAttribute(id)
.union(Or.equals("login-btn"),
Or.equals("signin-btn"),
Or.contains("auth"));
// Result: //button[@id='login-btn' or @id='signin-btn' or contains(@id, 'auth')]
import static com.xpathy.Case.*;
// Ignore case
XPathy locator = button.byAttribute(id)
.withCase(IGNORED)
.contains("login-button");
// Force uppercase
XPathy locator = label.byText()
.withCase(UPPER)
.equals("USERNAME");
// Normalize spaces
XPathy locator = div.byText()
.withNormalizeSpace()
.equals("Invalid password");
// Result: //div[normalize-space(text())='Invalid password']
import static com.xpathy.Only.*;
// Keep only letters and numbers
XPathy locator = td.byText()
.withKeepOnly(ENGLISH_ALPHABETS, NUMBERS)
.equals("ORD1234");
// Remove special characters
XPathy locator = span.byText()
.withRemoveOnly(SPECIAL_CHARACTERS)
.contains("1999");
// Chain transformations
XPathy locator = div.byText()
.withNormalizeSpace()
.withRemoveOnly(NUMBERS)
.withCase(IGNORED)
.contains("premium cafe");
// Handles: " Prémium Café 2024 " or "PREMIUM CAFE"
XPathy locator = div.byAttribute(class_)
.equals("product-card")
.and()
.byHaving(
span.byText().contains("In Stock")
);
// Result: //div[@class='product-card' and ( span[contains(text(), 'In Stock')] )]
XPathy locator = table.byHaving().child(
tr.byAttribute(class_).equals("total-row")
);
// Result: //table[( ./tr[@class='total-row'] )]
XPathy locator = section.byAttribute(id)
.equals("checkout")
.and()
.byHaving().descendant(
button.byText().contains("Place Order")
);
// Result: //section[@id='checkout' and ( .//button[contains(text(), 'Place Order')] )]
XPathy locator = div.byAttribute(class_)
.equals("price-tag")
.and()
.byHaving().ancestor(
section.byAttribute(id).equals("product-details")
);
// Result: //div[@class='price-tag' and ( ancestor::section[@id='product-details'] )]
Explore comprehensive guides for every XPathy feature
Attributes, tags, text content, and numeric comparisons
→Understanding how XPathy builds expressions
→AND, OR, NOT operations for complex conditions
→Parent, child, sibling, and ancestor traversal
→Case, whitespace, and character filtering
→Advanced logical grouping operations
→Complex business rules with nested logic
→Conditions on related elements
→