SlowLoadableComponent and NoSuchElementException

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 if you want to avoid bugs in your PageObjects.

Note that this is a reminder to me because I forgot and spent 20 embarrassing minutes working out why my ‘load’ method wasn’t being called. Shame on me, as penance I write this post.

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 inderal price catch a Java `Error`”, which also means we should never catch a `Throwable`.

As a result I tend to get a little uneasy when throwing Errors, as I prefer to throw Exceptions. The official docs for LoadableComponent bypass that aversion by using assertions… I don’t like adding assertions in my abstraction code, I only want assertions in my tests.

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("findme"));

…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.

Remember to wrap your code in try catch blocks and convert any exceptions into Error so that you comply with the contract for SlowLoadableComponent.

try{
     WebElement elem = driver.findElement(By.id("findme"));
}catch(Exception e){
     throw new Error(e.getMessage());
}

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’.

But when you work like I do:

  • create code in the test
  • refactor the code to PageObjects

You are sometimes moving from a WebDriverWait (which captures and handles NoSuchElementExceptions) to the SlowLoadableComponent `isLoaded` method, which, as we saw above, does not.

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 works with.

 

This entry was posted in Selenium Simplified Blog, WebDriver. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *