【发布时间】:2011-05-05 23:02:06
【问题描述】:
有时在关闭 Javascript 的情况下在 WebDriver 上运行测试时,WebDriver 在找到元素并尝试单击它时会由于 ElementNotFound 错误而崩溃。
但是,元素显然存在!
我得出的结论是 webdriver 一定不能等到网页完成加载。如何使用 Webdriver 等待类?有人可以举个例子吗?
【问题讨论】:
标签: webdriver
有时在关闭 Javascript 的情况下在 WebDriver 上运行测试时,WebDriver 在找到元素并尝试单击它时会由于 ElementNotFound 错误而崩溃。
但是,元素显然存在!
我得出的结论是 webdriver 一定不能等到网页完成加载。如何使用 Webdriver 等待类?有人可以举个例子吗?
【问题讨论】:
标签: webdriver
这个例子was posted on Google Groups。根据 Google 开发人员的说法:
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
/**
* @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 - 不推荐,因为它为所有会话配置一次。这也用于每个 find 元素并仅等待存在(无 ExpectedConditions 等...):
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
【讨论】: