Define project-level configuration
Kolibrium is flexible and has many ways to configure element readiness checks, waiting strategies and decorators. Sometimes you may want to set configuration for default behaviors at a global level and for that you need to use project-level configuration. Project-level configuration allows you to customize element readiness criteria, define a global waiting strategy, and apply decorators across your entire test suite.
Configuration example
Project-level configuration can be created by implementing an object that extends from AbstractSeleniumProjectConfiguration
class and by overriding the desired properties.
object SeleniumConfiguration : AbstractSeleniumProjectConfiguration() {
override val elementReadyCondition: (WebElement.() -> Boolean) = { isClickable }
override val elementsReadyCondition: (WebElements.() -> Boolean) = { isClickable }
override val waitConfig = DEFAULT.copy(
pollingInterval = 250.milliseconds,
timeout = 5.seconds
)
override val decorators = listOf(
HighlighterDecorator(style = DASHED, color = GREEN, width = 5),
SlowMotionDecorator(wait = 1.seconds),
ElementStateCacheDecorator(cacheDisplayed = true, cacheEnabled = true)
)
}
With the above configuration:
- By default
isClickable
is used to determine if an element or elements are ready for use - The waiting uses a 250 milliseconds polling interval with 5 seconds of timeout
- All
WebDriver
andWebElement
instances will be decorated with:- A green dashed highlight border (5px wide) around elements for visual feedback
- A 1 second delay after each element interaction for slowed-down test execution
- Caching of positive displayed and enabled state checks for performance optimization
All tests will inherit these settings automatically. The waiting configuration will also ignore NoSuchElementException
exception and report "Element could not be found" error on time outs - these are inherited from the DEFAULT
wait configuration.
ServiceLoader configuration
Java's ServiceLoader is a mechanism for dynamic service discovery and loading. In Kolibrium, automatic configuration discovery is enabled at runtime by scanning for and instantiating objects that extend AbstractSeleniumProjectConfiguration
, applying their defined configuration values.
Once the configuration is created, we need to also configure metadata for the ServiceLoader by registering our implementation under META-INF/services
folder.
Manual vs. AutoService approach
Manual Approach:
- Requires manually creating service descriptor file.
- Prone to human errors (typos, outdated paths).
- Needs manual updates during refactoring.
AutoService Approach:
- Automatically generates service descriptor.
- Compile-time safety.
- Reduces maintenance overhead.
- Prevents configuration registration errors.
The key difference is automation and compile-time verification, making AutoService the recommended method for maintaining project-level configurations.
Manual approach
Create a file named as dev.kolibrium.core.selenium.configuration.AbstractSeleniumProjectConfiguration
with content of
FQN.SeleniumConfiguration
under resources/META-INF/services
directory, where FQN
is the fully-qualified name of the object implementing AbstractSeleniumProjectConfiguration
.
AutoService approach
To prevent manual service descriptor maintenance errors, we can leverage on a more robust solution: AutoService generates the metadata for any class annotated with @AutoService
, avoiding typos, providing resistance to errors from refactoring, etc.
First, we need to register the Kotlin Symbol Processing (KSP) plugin and add the AutoService dependency.
plugins {
id("com.google.devtools.ksp") version "2.0.21-1.0.29"
// other plugins
}
dependencies {
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.2.0")
// other dependencies
}
After that, we just annotate our SeleniumConfiguration
object as follows.
@AutoService(AbstractSeleniumProjectConfiguration::class)
object SeleniumConfiguration : AbstractSeleniumProjectConfiguration() {
// override desired properties
}