2010-11-06 17 views
9

a veces, al ejecutar pruebas en WebDriver con Javascript desactivado, WebDriver se cuelga debido a un error ElementNotFound cuando encuentra un elemento e intenta hacer clic en él.WebDriver Selenium API: ElementNotFoundErrorException cuando el elemento está claramente allí.

¡Sin embargo, el elemento está claramente allí!

Después de leer esto: http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_My_XPath_finds_elements_in_one_browser,_but_not_in_others._Wh

llegué a la conclusión de que WebDriver no debe estar esperando hasta que la página web se ha completado cargado. ¿Cómo uso la clase Webdriver Wait? ¿Alguien puede dar un ejemplo?

Respuesta

18

Este ejemplo was posted on Google Groups. De acuerdo con los desarrolladores de Google:

1 Use esperas implícitas. Aquí el controlador esperará hasta el tiempo de espera designado hasta que se encuentre el elemento. Asegúrese de leer el javadoc para las advertencias . Uso:

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 Utilice la clase org.openqa.selenium.support.ui.WebDriverWait. Esto hará sondeo hasta que la condición esperada sea verdadera, devolviendo el resultado de esa condición (si está buscando un elemento). Esto es mucho más flexible que el implícito, ya que puede definir cualquier comportamiento personalizado. Uso:

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")); 
+1

¿Puede explicar "Función"? No existe tal objeto llamado "Función" y se preguntaba si podría ponerlo en contexto mejor? – djangofan

3

Tomando un paso más allá respuesta de nilesh, también puede permitir búsquedas más finos-sintonizado (por ejemplo, en el contexto de un WebElement) mediante la interfaz SearchContext:

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

ejecución se lleva a cabo por una instancia de FluentWait <SearchContext> (en lugar de WebDriverWait). Dése una interfaz de programación agradable envolviendo su ejecución y el control de excepciones necesarias en un método de utilidad (la raíz de la jerarquía de tipos PageObject es un buen lugar): el uso

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

Ejemplo:

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

Su ejemplo no explica qué es "elementLocated". – djangofan

+0

Sí lo hace. Es un método (definido en mi primer bloque de código) que devuelve una Función, que a su vez es invocada repetidamente por FluentWait hasta que se devuelve un objeto, expira el tiempo de espera o se lanza una excepción no ignorada (lo que ocurra primero). –

0

Fluent Wait - El mejor enfoque, ya que es el más flexible y configurable sobre la marcha (tiene opción de ignorar excepciones, sondeando cada, tiempo de espera):

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

uso de este modo:

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

Wait explícita - Bueno, es lo mismo que FluentWait pero con pre-configurado pollingEvery y el tipo de Espera, por ejemplo, FluentWait<WebDriver> (más rápido de usar):

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

ImplicitWait - No es recomendable ya que se configura una vez por todas su sesión. Esto también se usa para cada elemento de búsqueda y solo espera presencia (no ExpectedConditions etc ...):

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