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
}
}