Skip to main content

Decorating WebDriver and WebElement

In the context of Selenium testing with Kolibrium, decorators are design pattern implementations that allow you to dynamically enhance the behavior of WebDriver and WebElement instances without modifying their core functionality. They follow the decorator pattern from software design to add supplementary behaviors to existing objects at runtime.

Core decorator concept

Decorators in Kolibrium wrap around standard Selenium WebDriver and WebElement objects to intercept and augment their methods. This enables you to add cross-cutting functionality that applies consistently across your test suite without cluttering your test code.

The decorator framework consists of:

  1. AbstractDecorator - The base class that all decorators extend, handling the initial type checking and routing
  2. DecoratorManager - Manages decorators on a per-thread basis for parallel test execution
  3. Concrete decorators - Specialized implementations for specific behaviors

Available decorators

Kolibrium provides several built-in decorators.

SlowMotionDecorator

Adds configurable delays between Selenium operations, useful for:

  • Debugging tests visually
  • Creating demonstrations or recordings
  • Simulating human-like interaction timing

Example usage:

DecoratorManager.addDecorators(SlowMotionDecorator(2.seconds))

HighlighterDecorator

Visually highlights elements on the page by adding a colored border around them when they're found or interacted with:

  • Configurable border style, color, and width
  • Automatically cleans up previous highlights
  • Helps visualize which elements are being targeted during test execution

Example usage:

DecoratorManager.addDecorators(HighlighterDecorator(
style = BorderStyle.SOLID,
color = Color.BLUE,
width = 3
))

ElementStateCacheDecorator

Optimizes performance by caching positive state check results for elements:

  • Eliminates redundant WebDriver calls for state checks
  • Caches only positive results (true values)
  • Configurable for different state methods (displayed, enabled, selected)

Example usage:

DecoratorManager.addDecorators(ElementStateCacheDecorator(
cacheDisplayed = true,
cacheEnabled = true,
cacheSelected = false
))

Applying decorators

There are two ways to apply decorators: define them at the test-level or through project-level configuration. The latter approach can be found under the project-level configuration.

Test-level vs project-level decorator precedence rule

Kolibrium applies this precedence rule to decide what decorators shall be used in tests:

  • If only project-level decorators exist (through AbstractSeleniumProjectConfiguration), they will be used
  • If only test-level decorators exist (through DecoratorManager), they will be used
  • If both exist, test-level decorators take precedence
  • If neither exists, the original SearchContext is returned unchanged

Applying decorators at the test-level

Decorators can be applied at the test-level through the DecoratorManager:

@BeforeEach
fun setup() {
DecoratorManager.addDecorators( // Add decorators before the start of your tests
SlowMotionDecorator(1.seconds),
HighlighterDecorator(style = DASHED, color = GREEN, width = 5)
)
}

@AfterEach
fun cleanup() {
DecoratorManager.clearDecorators() // Clear decorators after tests execution
}

Decorators are applied in the order they're added, allowing you to combine multiple decorators to create a customized testing experience.

Why not implementing decorators with WebDriverDecorator or EventFiringDecorator from Selenium support library?

Firstly, the WebDriverDecorator and EventFiringDecorator are designed primarily for WebDriver instances and not suitable for modifying the behavior of WebElement.findElement() calls or wrapping the returned elements, so they would not work with Page Component Objects.

Secondly, they are annotated with @Beta which is according to the Javadoc:

Indicates that a feature or API is in active development, and so should not be relied upon. The update policy for anything marked beta is that it may be deleted in the next Selenium release without warning.

While the second point is slightly concerning, the first one is a significant limitation.

Kolibrium's AbstractDecorator implementations address this limitation because:

  • They are more flexible than the WebDriverDecorator or EventFiringDecorator approach.
  • They work consistently for both top-level (through WebDriver) and nested element (through WebElement) searches (both single and multiple elements).

Benefits of using Kolibrium's decorators

  1. Separation of Concerns: Keep test logic separate from cross-cutting concerns.
  2. Reusability: Apply the same enhancements across multiple tests.
  3. Thread Safety: Decorators are managed per-thread for parallel test execution.
  4. Dynamic Application: Add or remove behaviors at runtime.
  5. Non-Invasive: Enhance functionality without modifying the core Selenium classes or requiring changes to their source code. This maintains compatibility with future Selenium updates and allows you to add behaviors without subclassing or replacing the original implementation.

Decorators provide a powerful way to enhance your Selenium tests with visual feedback, performance optimizations, and debugging capabilities while maintaining clean and modular test code.