【问题标题】:WebDriver Selenium API: ElementNotFoundErrorException when Element is clearly there !WebDriver Selenium API:Element明显存在时出现ElementNotFoundErrorException!
【发布时间】: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 等待类?有人可以举个例子吗?

【问题讨论】:

    标签: 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);
    

    【讨论】:

      猜你喜欢
      • 2014-03-03
      • 2017-06-09
      • 2013-05-26
      • 1970-01-01
      • 1970-01-01
      • 2018-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多