Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebDriver: How to check if an page object web element exists?

How to check if an Element exists, when using Page Objects with webdriver.

So far I am doing it this way.

DefaultPage defaultPage = PageFactory.initElements(this.driver,
      DefaultPage.class);
assertTrue(defaultPage.isUserCreateMenuLinkPresent());

Page Object:

public class DefaultPage {     
    @FindBy(id = "link_i_user_create")
    private WebElement userCreateMenuLink;


    public boolean isUserCreateMenuLinkPresent() {
        try {
            this.userCreateMenuLink.getTagName();
            return true;
        } catch (NoSuchElementException e) {
            return false;
        }
    }
 }

But I can not believe that this try/catch is the way one should do it. So what would be a better way to check if the elements exits (with using Page Objects)?

like image 497
Ralph Avatar asked Jun 30 '11 10:06

Ralph


2 Answers

The problem is the pattern itself. It uses @FindBy annotation (used by PageFactory to init the fields that must be wrapped by Proxy) that replaces the standard elements with their proxy instances which contain InvocationHandler.

Each time you try to access a field, annotated with @FindBy, the invocation handler tries to find the element using the default ElementLocator.The problem is that the ElementLocator.findElement() method throws an TimeoutException / NoSuchElementException if there are no elements presented in the DOM.

public WebElement findElement(SearchContext context) {
   List<WebElement> allElements = findElements(context);
   if (allElements == null || allElements.isEmpty())
      throw new NoSuchElementException("Cannot locate an element using "
      + toString());
   return allElements.get(0);
}

Therefore, each time you need to check whether an element is displayed or not you have to search for a List of elements and check its size.

@FindBy(css = "div.custom")
private List<WebElement> elements
...

public isElementPresented(){
   return elements != null && elements.size > 0
}

Another way to solve this problem is to create your own implementation of LocatingElementHandler and ElementLocator

So, if you need your own isDisplayed() method to return false instead of Exception, you have to replace the findElement() method in ElementLocator with something like that:

...
List<WebElement> elements = searchContext.findElements(by)
if(elements != null && elements.size() > 0){
   List<WebElement> visibleElements = []
   elements.each {
      if(it.displayed){
         visibleElements.add(it)
      }
   }
   if(visibleElements.size() > 0){
      return visibleElements.get(0)
   }
}
return null
...

And add new conditions to LocatingElementHandler.invoke()

Something like:

element = locator.findElement()
if(element == null){
   if(method.name == "isDisplayed"){
      return false
   }
}
like image 194
Andrey Shkrob Avatar answered Nov 16 '22 15:11

Andrey Shkrob


Webdriver is designed to throw an exception if an element is not found, So there aren't any methods to verify presence of an element in Webdriver.

Check this - http://groups.google.com/group/webdriver/browse_thread/thread/909a9b6cb568e341

like image 4
dmp Avatar answered Nov 16 '22 14:11

dmp