2012-10-05 23 views
5

Si marca los elementos ausentes con el siguiente código:Selenium 2 - ¿Cómo comprobar si el elemento no está presente mientras espera implícitamente?

// ... 
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); 
try { 
    driver.findElement(By.cssSelector("td.name")); 
} catch (NoSuchElementException e) { 

    // here you go, element not found 

} 

puede obtener un resultado correcto, pero el tiempo de funcionamiento es siempre 30 segundos, debido a findElement método de bloqueo en la espera implícita.

¿Hay alguna manera de evitar este comportamiento, manteniendo la espera implícita en su lugar?

<EDIT> pruebas van a ser generados a través de Selenio IDE por los no desarrolladores, por lo que necesitan una solución que mantiene su trabajo tan simple como sea posible (que es mantener espera implícita!). </EDIT>

Gracias,

Marco

+0

¿No se puede hacer un método central, que establece la espera implícita en algo pequeño, luego lo restablece a 30 segundos? – Arran

+0

Me sentiría tentado a dejar caer las implicidades por completo, aunque estoy usando una plantilla para convertir casos de prueba escritos con Selenium IDE y esperaba mantener los cambios en el código al mínimo. –

Respuesta

2

Usted podría ser capaz de hacerlo con selectores XPath. Encuentre el elemento justo antes de que usted sepa que debería estar allí, luego use "following-sibling" para obtener el siguiente elemento. Algo como:

//td.previous/following-sibling::td 

Luego verifique que no haya devuelto el nombre. Por supuesto, eso solo funcionaría si hay otro elemento "td".

Personalmente, me sentiría tentado a soltar las esperas implícitas y solo usar las esperas cuando sean necesarias.

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

+1 para la solución inteligente. Desafortunadamente ... ver edición –

2

En lugar de configurar tiempos de espera, utilizo fluentWait que se introdujeron en 2.25.

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

Si se va a convertir sus métodos para algo como esto, usted será capaz de eliminar su driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); lo que le permite 'No' encontrar un elemento al instante.

Espero que esto ayude!

+0

Esa es la forma en que normalmente iría, gracias. Por desgracia ... ver edición. –

3

Los métodos anteriores esperan la cantidad de tiempo proporcionada incluso si el elemento ya no está presente. Escribí mis propios métodos para esperar hasta que el elemento esté visible y no presente. Ellos trabajan para mi Aquí están:

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

Se necesita una función como esta, que utiliza findElements, no 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; 
     } 
    }; 
} 

A continuación, puede configurar un objeto FluentWait como se describe por Falkenfighter y:

fluentWait.until(elementCountIs(By.cssSelector("td.name"), 0); 
+0

Lo siento, ahora me he dado cuenta de que esto es incorrecto. Las esperas implícitas se aplican tanto a findElements como findElement, que es muy molesto. –

0

Tendrá que actualizar temporalmente el ImplicitWait y reiniciarlo cuando haya terminado.

Esta es la forma en que hemos manejado esta situación: guarde el valor predeterminado actual, actualice el ImplicitWait temporalmente y luego vuelva a cambiar al valor predeterminado más adelante.
Esta sugerencia se basa fuera de Mozilla, que es la forma en que manejan esta situación en la que usted está esperando algo que no estar presentes: 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

No, no se puede. implicit El tiempo de espera tendrá prioridad sobre las esperas explícitas. Si su tiempo implicit es 30s, cualquier hallazgo que ejecute tendrá al menos 30 segundos en caso de que el elemento no esté presente. Lo que podría hacer es manipular el tiempo de espera de implicit en su marco, pero no estoy seguro de cómo funciona con el IDE, nunca he trabajado con él.

Creé un método personalizado que devuelve boolean con el resultado. La entrada es cualquier Por localizador compatible con WebDriver (CSS, xpath, etc.). O bien, puede modificarlo como lo desee.

Ayudó a hacer mi código más limpio y más rápido. Espero que ayude a otras personas también.

El valor predeterminado pooling es de 500 Millis, pero se puede cambiar en el objeto 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; 
    }; 
Cuestiones relacionadas