Abstraction layers can provide a new layer of specificity or flexibility to an existing library. How can we make a WebElement
more fluent and act as a readable Domain Specific Language?
What might a WebElement DSL look like?
@Test
public void whatIfWeHadAFluentWebElementForSearchPage(){
FluentWebElement searchBox = new FluentWebElement(
driver.findElement(By.name("q")));
searchBox.clear().then().
sendKeys("Fluent Programming").and().submit();
Assertions.assertTrue(
driver.getTitle().contains("Fluent Programming"));
}
And how was this done?
FluentWebElement is a class that wraps the WebElement, delegating off to the WebElement most of the time, and returning self for all those WebElement methods that normally void out.
e.g. the important bits
private WebElement webElement;
public FluentWebElement(WebElement aWebElement){
this.webElement = aWebElement;
}
// Fluentese
public FluentWebElement click() {
webElement.click();
return this;
}
public void submit() {
webElement.submit();
}
public FluentWebElement sendKeys(CharSequence... keysToSend) {
webElement.sendKeys(keysToSend);
return this;
}
public FluentWebElement clear() {
webElement.clear();
return this;
}
public FluentWebElement and(){
return this;
}
public FluentWebElement then(){
return this;
}
Element Level DSL
With DSLs it is important to keep the context fairly tight, e.g. if any of these methods returned a Page Object or another object too far off track then it could create very long method chains.
And the aim is not to create a long method chain, the aim is to create readable tests that use the IDE to support writing code through code completion.
Full Source
The full source for this is in my Webdriver Java FAQs project:
Specifically:
If you want to learn how to use Selenium WebDriver with Java then check out our online courses. We even have a course on Page Objects and Abstraction Layers.
Note: this post was originally written in 2012 and formed part of my webdriverexperiments repo, I updated this on 20200630 to be one of the WebDriver FAQs.