2012-10-05 37 views
5

如果选中下面的代码缺少的元素:Selenium 2 - 如何在隐式等待时检查元素是否存在?

// ... 
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>测试将要由非开发人员通过硒IDE生成的,所以我需要,保持他们的工作尽可能简单的解决方案(这是保持等待隐含的!)。 </EDIT>

感谢,

马尔科

+0

你能不能做一个中心的方法,将隐含的等待设置为小的东西,然后重置为30秒? – Arran

+0

尽管我使用模板来转换用Selenium IDE编写的测试用例,但我希望将代码的更改保持在最低限度,但我会试图完全放弃这些implicits。 –

回答

2

你也许可以用XPath选择这样做。在它之前找到你知道应该在那里的元素,然后使用“跟随 - 兄弟”来获得下一个元素。例如:

//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)); 
     } 
    }); 
} 
+0

为巧妙的解决方案。不幸的是...见编辑 –

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);允许你“而不是”即刻找到一个元素。

希望这会有所帮助!

+0

这就是我通常会去的方式,谢谢。唉......看到编辑。 –

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

对不起,我现在意识到这是不正确的。隐式等待同样适用于findElement,因为findElement非常烦人。 –

0

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

这是我们处理这种情况的方式 - 保存当前的默认值,暂时更新ImplicitWait,然后再更改回默认值。
这是基于Mozilla的关闭的建议,这是他们如何处理这种情况下,你期待的东西不存在: https://blog.mozilla.org/webqa/2012/07/12/webdrivers-implicit-wait-and-deleting-elements/

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

不,你不能。 implicit等待时间优先于显式等待。 如果你的implicit时间是30秒,你运行的任何发现至少30秒,以防元素不存在。 你可以做的是在你的框架上操作implicit等待时间,但不知道如何与IDE一起工作,我从来没有使用它。

我创建了一个自定义方法,返回结果为boolean。 输入是任何通过定位器支持WebDriver(CSS,xpath等)。 或者,您可以随意修改它。

它有助于使我的代码更干净更快。我希望它也能帮助其他人。

默认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; 
    };