WebDriver Selenium API:Element明显存在时出现ElementNotFoundErrorException!

Posted

技术标签:

【中文标题】WebDriver Selenium API:Element明显存在时出现ElementNotFoundErrorException!【英文标题】:WebDriver Selenium API: ElementNotFoundErrorException when Element is clearly there ! 【发布时间】:2011-05-05 23:02:06 【问题描述】:

有时在关闭 javascript 的情况下在 WebDriver 上运行测试时,WebDriver 在找到元素并尝试单击它时会由于 ElementNotFound 错误而崩溃。

但是,元素显然存在!

阅读后:http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_My_XPath_finds_elements_in_one_browser,_but_not_in_others._Wh

我得出的结论是 webdriver 一定不能等到网页完成加载。如何使用 Webdriver 等待类?有人可以举个例子吗?

【问题讨论】:

【参考方案1】:

这个例子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"));

【讨论】:

你能解释一下“功能”吗?没有这样的对象称为“函数”,想知道是否可以更好地把它放在上下文中?【参考方案2】:

进一步了解 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 实例(而不是 WebDriverWait)执行。通过将其执行和必要的异常处理包装在实用方法中,给自己一个漂亮的编程接口(@98​​7654321@ 类型层次结构的根是一个好地方):

/**
 * @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
    

【讨论】:

你的例子没有解释什么是“elementLocated”。 是的。它是一个方法(在我的第一个代码块中定义),它返回一个函数,而 FluentWait 又会重复调用该函数,直到返回一个对象、超时到期或抛出一个不可忽略的异常(以先到者为准)。【参考方案3】:

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&lt;WebDriver&gt;(使用更快):

WebDriverWait wait = new WebDriverWait(driver, 30000);
WebElement item = wait.until(ExpectedConditions.visibilityOfElementLocated(yourBy));

ImplicitWait - 不推荐,因为它为所有会话配置一次。这也用于每个 find 元素并仅等待存在(无 ExpectedConditions 等...):

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

【讨论】:

以上是关于WebDriver Selenium API:Element明显存在时出现ElementNotFoundErrorException!的主要内容,如果未能解决你的问题,请参考以下文章

python+selenium自动测试之WebDriver的常用API(基础篇一)

selenium 常用api

selenium webdriver API是像JAVA API一样的吗?

java+selenium3-常用的WebDriver API

Selenium2+Python:Webdriver API速记手册

Selenium Webdriver API