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.idis 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.cssSelectoris 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
- Gradle
- Maven
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()
}
To get started, add the following dependency to the dependencies section.
<dependency>
<groupId>dev.kolibrium</groupId>
<artifactId>kolibrium-selenium</artifactId>
<version>0.7.0</version>
</dependency>
Finding elements with locator delegate functions
Kolibrium's Selenium module provides support for the following traditional locator strategies.
| Locator | Description | Multiple elements supported? |
|---|---|---|
className | Locates elements with a class name containing the search value (compound class names are not allowed). | Yes |
cssSelector | Locates elements that match a CSS selector. | Yes |
dataQa | Locates elements with a data-qa attribute that matches the search value. | Yes |
dataTest | Locates elements with a data-test attribute that matches the search value. | Yes |
dataTestId | Locates elements with a data-testid attribute that matches the search value. | Yes |
id | Locates elements with an ID attribute that matches the search value. | No |
idOrName | First, attempts to locate an element by ID and falls back to using the name if the ID is not found. | No |
linkText | Locates anchor elements with visible text that matches the search value. | Yes |
name | Locates elements with a NAME attribute that matches the search value. | Yes |
partialLinkText | Locates anchor elements with visible text that contains the search value; if multiple elements match, only the first one is selected. | Yes |
tagName | Locates elements with a tag name that matches the search value. | Yes |
xpath | Locates 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']")