When using SlowLoadableComponent we have to remember that in the Java Throwable hierarchy the Error and the Exception are siblings. This means that you have to catch exceptions in SlowLoadableComponents and convert them to Errors to cause synchronisation to take place.
The most common mistake when using SlowLoadableComponent
is for the isLoaded
method to throw exceptions.
This Will Not Sync
A SlowLoadableComponent
with the following isLoaded
method would never wait because it never throws an Error
.
@Override
protected void isLoaded() throws Error {
// button must exist
final WebElement button =
driver.findElement(By.id("button00"));
if(!button.isDisplayed() && !button.isEnabled()){
throw new RuntimeException("Button not Ready");
}
}
isLoaded
throws an error to signify the page is not ready.
Explanation
The Java Throwable inheritance hierarchy, just so we remember that Error and Exceptions are siblings:
- Throwable
- Error
- Exception
- RuntimeException
A Brief intro into SlowLoadableComponent, you can skip the next two paragraphs if you already know what it is:
The SlowLoadableComponent is a support class in WebDriver which provides a simple and consistent way of writing PageObjects which model pages and components that take additional time from being present in the DOM to being ready to use.
A SlowLoadableComponent has a public ‘get’ method that it inherits from SlowLoadableComponent, and 2 additional methods a ’load’ and an ‘isLoaded’ method. When the ‘get’ method is called, the ‘isLoaded’ method is used to check if the component is loaded, if not then the ’load’ method is called, and then the SlowLoadableComponent polls the ‘isLoaded’ method until the component is loaded or a timeout time is exceeded.
The SlowLoadableComponent in the Java support classes for WebDriver uses Error
as the escape mechanism in its get() processing:
public T get() {
try {
isLoaded();
return (T) this;
} catch (Error e) {
load();
}
...
In Java For Testers I wrote the following paragraph when describing the difference between Error and Exception.
Error
is reserved for serious Java platform errors. The general guidance provided to Java programmers is “never catch a JavaError
”, which also means we should never catch aThrowable
.
As a result I tend to get a little uneasy when throwing Errors, as I prefer to throw Exceptions.
When I use SlowLoadableComponent, I bite the bullet and write throw new Error
in my abstraction layers because I need to.
But, the WebDriver code throws exceptions.
WebDriver is particularly fond of NoSuchElementException
, especially when your page hasn’t loaded, so if you do something like the following in your isLoaded
:
WebElement elem = driver.findElement(By.id("button00"));
…and if the driver cannot find the element, and this is the first time your isLoaded
is called then an Exception
will be thrown rather than an Error
, and your load
method will not be called.
Wrap your code in a try
catch
block and convert any Exception
into Error
so that you comply with the contract for SlowLoadableComponent
.
try {
final WebElement button =
driver.findElement(By.id("button00"));
if(!button.isDisplayed() && !button.isEnabled()){
throw new RuntimeException("Button not Ready");
}
}catch(Exception e){
throw new Error(e);
}
Assuming of course that you do want the load method to fire.
Note: that very often you don’t experience this because the load
method is often left empty - particularly when it is a component in a page, or navigated to organically e.g. by clicking a link, rather than an explicit ‘get’.
So, just a cautionary word, based on experience… Handle the exceptions in your isLoaded
methods and convert them to Error
because that is what the SlowLoadableComponent
needs.
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. And we have a full course on Page Objects and the SlowLoadableComponent
is covered in depth in our Support classes course.