We want to send some keys to an element identified by name. In the application there might be multiple elements with the same name but in that case just one will be visible. To do that we have a code snippet like that (simplistic code, no production code):
List<WebElement> list = driver.findElements(By.xpath("//[@name='title']"));
for (WebElement elem : list) {
try {
elem.sendKeys(value);
break;
} catch (Exception e) {
// ignore
}
}
If the title element is not yet there we wait for it to appear using implicit wait. So usually this will work fine. Anyway we sometimes have the case that there are already elements with that name (but are hidden) and the correct one will just be created by async code. But in this case the code will not work. As the findElements()
will return immediately (no implicit wait) just returning invisible elements. In that case sendKeys()
will wait for the element to become visible but this never happens (ignoring new elements created after findElements
) and so it fails after the implicit wait timeout.
Basically we need the possibility to tell findElements()
that we just want to have visible elements. If there are no visible elements Selenium should wait for the implicit wait duration. Is this possible?
Based on the answer from DebanjanB and JeffC I was able to create my own wait implementation that waits for the first visible element but also takes into consideration elements that are created during the wait:
new WebDriverWait(driver, 5).until(drv -> {
List<WebElement> elements = drv.findElements(By.xpath("//[@name='title']"));
for (WebElement element : elements) {
if (element.isDisplayed()) {
return element;
}
}
return null;
});
Or with streams ;-)
new WebDriverWait(driver, 5).until(drv -> {
List<WebElement> elements = drv.findElements(By.xpath("//[@name='title']"));
return elements.stream()
.filter(WebElement::isDisplayed)
.findFirst()
.orElse(null);
});