Skip to main content

Locator delegates

Kolibrium's Selenium module provides a type-safe, Kotlin-first approach to browser automation using Selenium WebDriver. This section explains how to use Kolibrium's locator strategies and configuration options for reliable web element interaction.

Locator strategies

A locator or locator strategy is a mechanism used by Selenium to find elements on a web page. It specifies how to identify an element using specific attributes, properties or selector syntax.

Some strategies use attribute-based locators (e.g. id, name, className) and some use selector syntax or query string (cssSelector and xpath).

For example, in By.id("button")

  • By.id is the locator strategy. It tells Selenium to use the ID attribute of an element to locate it.
  • "button" is the value of the locator or the target string. It specifies the actual ID of the element you want to find.

Similarly, in By.cssSelector("div.container > ul > li:nth-child(2)")

  • By.cssSelector is the locator strategy. It tells Selenium to use the CSS selector of an element to locate it.
  • "div.container > ul > li:nth-child(2)" is the query string used for the search.

Kolibrium uses Kotlin's property delegation to find elements.

Property delegation allows a property's behavior to be managed by a separate, reusable delegate object. This functionality is implemented using the by keyword, which delegates the property's management to a helper object.

Property delegation provides significant advantages for Selenium testing:

Abstraction of element location

  • Separates the complex logic of finding web elements from the test code.
  • Allows declarative, clean syntax for element identification.

Reusability and maintainability

  • Centralize locator strategies in a single, consistent approach.
  • Reduces boilerplate code for element finding.

Let's see how we can do property delegation with Kolibrium.

Add the Selenium module to your project

To get started, add the following dependency and configure JUnit in your Gradle project build file (build.gradle.kts).

dependencies { 
implementation("dev.kolibrium:kolibrium-selenium:0.7.0")
// other dependencies
}

tasks.test {
useJUnitPlatform()
}

Finding elements with locator delegate functions

Kolibrium's Selenium module provides support for the following traditional locator strategies.

LocatorDescriptionMultiple elements supported?
classNameLocates elements with a class name containing the search value (compound class names are not allowed).Yes
cssSelectorLocates elements that match a CSS selector.Yes
dataQaLocates elements with a data-qa attribute that matches the search value.Yes
dataTestLocates elements with a data-test attribute that matches the search value.Yes
dataTestIdLocates elements with a data-testid attribute that matches the search value.Yes
idLocates elements with an ID attribute that matches the search value.No
idOrNameFirst, attempts to locate an element by ID and falls back to using the name if the ID is not found.No
linkTextLocates anchor elements with visible text that matches the search value.Yes
nameLocates elements with a NAME attribute that matches the search value.Yes
partialLinkTextLocates anchor elements with visible text that contains the search value; if multiple elements match, only the first one is selected.Yes
tagNameLocates elements with a tag name that matches the search value.Yes
xpathLocates elements that match an XPath expression.Yes

Creating locators

To interact with a web element using Selenium, first we need to locate it on the web page. Selenium offers several methods to locate elements on the page. To learn and create locators, we will refer to the following HTML snippet.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Selenium Locators Test Page</title>
</head>
<body>
<h1>Selenium Locators Test Page</h1>

<div class="locator" id="single-locators">
<h2>Single Element Locators</h2>
<div class="by-class-name">Locate by Class Name</div><br>
<div data-test="css-selector">Locate by CSS Selector</div><br>
<div id="by-id">Locate by ID</div><br>
<a href="#" id="by-link-text">Locate by Link Text</a><br><br>
<button name="by-name">Locate by Name</button><br><br>
<a href="#" id="by-partial-link">Locate by Partial Link Text Example</a><br>
<p>Locate by Tag Name</p>
<div id="by-xpath">Locate by XPath</div>
</div>

<div class="locator" id="multiple-locators">
<h2>Multiple Element Locators</h2>
<div class="multiple">Multiple Locate by Class Name</div><br>
<div class="multiple">Multiple Locate by Class Name</div><br>
<div data-test="multiple">Multiple Locate by CSS Selector</div><br>
<div data-test="multiple">Multiple Locate by CSS Selector</div><br>
<a href="#">Multiple Locate by Link Text</a><br><br>
<a href="#">Multiple Locate by Link Text</a><br><br>
<button name="multiple-by-name">Multiple Locate by Name</button><br><br>
<button name="multiple-by-name">Multiple Locate by Name</button><br><br>
<a href="#">Locate by Partial Link Example</a><br><br>
<a href="#">Locate by Partial Link Example</a><br><br>
<span>Multiple Locate by Tag Name</span><br><br>
<span>Multiple Locate by Tag Name</span><br><br>
<div class="multiple-by-xpath">Multiple Locate by XPath</div><br>
<div class="multiple-by-xpath">Multiple Locate by XPath</div>
</div>
</body>
</html>

Readiness conditions (readyWhen)

Every locator delegate supports an optional readiness predicate via the trailing lambda. The parameter name is readyWhen, so both forms below are equivalent:

// Trailing lambda form (parameter name is readyWhen)
val button by driver.id("button") { isDisplayed && isEnabled }

// Explicit named-parameter form
val button2 by driver.id(
value = "button",
readyWhen = { isDisplayed && isEnabled }
)

Types used by delegates:

// Provided by Kolibrium for concise signatures
typealias WebElements = List<WebElement>

className locator strategy

HTML web elements can have a class attribute. These elements can be identified using the class name locator provided by Selenium.

Locating single element

val className by driver.className("by-class-name")

Locating multiple elements

val classNames by driver.classNames("multiple")

cssSelector locator strategy

We can use the CSS selector locator strategy to identify elements on the page. If the element has an ID, the locator is defined as css=#id. Otherwise, the format used is css=[attribute=value].

Locating single element

val cssSelector by driver.cssSelector("[data-test='css-selector']")

Locating multiple elements

val cssSelectors by driver.cssSelectors("[data-test='multiple']")

dataQa locator strategy

For elements that use a data-qa attribute, Kolibrium provides a convenience delegate that builds a safe CSS selector for you.

Locating single element

val dataQa by driver.dataQa("submit-btn")

Locating multiple elements

val dataQas by driver.dataQas("multiple")

dataTest locator strategy

For elements that use a data-test attribute.

Locating single element

val dataTest by driver.dataTest("form-field")

Locating multiple elements

val dataTests by driver.dataTests("multiple")

dataTestId locator strategy

For elements that use a data-testid attribute.

Locating single element

val dataTestId by driver.dataTestId("login-button")

Locating multiple elements

val dataTestIds by driver.dataTestIds("multiple")

id selector locator strategy

The ID attribute of an element on a web page can be used to locate it. Typically, the ID property is unique for each element on the page.

Locating single element

val id by driver.id("by-id")

Locating multiple elements with ID attribute is not supported.

idOrName selector locator strategy

This locator strategy first tries to locate the element by ID. If the element is not found, it then tries by name.

Locating single element

val idOrName by driver.idOrName("by-name")

Locating multiple elements with ID or name attribute is not supported.

linkText locator strategy

To locate an element that is a link, we can use the link text locator. The link text refers to the visible text displayed for the link on the web page.

Locating single element

val linkText by driver.linkText("Locate by Link Text")

Locating multiple elements

val linkTexts by driver.linkTexts("Multiple Locate by Link Text")

name locator strategy

The name attribute of an element on a web page can be used to locate it.

Locating single element

val name by driver.name("by-name")

Locating multiple elements

val names by driver.names("multiple-by-name")

partialLinkText locator strategy

To locate an element that is a link, we can use the partial link text locator on the web page. The link text refers to the visible text of the link, and we can provide a portion of this text as the value.

Locating single element

val partialLinkText by driver.partialLinkText("Partial Link Text Example")

Locating multiple elements

val partialLinkTexts by driver.partialLinkTexts("Partial Link Example")

tagName locator strategy

The HTML tag itself can be used as a locator to identify a web element on the page.

Locating single element

val tagName by driver.tagName("p")

Locating multiple elements

val tagNames by driver.tagNames("span")

xpath locator strategy

An HTML document can be treated as an XML document, allowing us to use XPath to navigate the path to the desired element for locating it. XPath can be absolute, starting from the root of the document. For example, /html/body/h1 refers to the "Single Element Locators" heading. Alternatively, XPath can be relative, such as //button[@name='by-name'], which identifies the "Locate by Name" button.

Locating single element

val xpath by driver.xpath("//div[@id='by-xpath']")

Locating multiple elements

val xpaths by driver.xpaths("//div[@class='multiple-by-xpath']")