6

如果您使用以下代码检查缺失的元素:

// ...
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
try {
    driver.findElement(By.cssSelector("td.name"));
} catch (NoSuchElementException e) {

    // here you go, element not found

}

你得到了正确的结果,但运行时间总是 30 秒,因为findElement方法阻塞了隐式等待。

有没有办法避免这种行为,同时保持隐式等待?

<EDIT>测试将由非开发人员通过 Selenium IDE 生成,因此我需要一个使他们的工作尽可能简单的解决方案(即保持隐式等待!)。</EDIT>

谢谢,

马可

4

6 回答 6

3

即使元素不再存在,上述方法也会等待提供的时间量。我编写了自己的方法来等待元素可见且不存在。他们为我工作。他们来了:

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);
}
于 2013-03-18T10:17:12.130 回答
2

我没有设置超时,而是使用 2.25 中引入的 fluentWait。

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));
}

如果您要将您的方法转换为类似的方法,您将能够删除driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);允许您立即“不”查找元素的选项。

希望这可以帮助!

于 2012-10-06T03:59:29.443 回答
2

您也许可以使用 xpath 选择器来做到这一点。在它之前找到你知道应该在那里的元素,然后使用“following-sibling”来获取下一个元素。就像是:

//td.previous/following-sibling::td

然后检查它是否没有返回“名称”。当然,这只有在有另一个“td”元素的情况下才有效。

就我个人而言,我很想放弃隐式等待,只在需要时使用等待。

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 ) );
        }
    } );
}
于 2012-10-05T14:30:06.223 回答
0

你不能。 implicit等待时间将优先于显式等待。如果您的implicit时间是 30 秒,那么您运行的任何查找将至少需要 30 秒,以防元素不存在。您可以做的是操纵implicit框架上的等待时间,但不确定如何与 IDE 配合使用,我从未使用过它。

我创建了一个返回boolean结果的自定义方法。输入是WebDriver (CSS, xpath, etc)支持的任何By 定位器。或者,您可以根据需要对其进行修改。

它有助于使我的代码更简洁、更快速。我希望它也能帮助其他人。

默认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;
    };
于 2015-04-06T20:40:11.280 回答
0

您必须暂时更新 ImplicitWait,并在完成后将其重置。

这是我们处理这种情况的方式 - 保存当前默认值,暂时更新 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));
        }
}
于 2014-09-24T00:24:25.050 回答
0

你需要一个这样的函数,它使用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;
        }
    };
}

FluentWait然后您可以按照 Falkenfighter 的描述设置一个对象,并且:

fluentWait.until(elementCountIs(By.cssSelector("td.name"), 0);
于 2014-04-30T09:45:47.280 回答