Skip to main content

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 vararg parameters, so you can pass any number of locators
  • chained wraps Selenium's ByChained (sequential scoping)
  • anyOf wraps Selenium's ByAll (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