Selenium: пусть findElements ждет видимого элемента, хотя невидимый элемент существует
Мы хотим отправить некоторые ключи элементу, идентифицированному по имени. В приложении может быть несколько элементов с одинаковым именем, но в этом случае будет виден только один элемент. Для этого у нас есть такой фрагмент кода (упрощенный код, без производственного кода):
List<WebElement> list = driver.findElements(By.xpath("//[@name='title']"));
for (WebElement elem : list) {
try {
elem.sendKeys(value);
break;
} catch (Exception e) {
// ignore
}
}
Если элемент title еще не существует, мы ожидаем его появления, используя неявное ожидание. Так что обычно это будет работать нормально. В любом случае, иногда мы имеем дело с тем, что уже есть элементы с таким именем (но они скрыты), и правильный будет просто создан асинхронным кодом. Но в этом случае код не будет работать. Как findElements()
вернется немедленно (без неявного ожидания), просто вернув невидимые элементы. В этом случае sendKeys()
будет ждать, пока элемент станет видимым, но этого не произойдет (игнорирование новых элементов, созданных после findElements
) и поэтому он не работает после неявного тайм-аута ожидания.
В основном нам нужна возможность сказать findElements()
что мы просто хотим иметь видимые элементы. Если видимых элементов нет, Selenium должен дождаться неявного ожидания. Это возможно?
2 ответа
Основываясь на ответе от DebanjanB и JeffC, я смог создать собственную реализацию ожидания, которая ожидает первый видимый элемент, но также учитывает элементы, созданные во время ожидания:
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;
});
Или с потоками;-)
new WebDriverWait(driver, 5).until(drv -> {
List<WebElement> elements = drv.findElements(By.xpath("//[@name='title']"));
return elements.stream()
.filter(WebElement::isDisplayed)
.findFirst()
.orElse(null);
});
Поскольку ваш сценарий использования включает в себя:
- может быть несколько элементов с одинаковым именем, но в этом случае будет виден только один элемент
- отправить несколько ключей элементу, указанному по имени
- ждать, пока оно появится
- используя неявное ожидание
Многофункциональным решением для удовлетворения всех вышеупомянутых условий было бы использование WebDriverWait в сочетании с ExpectedConditions, установленным как elementToBeClickable()
,
elementToBeClickable()
: Ожидание проверки элемента является видимым и включенным, так что вы можете щелкнуть по нему.Пример кода:
try { new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//button[@class='nsg-button']"))).sendKeys(value); } catch (TimeoutException e) { System.out.println("Desired element was not present"); }
Кроме того, вы должны удалить все экземпляры ImplicitWait
Примечание: не смешивайте
implicit and explicit waits
, Это может привести кunpredictable wait times
, Например, установка неявного ожидания 10 секунд и явного ожидания 15 секунд может привести к возникновению тайм-аута через 20 секунд.
Соответствующее обсуждение можно найти в разделе Замена неявного ожидания явным ожиданием (selenium webdriver & java).