Java Selenium WebDriver:当无法使用 WebDriver.findElement 定位时,等待元素出现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19851518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Selenium WebDriver: wait for element to be present when locating with WebDriver.findElement is impossible
提问by user2432405
It's convenient to wait for an WebElement
to be present with WebDriverWait
and ExpectedConditions
.
等待 anWebElement
与WebDriverWait
and一起出现很方便ExpectedConditions
。
The problem is, what if WebElement.findElment
was the only possible way to locate the element , 'cause it has no id, no name, no unique class?
问题是,如果WebElement.findElment
是定位元素的唯一可能方法,因为它没有 id、没有名称、没有唯一的类怎么办?
WebDriverWait
's constructor accepts only WebDriver
as arguments, not WebElement
.
WebDriverWait
的构造函数只接受WebDriver
作为参数,而不接受WebElement
。
I've set the implicitlyWait
time, so it seems not a good idea to use try{} catch(NoSuchElementException e){}
, 'cause I don't want to wait that long time for this element.
我已经设置了implicitlyWait
时间,所以使用 似乎不是一个好主意try{} catch(NoSuchElementException e){}
,因为我不想为这个元素等待那么长时间。
Here's the scenario:
这是场景:
There's one web page with a form containing many input
tags. Each input
tag has a format requirement.
有一个包含许多input
标签的表单的网页。每个input
标签都有格式要求。
A dynamic div
tag would be present after this input
tag when the format requirement is not satisfied.
当不满足格式要求时,该div
标签后将出现一个动态标签input
。
As there're so many input
tags, I create a general method like:
由于input
标签太多,我创建了一个通用方法,例如:
public WebElement txtBox(String name) {
return driver.findElement(By.name(name));
}
instead of creating a data member for each input
tag.
而不是为每个input
标签创建一个数据成员。
Then I create a method isValid
to check whether user inputs in some input
are valid. All I should do in isValid
is to check whether a div
tag is present after inputboxToCheck
, with code like this:
然后我创建了一个方法isValid
来检查用户输入是否input
有效。我应该做的isValid
就是检查div
在 之后是否存在标签inputboxToCheck
,代码如下:
public boolean isValid(WebElement inputboxToCheck) {
WebElementWait wait = new WebElementWait(inputboxToCheck, 1);
try {
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("./following-sibling::div")));
return false;
} catch (TimeOutException e) {
return true;
}
}
WebElementWait
is an imaginary (not exist) class which works the same way as WebDriverWait
.
WebElementWait
是一个虚构的(不存在的)类,其工作方式与WebDriverWait
.
采纳答案by user2432405
The WebElementWait class as metioned above:
上面提到的 WebElementWait 类:
package org.openqa.selenium.support.ui;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebElement;
public class WebElementWait extends FluentWait<WebElement> {
public final static long DEFAULT_SLEEP_TIMEOUT = 500;
public WebElementWait(WebElement element, long timeOutInSeconds) {
this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, DEFAULT_SLEEP_TIMEOUT);
}
public WebElementWait(WebElement element, long timeOutInSeconds, long sleepInMillis) {
this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, sleepInMillis);
}
protected WebElementWait(WebElement element, Clock clock, Sleeper sleeper, long timeOutInSeconds,
long sleepTimeOut) {
super(element, clock, sleeper);
withTimeout(timeOutInSeconds, TimeUnit.SECONDS);
pollingEvery(sleepTimeOut, TimeUnit.MILLISECONDS);
ignoring(NotFoundException.class);
}
}
It's the same as WebDriverWait, except that the WebDriver
argument is replaced with WebElement
.
它与 WebDriverWait 相同,只是WebDriver
参数被替换为WebElement
.
Then, the isValid method:
然后是 isValid 方法:
//import com.google.common.base.Function;
//import org.openqa.selenium.TimeoutException;
public boolean isValid(WebElement e) {
try {
WebElementWait wait = new WebElementWait(e, 1);
//@SuppressWarnings("unused")
//WebElement icon =
wait.until(new Function<WebElement, WebElement>() {
public WebElement apply(WebElement d) {
return d.findElement(By
.xpath("./following-sibling::div[class='invalid-icon']"));
}
});
return false;
} catch (TimeoutException exception) {
return true;
}
}
回答by Andrian Durlestean
I don't know if this help you, but it permits to wait element how much time do you want.
我不知道这是否对你有帮助,但它允许等待元素你想要多长时间。
public WebElement findDynamicElement(By by, int timeOut) {
WebDriverWait wait = new WebDriverWait(driver, timeOut);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
return element;
}
findDynamicElement(By.xpath("//body") , 30);
回答by Eric Francis
I found this blog: Checking for an element – exists?, visible?, present? - https://jkotests.wordpress.com/2012/11/02/checking-for-an-element-exists-visible-present/
我找到了这个博客:检查元素 – 存在吗?可见吗?存在吗?- https://jkotests.wordpress.com/2012/11/02/checking-for-an-element-exists-visible-present/
And it brought up the differences between exists, visible, and present.
它提出了存在、可见和现在之间的差异。
- exists? – Returns whether this element actually exists.
- present? – Returns true if the element exists and is visible on the page
- visible? – If any parent element isn't visible then we cannot write to the element. The only reliable way to determine this is to iterate up the DOM element tree checking every element to make sure it's
visible.
- 存在吗?– 返回此元素是否实际存在。
- 展示?– 如果元素存在并且在页面上可见,则返回 true
- 可见的?– 如果任何父元素不可见,则我们无法写入该元素。确定这一点的唯一可靠方法是迭代 DOM 元素树,检查每个元素以确保它是
可见的。
Exists will tell you if what you are searching for is anywhere in the DOM; however, WebDriver
does not seem to have a built in way to check if an element exists similar to plain driver.findElement(By.name(name))
.
Exists 会告诉您您要搜索的内容是否在 DOM 中的任何位置;但是,WebDriver
似乎没有内置的方法来检查是否存在类似于 plain 的元素driver.findElement(By.name(name))
。
And, as explained in the blog, Existsis not the same as Present. So I can't use ExpectedConditions.presenceOfAllElementLocatedBy(By.cssSelector(cssSelector)
而且,正如博客中所解释的,Exists与Present 不同。所以我不能用ExpectedConditions.presenceOfAllElementLocatedBy(By.cssSelector(cssSelector)
My solution: (looking for feedback here :)
我的解决方案:(在这里寻找反馈:)
public WebElement waitForElementExists(String selector, String timeout) {
Wait<WebDriver> wait = new WebDriverWait(driver, timeout);
WebElement element = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.cssSelector(selector));
}
});
return element;
}
回答by Nik
A more universal variant of user2432405's solution would be using SearchContext type rather then WebElement:
user2432405 解决方案的一个更通用的变体是使用 SearchContext 类型而不是 WebElement:
public class SearchContextWait extends FluentWait<SearchContext> {
...
This allows to do waits on both WebDriver and WebElement similarly as the SearchContext interface is the ancestor of both WebDriver and WebElement. The isValid method needs adjustment too:
这允许在 WebDriver 和 WebElement 上进行等待,类似于 SearchContext 接口是 WebDriver 和 WebElement 的祖先。isValid 方法也需要调整:
...
WebElement icon = wait
.until(new Function<SearchContext, WebElement>() {
public WebElement apply(SearchContext d) {
...
Unfortunately, you lose all conveniences of ExpectedConditions.xxxx() methods as they use the WebDriver interface internally.
不幸的是,您失去了 ExpectedConditions.xxxx() 方法的所有便利,因为它们在内部使用 WebDriver 接口。