WebDriver Selenium API: ElementNotFoundErrorException when Element is clearly there !

前端 未结 3 452
旧时难觅i
旧时难觅i 2020-12-24 03:37

sometimes when running tests on WebDriver with Javascript turned off, WebDriver crashes due to an ElementNotFound Error when it finds an element, and attempts to click it.

相关标签:
3条回答
  • 2020-12-24 04:19

    This example was posted on Google Groups. According to Google developers:

    1 Use implicit waits. Here the driver will wait up until the designated timeout until the element is found. Be sure to read the javadoc for the caveats. Usage:

    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 Use the org.openqa.selenium.support.ui.WebDriverWait class. This will poll until the expected condition is true, returning that condition's result (if it's looking for an element). This is much more flexible than implicit waits, as you can define any custom behavior. Usage:

    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"));
    
    0 讨论(0)
  • 2020-12-24 04:39

    Taking nilesh's answer a step further, you can also allow finer-tuned searches (eg, within the context of a WebElement) by using the SearchContext interface:

    Function<SearchContext, WebElement> elementLocated(final By by) {
        return new Function<SearchContext, WebElement>() {
            public WebElement apply(SearchContext context) {
                return context.findElement(by);
            }
        };
    }
    

    Execution is performed by a FluentWait<SearchContext> instance (instead of WebDriverWait). Give yourself a nice programming interface by wrapping its execution and necessary exception handling in a utility method (the root of your PageObject type hierarchy is a good spot):

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

    Example usage:

    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
        }
    }
    
    0 讨论(0)
  • 2020-12-24 04:39

    Fluent Wait - Best approach as it's the most flexible and configurable on the fly (has ignore exceptions option, polling every, timeout):

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

    Use like so:

    WebElement webElement = getFluentWait().until(x -> { return driver.findElement(elementBy); } );
    

    Explicit Wait - Well it's the same as FluentWait but with pre-configured pollingEvery and the type of Wait e.g. FluentWait<WebDriver> (faster to use):

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

    ImplicitWait - Not recommended as it is configured once for all your session. This also is used for every find element and waits for presence only (no ExpectedConditions etc...):

    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    
    0 讨论(0)
提交回复
热议问题