java Selenium 2 - 如何在隐式等待时检查元素是否不存在?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12747444/
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 2 - How to check if element not present while implicitly waiting?
提问by Marco Bolis
If you check absent elements with the following code:
如果您使用以下代码检查不存在的元素:
// ...
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
try {
driver.findElement(By.cssSelector("td.name"));
} catch (NoSuchElementException e) {
// here you go, element not found
}
You get right result, but running time is always 30 seconds, due to findElement
method blocking on the implicit wait.
您得到正确的结果,但由于findElement
隐式等待上的方法阻塞,运行时间始终为 30 秒。
Is there a way to avoid this behavior, while keeping the implicit wait in place?
有没有办法避免这种行为,同时保持隐式等待?
<EDIT>
tests are going to be generated through Selenium IDE by non-developers, so I need a solution that keeps their job as simple as possible (that's keeping waits implicit!). </EDIT>
<EDIT>
测试将由非开发人员通过 Selenium IDE 生成,因此我需要一个解决方案,使他们的工作尽可能简单(即保持隐式等待!)。 </EDIT>
Thanks,
谢谢,
Marco
马可
回答by Istvan Kis
The methods above wait for the provided amount of time even if the element is not present anymore. I wrote my own methods for waiting until element is visible and not present. They work for me. Here they are:
即使元素不再存在,上述方法也会等待提供的时间量。我编写了自己的方法来等待元素可见且不存在。他们对我来说有效。他们来了:
public void waitUntilElementExists(By by, int waitSeconds,
int noOfRetries) {
getDriver().manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
boolean foundElement = false;
for (int i = 0; i < noOfRetries; i++)
try {
getDriver().findElement(by);
foundElement = true;
break;
} catch (Exception e) {
}
assertTrue("The searched element was not found after " + noOfRetries * waitSeconds + " seconds!", foundElement);
}
public void waitUntilElementDoesntExist(By by, int waitSeconds,
int noOfRetries) {
getDriver().manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
boolean elementDisappeared = false;
for (int i = 0; i < noOfRetries; i++)
try {
getDriver().findElement(by);
waitABit(1000 * waitSeconds);
} catch (Exception e) {
elementDisappeared = true;
break;
}
assertTrue("The searched element did not disappear after " + noOfRetries * waitSeconds + " seconds!", elementDisappeared);
}
回答by Nick Wilson
You might be able to do it with xpath selectors. Find the element just before it that you know should be there, then use "following-sibling" to get the next element. Something like:
您也许可以使用 xpath 选择器来实现。找到您知道应该在它之前的元素,然后使用“following-sibling”来获取下一个元素。就像是:
//td.previous/following-sibling::td
Then check to see that it hasn't returned the "name" one. Of course that would only work if there is another "td" element.
然后检查它是否没有返回“名称”。当然,这只有在有另一个“td”元素时才有效。
Personally I'd be tempted to drop the implicit waits and just use waits when they are required.
就我个人而言,我很想放弃隐式等待,只在需要时使用等待。
private WebElement cssWait( final String css )
{
return new WebDriverWait( driver, 30 ).until( new ExpectedCondition< WebElement >()
{
@Override
public WebElement apply( WebDriver d )
{
return d.findElement( By.cssSelector( css ) );
}
} );
}
回答by Falkenfighter
Instead of setting up timeouts I use fluentWait which were introduced in 2.25.
我没有设置超时,而是使用 fluentWait,它是在 2.25 中引入的。
public void waitForElement(WebDriver driver, final String xpath)
{
//Set up fluentWait to wait for 35 seconds polling every 1
Wait<WebDriver> fluentWait = new FluentWait<WebDriver>(driver)
.withTimeout(35, TimeUnit.SECONDS)
.pollingEvery(1, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement element;
//Look for element, if not found start fluentWait
try
{
element = driver.findElement(By.xpath(xpath));
}
catch (WebDriverException e)
{
logger.info("[getElementByXpath] Element not initially found. Starting fluentWait ["+xpath+"]");
try
{
element = fluentWait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver d) {
return d.findElement(By.xpath(xpath));
}
});
}
catch (WebDriverException f)
{
logger.info("[getElementByXpath] FluentWait findElement threw exception:\n\n" + f +"\n\n");
throw new WebDriverException("Unable to find element ["+xpath+"]");
}
}
//Once we've found the element wait for element to become visible
fluentWait.until(ExpectedConditions.visibilityOf(element));
}
If you were to convert your methods to something like this, you would be able to remove your driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
allowing you to 'Not' find an element instantly.
如果您要将您的方法转换为这样的方法,您将能够删除driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
允许您立即“不”找到元素的选项。
Hope this helps!
希望这可以帮助!
回答by Tim Band
You need a function like this, that uses findElements
, not findElement
:
你需要一个这样的函数,它使用findElements
,而不是findElement
:
public static ExpectedCondition<Boolean> elementCountIs(final By sel, final int count) {
return new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return driver.findElements(sel).size() == count;
}
};
}
Then you can set up a FluentWait
object as described by Falkenfighter and:
然后,您可以FluentWait
按照 Falkenfighter 的描述设置一个对象,然后:
fluentWait.until(elementCountIs(By.cssSelector("td.name"), 0);
回答by lvanzyl
You'll have to update the ImplicitWait temporarily, and reset it after you're done.
您必须暂时更新 ImplicitWait,并在完成后重置它。
This is the way we've handled this situation - save the current default, update the ImplicitWait temporarily, then change back to the default afterwards.
This is based off Mozilla's suggestion, which is how they handle this situation where you are expecting something to notbe present:
https://blog.mozilla.org/webqa/2012/07/12/webdrivers-implicit-wait-and-deleting-elements/
这是我们处理这种情况的方式 - 保存当前默认值,临时更新 ImplicitWait,然后更改回默认值。
这是基于 Mozilla 的建议,这就是他们如何处理您期望某些东西不存在的情况:https:
//blog.mozilla.org/webqa/2012/07/12/webdrivers-implicit-wait-and-删除元素/
public bool ElementExists(By by, int waitMilliseconds)
{
var defaultWebDriverTimeout = 30000;// Get default timeout that you're using
WebDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromMilliseconds(waitMilliseconds));
try
{
WebDriver.FindElement(by); //Note could be FindElements instead, but this is quicker
return true;
}
catch (NoSuchElementException)
{
return false;
}
finally
{
WebDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromMilliseconds(defaultWebDriverTimeout));
}
}
回答by cbaldan
No, you cannot.
implicit
wait time will have precedence over explicit waits.
If your implicit
time is 30s, any finds you run will at least 30s in case the element is not present.
What you could do is manipulate the implicit
wait time on your framework, but not sure how that goes with the IDE, I've never worked with it.
你不能。
implicit
等待时间将优先于显式等待。如果您的implicit
时间是 30 秒,那么在元素不存在的情况下,您运行的任何发现至少需要 30 秒。您可以做的是操纵implicit
框架上的等待时间,但不确定 IDE 的情况如何,我从未使用过它。
I created a custom method that returns a boolean
with the result.
The input is any By locatorsupported by WebDriver (CSS, xpath, etc).
Or, you can modify it as you like.
我创建了一个返回boolean
结果的自定义方法。输入是WebDriver(CSS、xpath 等)支持的任何By locator。或者,您可以根据需要对其进行修改。
It helped to make my code cleaner and faster. I hope it helps other people too.
它有助于使我的代码更清晰、更快。我希望它也能帮助其他人。
The default pooling
is 500 Millis, but it can be changed on the wait
object.
默认pooling
值为 500 毫秒,但可以在wait
对象上更改。
public boolean isElementNotPresent(final By locator) {
boolean result = false;
// use your custom timeout here
long timeout = ConfigurationProvider.getWebDriverWaitTimeout();
// log4j used
msg = "isElementNotPresent: " + locator;
LOG.info(msg);
Wait<WebDriver> wait = new FluentWait<WebDriver>(
getDriver()).withTimeout(timeout, TimeUnit.SECONDS);
try {
result = wait.until(new Function<WebDriver, Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
return driver.findElements(locator).size() == 0;
}
});
} catch (TimeoutException e) {
msg = String.format("Element remained visible after %.2f seconds",
((float) timeout / 1000));
LOG.debug(msg);
} catch (Exception e) {
msg = "Exception at isElementNotPresent()\n" + e.getMessage();
// I use jUnit to fail my test
Assert.fail(msg);
}
return result;
};