XPathy goes beyond simple and(), or(), and not() chaining
by introducing union and intersect operations. These allow you
to group multiple conditions into clean, reusable blocks.
1. Union (union(Or...))
The union() method combines multiple OR conditions into a
single predicate. Instead of chaining multiple .or() calls, you can list them
together for clarity.
Multiple Login Button IDs
XPathy locator = button.byAttribute(id)
.union(Or.equals("login-btn"),
Or.equals("signin-btn"),
Or.contains("auth"));
//button[@id='login-btn' or @id='signin-btn' or contains(@id, 'auth')]
Use Case: Different environments (dev, QA, prod) may use slightly different IDs for the login button. Instead of writing separate locators for each, the union ensures one robust locator works everywhere.
2. Intersect (intersect(And...))
The intersect() method combines multiple AND conditions into
one predicate. This is especially useful when you want a field or text to satisfy multiple
patterns simultaneously.
Order Confirmation Messages
XPathy locator = div.byText()
.intersect(And.startsWith("Order #"),
And.contains("Confirmed"),
And.not().contains("Cancelled"));
//div[starts-with(text(), 'Order #') and contains(text(), 'Confirmed') and not(contains(text(), 'Cancelled'))]
Use Case: After placing an order, the app shows confirmation text in different formats. Intersect ensures your test only picks valid confirmed orders.
3. Using Transformations with Union and Intersect
Just like with single conditions, you can apply transformations inside
union() and intersect(). This makes locators more resilient to
variations.
Union with Transformation
XPathy locator = li.byAttribute(class_)
.union(Or.withRemoveOnly(SPECIAL_CHARACTERS).contains("active"),
Or.withCase(IGNORED).equals("selected"));
Use Case: A navigation tab might render with classes like
active!, selected, or SELECTED. With transformations,
the locator still works consistently.
Intersect with Transformation
XPathy locator = span.byText()
.intersect(And.withNormalizeSpace().contains("Premium"),
And.withCase(LOWER).contains("subscription"));
Use Case: Product labels may appear as Premium SUBSCRIPTION,
premium subscription, or PREMIUM Subscription. Normalization and
case-insensitive comparison ensure all variants match.