Composite locators
Kolibrium provides two composite locator functions that allow you to combine multiple locator strategies for more flexible and powerful element location.
chained — Sequential locator application
The chained function creates a locator that applies multiple locators sequentially, with each locator narrowing down the search from the result of the previous one. This is particularly useful for locating elements nested within other elements.
Signature
import dev.kolibrium.selenium.chained
fun chained(vararg locators: By): By
How it works
Each locator in the chain is applied to the result of the previous locator, effectively narrowing down the search with each step. For example, chained(By.id("parent"), By.className("child")) first finds the element with ID "parent", then searches within that element for an element with class "child".
Usage examples
Basic chaining
// Find a button within a specific form
val submitButton by driver.element(
chained(
By.id("login-form"),
By.cssSelector("button[type='submit']")
)
)
Multi-level nesting
// Navigate through multiple levels of nesting
val nestedElement by driver.element(
chained(
By.className("container"),
By.id("content"),
By.className("item")
)
)
anyOf — Match any locator (OR)
The anyOf function creates a locator that finds elements matching any of the given locators (logical OR). Use it when an element can be located using different strategies.
Signature
import dev.kolibrium.selenium.anyOf
fun anyOf(vararg locators: By): By
How it works
The resulting locator will return elements that match at least one of the provided locators. This lets you express “this OR that” alternatives without extra filtering code.
Usage examples
Combine tag and attribute
// Find elements that are either buttons or marked as primary
val primaryAction by driver.element(
anyOf(
By.tagName("button"),
By.cssSelector("[data-test='primary']")
)
)
Match by class or ARIA role
// Find elements that have the expected class OR the ARIA role
val options by driver.elements(
anyOf(
By.className("option"),
By.cssSelector("[role='option']")
)
)
Match elements with either class
// Find elements that are .btn or .primary (or both)
val buttons by driver.elements(
anyOf(
By.className("btn"),
By.className("primary")
)
)
Combining chained and anyOf
You can nest composite locators to create sophisticated location strategies:
// Find items inside a container matched by either id or class
val nestedItem by driver.element(
chained(
anyOf(
By.id("main-container"),
By.className("container")
),
By.className("item")
)
)
// Within a specific parent, find a child matching either condition
val constrainedChild by driver.element(
chained(
By.id("parent"),
anyOf(
By.className("child"),
By.cssSelector("[data-kind='primary']")
)
)
)
Integration with locator delegates
Both chained and anyOf work seamlessly with Kolibrium's generic element and elements delegates:
class MyPage : Page<MySite>(path = "/products") {
// Single element with chained locator
private val productName by element(
chained(By.className("product"), By.className("name"))
)
// Elements matching any of these locators (OR)
private val primaryButtons by elements(
anyOf(By.tagName("button"), By.className("primary"))
)
}
Notes
- Both functions accept
varargparameters, so you can pass any number of locators chainedwraps Selenium'sByChained(sequential scoping)anyOfwraps Selenium'sByAll(union/OR semantics)- Composite locators support all the same readiness conditions and synchronization features as standard locator delegates
- You can combine composite locators with custom readiness predicates for even more control