有时在关闭 Javascript 的情况下在 WebDriver 上运行测试时,WebDriver 在找到元素并尝试单击它时会由于 ElementNotFound 错误而崩溃。
但是,元素显然存在!
我得出的结论是 webdriver 一定不能等到网页完成加载。如何使用 Webdriver 等待类?有人可以提供一个例子吗?
有时在关闭 Javascript 的情况下在 WebDriver 上运行测试时,WebDriver 在找到元素并尝试单击它时会由于 ElementNotFound 错误而崩溃。
但是,元素显然存在!
我得出的结论是 webdriver 一定不能等到网页完成加载。如何使用 Webdriver 等待类?有人可以提供一个例子吗?
此示例发布在 Google Groups 上。根据谷歌开发者的说法:
1 使用隐式等待。在这里,驱动程序将一直等到指定的超时时间,直到找到元素。请务必阅读 javadoc 中的注意事项。用法:
driver.get("http://www.google.com");
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
WebElement element = driver.findElement(By.name("q"));
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
// continue with test...
2 使用org.openqa.selenium.support.ui.WebDriverWait
类。这将轮询直到预期的条件为真,返回该条件的结果(如果它正在寻找一个元素)。这比隐式等待灵活得多,因为您可以定义任何自定义行为。用法:
Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
return new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
// ...
driver.get("http://www.google.com");
WebDriverWait wait = new WebDriverWait(driver, /*seconds=*/3);
WebElement element = wait.until(presenceOfElementLocated(By.name("q"));
将 nilesh 的回答更进一步,您还可以通过使用 SearchContext 接口允许更精细的搜索(例如,在 WebElement 的上下文中):
Function<SearchContext, WebElement> elementLocated(final By by) {
return new Function<SearchContext, WebElement>() {
public WebElement apply(SearchContext context) {
return context.findElement(by);
}
};
}
执行由 FluentWait<SearchContext> 实例(而不是 WebDriverWait)执行。通过将其执行和必要的异常处理包装在一个实用方法中,给自己一个漂亮的编程接口(PageObject类型层次结构的根是一个好地方):
/**
* @return The element if found before timeout, otherwise null
*/
protected WebElement findElement(SearchContext context, By by,
long timeoutSeconds, long sleepMilliseconds) {
@SuppressWarnings("unchecked")
FluentWait<SearchContext> wait = new FluentWait<SearchContext>(context)
.withTimeout(timeoutSeconds, TimeUnit.SECONDS)
.pollingEvery(sleepMilliseconds, TimeUnit.MILLISECONDS)
.ignoring(NotFoundException.class);
WebElement element = null;
try {
element = wait.until(elementLocated(by));
}
catch (TimeoutException te) {
element = null;
}
return element;
}
/**
* overloaded with defaults for convenience
*/
protected WebElement findElement(SearchContext context, By by) {
return findElement(context, by, DEFAULT_TIMEOUT, DEFAULT_POLL_SLEEP);
}
static long DEFAULT_TIMEOUT = 3; // seconds
static long DEFAULT_POLL_SLEEP = 500; // milliseconds
示例用法:
WebElement div = this.findElement(driver, By.id("resultsContainer"));
if (div != null) {
asyncSubmit.click();
WebElement results = this.findElement(div, By.id("results"), 30, 500);
if (results == null) {
// handle timeout
}
}
Fluent Wait - 最好的方法,因为它是最灵活和可动态配置的(具有忽略异常选项,轮询每个,超时):
public Wait<WebDriver> getFluentWait() {
return new FluentWait<>(this.driver)
.withTimeout(driverTimeoutSeconds, TimeUnit.SECONDS)
.pollingEvery(500, TimeUnit.MILLISECONDS)
.ignoring(StaleElementReferenceException.class)
.ignoring(NoSuchElementException.class)
.ignoring(ElementNotVisibleException.class)
}
像这样使用:
WebElement webElement = getFluentWait().until(x -> { return driver.findElement(elementBy); } );
显式等待FluentWait
- 好吧,它与预配置的等待类型相同,但具有pollingEvery
等待类型,例如FluentWait<WebDriver>
(使用更快):
WebDriverWait wait = new WebDriverWait(driver, 30000);
WebElement item = wait.until(ExpectedConditions.visibilityOfElementLocated(yourBy));
ImplicitWait - 不推荐,因为它为您的所有会话配置一次。这也用于每个查找元素并仅等待存在(不等ExpectedConditions
...):
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);