¿Prueba si el elemento está presente usando Selenium WebDriver?

163

¿Hay alguna forma de probar si un elemento está presente? Cualquier método findElement terminaría en una excepción, pero eso no es lo que quiero, porque puede ser que un elemento no esté presente y eso está bien, eso no es un fallo de la prueba, por lo que una excepción no puede ser la solución.

He encontrado esta publicación: Selenium c # Webdriver: Espere hasta que Element esté presente Pero esto es para C # y no soy muy bueno en eso. ¿Alguien puede traducir el código a Java? Lo siento muchachos, lo probé en Eclipse pero no lo consigo en el código Java.

Este es el código:

public static class WebDriverExtensions{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds){

        if (timeoutInSeconds > 0){
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }

        return driver.FindElement(by);
    }
}
ensayador
fuente
Tengo un par de métodos que funcionan de manera muy efectiva para verificar un objeto, pero depende de lo que quieras hacer con él. por ejemplo, ¿desea buscar el elemento hasta que exista, desea buscarlo hasta que ya no exista o simplemente intente encontrarlo?
CBRRacer
1
Java es muy similar a C # Creo que uno de los principales problemas con los que se encuentra aquí es en Java, es WebElement en lugar de IWebElement
CBRRacer
¿Conoces el método de espera implícito? Al configurar esto al comienzo de la prueba, nunca tendrá que verificar la existencia de un elemento, ya que utiliza el valor de espera implícito para sondear, sin embargo, si excede ese valor, arrojará una excepción
Bob Evans el
Aquí está mi publicación sobre WebDriverWait en Java: WebDriverWait
Si cualquiera de los casos está bien, esto puede ser problemático para el rendimiento de la prueba, ya que el tiempo de espera asociado para esperar un elemento que no espera que exista realmente se suma. He usado algunos trucos para evitar el tiempo de espera, pero aún no he encontrado una solución realmente limpia para esto.
mrfreester

Respuestas:

277

Usar en findElementslugar de findElement.

findElements devolverá una lista vacía si no se encuentran elementos coincidentes en lugar de una excepción.

Para verificar que un elemento está presente, puede intentar esto

Boolean isPresent = driver.findElements(By.yourLocator).size() > 0

Esto devolverá verdadero si se encuentra al menos un elemento y falso si no existe.

La documentación oficial recomienda este método:

findElement no debe usarse para buscar elementos no presentes, use findElements (By) y afirme una respuesta de longitud cero en su lugar.

el roso
fuente
32
Esto agregará mucho tiempo para ejecutar sus pruebas. No puedes usar esta técnica en todas partes.
Droogans
8
@Droogans: no agregaré tiempo a sus pruebas. La razón no es porque la espera implícita predeterminada sigue siendo 0. Si aumentó la espera implícita predeterminada, entonces estoy de acuerdo en que lo haría, pero no parece ser el caso aquí.
djangofan
1
Buena llamada djangofan! Utilicé con éxito esta estrategia cambiando la espera implícita del tiempo de espera del controlador a cero y luego volviéndola a su valor anterior.
esmeril
3
Esto dio una excepción NoSuchElementFound, lo cual es una pena, ya que esperaba usar esto para evitar detectar esa excepción en una instancia determinada.
1
Una forma mucho más fácil es usar: if (driver.getPageSource (). Contiene ("Un texto en la página")) {} Si la página contiene este texto, la condición será verdadera, o de lo contrario será falsa y puede codificar en consecuencia.
pradyot
56

¿Qué pasa con un método privado que simplemente busca el elemento y determina si está presente así?

private boolean existsElement(String id) {
    try {
        driver.findElement(By.id(id));
    } catch (NoSuchElementException e) {
        return false;
    }
    return true;
}

Esto sería bastante fácil y hace el trabajo.

Editar: incluso podría ir más allá y tomar un By elementLocatorparámetro, eliminando problemas si desea encontrar el elemento por otra cosa que no sea id.

Dennis
fuente
3
Sí, este es el camino a seguir. No entiendo por qué las personas ignoran de esta manera y cuentan elementos coincidentes, para ver si el resultado es 0.
Ralph Lavelle
45
Bueno, debo decir que usar Excepciones para regular el flujo del programa no es la mejor manera de hacerlo.
Dennis
2
¿Eh? Fue tu sugerencia! Es un buen camino si su prueba espera no encontrar el elemento. Como muestra, simplemente devuelva null y afirmar.isnull o isnotnull, que es una forma significativa de probar si existe una cosa.
Ralph Lavelle
2
En caso de que haya malinterpretado la pregunta "¿hay alguna forma de probar si un elemento está presente?" mal, me alegrará saber por qué su opinión difiere sobre si esta es una respuesta legítima o no.
Dennis
Es posible que desee reducir el tiempo de espera. En este momento, si el elemento no existe, debe esperar "30 segundos" antes de que la función devuelva falso
Jason Smiley
14

Descubrí que esto funciona para Java:

WebDriverWait waiter = new WebDriverWait(driver, 5000);
waiter.until( ExpectedConditions.presenceOfElementLocated(by) );
driver.FindElement(by);
Tango Ben
fuente
18
presenceOfElementLocatedlanzará una Excepción si el elemento no se encuentra en un intento particular. Para evitar esto, agregue una wait.ignoring(NoSuchElementException.class);declaración entre la primera y la segunda línea.
Steve Chambers
8
public static WebElement FindElement(WebDriver driver, By by, int timeoutInSeconds)
{
    WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds);
    wait.until( ExpectedConditions.presenceOfElementLocated(by) ); //throws a timeout exception if element not present after waiting <timeoutInSeconds> seconds
    return driver.findElement(by);
}
RedDeckWins
fuente
5

Tuve el mismo problema. Para mí, dependiendo del nivel de permiso de un usuario, algunos enlaces, botones y otros elementos no se mostrarán en la página. Parte de mi suite estaba probando que faltan los elementos que DEBEN faltar. Pasé horas tratando de resolver esto. Finalmente encontré la solución perfecta.

Lo que esto hace es decirle al navegador que busque cualquiera y todos los elementos basados ​​en especificados. Si resulta 0, eso significa que no se encontraron elementos basados ​​en la especificación. Luego hago que el código ejecute una instrucción if para informarme que no se encontró.

Esto está dentro C#, por lo que tendrían que hacerse traducciones Java. Pero no debería ser demasiado difícil.

public void verifyPermission(string link)
{
    IList<IWebElement> adminPermissions = driver.FindElements(By.CssSelector(link));
    if (adminPermissions.Count == 0)
    {
        Console.WriteLine("User's permission properly hidden");
    }
}

También hay otro camino que puede tomar dependiendo de lo que necesita para su prueba.

El siguiente fragmento está verificando si existe un elemento muy específico en la página. Dependiendo de la existencia del elemento, hago que la prueba ejecute un if if else.

Si el elemento existe y se muestra en la página, me lo ha console.writehecho saber y seguir adelante. Si el elemento en cuestión existe, no puedo ejecutar la prueba que necesitaba, que es el principal razonamiento detrás de la necesidad de configurar esto.

Si el elemento no existe y no se muestra en la página. Tengo el else en if if ejecutar la prueba.

IList<IWebElement> deviceNotFound = driver.FindElements(By.CssSelector("CSS LINK GOES HERE"));
//if the element specified above results in more than 0 elements and is displayed on page execute the following, otherwise execute whats in the else statement
if (deviceNotFound.Count > 0 && deviceNotFound[0].Displayed){
    //script to execute if element is found
} else {
    //Test script goes here.
}

Sé que llego un poco tarde en la respuesta al OP. ¡Ojalá esto ayude a alguien!

Tasha
fuente
5

Pruebe esto: llame a este método y pase 3 argumentos:

  1. WebDriver variable. // suponiendo driver_variable como driver.
  2. El elemento que vas a verificar. Debe proporcionar desde por método. // ex: By.id ("id")
  3. Límite de tiempo en segundos.

Ejemplo: waitForElementPresent (driver, By.id ("id"), 10);

public static WebElement waitForElementPresent(WebDriver driver, final By by, int timeOutInSeconds) {

        WebElement element; 

        try{
            driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait() 

            WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds); 
            element = wait.until(ExpectedConditions.presenceOfElementLocated(by));

            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //reset implicitlyWait
            return element; //return the element
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return null; 
    }
Prabu Ananthakrishnan
fuente
3

Puede hacer que el código se ejecute más rápido acortando el tiempo de espera de selenio antes de su declaración de captura de prueba.

Utilizo el siguiente código para verificar si un elemento está presente.

protected boolean isElementPresent(By selector) {
    selenium.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
    logger.debug("Is element present"+selector);
    boolean returnVal = true;
    try{
        selenium.findElement(selector);
    } catch (NoSuchElementException e){
        returnVal = false;
    } finally {
        selenium.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
    }
    return returnVal;
}
Sin sentido esotérico
fuente
Esto es lo que uso en mi código. Dejo el tiempo de espera de Selenium predeterminado y luego lo uso.
Nicholas DiPiazza
2
Desde que escribí esta respuesta, aprendí que usar ExpectedConditions se considera una mejor forma, pero usar una declaración try catch sigue siendo útil cuando se intenta determinar si un elemento no está presente.
EsotericNonsense
Estoy atascado en una versión anterior de selenio porque tengo que probar IE8. pero lo intentaré cuando pueda actualizar
Nicholas DiPiazza
Cada vez que su método establecerá el tiempo de espera implícito, pero lógicamente deberíamos establecer la espera implícita solo una vez después de inicializar el objeto del controlador y el tiempo de espera se establece en la sesión del controlador.
Shekhar Swami
3

Escriba la siguiente función / método usando Java:

protected boolean isElementPresent(By by){
        try{
            driver.findElement(by);
            return true;
        }
        catch(NoSuchElementException e){
            return false;
        }
    }

Llame al método con el parámetro apropiado durante la aserción.

Ripon Al Wasim
fuente
2

si está usando rspec-Webdriver en ruby, puede usar este script asumiendo que un elemento realmente no debería estar presente y que es una prueba aprobada.

Primero, escriba este método primero desde su archivo RB de clase

class Test
 def element_present?
    begin
        browser.find_element(:name, "this_element_id".displayed?
        rescue Selenium::WebDriver::Error::NoSuchElementError
            puts "this element should not be present"
        end
 end

Luego, en su archivo de especificaciones, llame a ese método.

  before(:all) do    
    @Test= Test.new(@browser)
  end

 @Test.element_present?.should == nil

Si su elemento NO está presente, su especificación pasará, pero si el elemento está presente, arrojará un error, la prueba falló.

grayshell
fuente
2

Esto funciona para mi:

 if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
    //THEN CLICK ON THE SUBMIT BUTTON
}else{
    //DO SOMETHING ELSE AS SUBMIT BUTTON IS NOT THERE
}
Bytes Amstel
fuente
el mismo problema existe aquí: ¿qué pasa si el elemento "// * [@ id = 'submit']" no existe? a continuación, una excepción será lanzada, por lo tanto, si la condición no se evalúa
MrBCut
1
public boolean isElementDisplayed() {
        return !driver.findElements(By.xpath("...")).isEmpty();
    }
Bogdan Shulga
fuente
1

Personalmente, siempre busco una mezcla de las respuestas anteriores y creo un método de utilidad estática reutilizable que utiliza la size() > 0sugerencia:

public Class Utility {
   ...
   public static boolean isElementExist(WebDriver driver, By by) {
      return driver.findElements(by).size() > 0;
   ...
}

Esto es ordenado, reutilizable, mantenible ... todas esas cosas buenas ;-)

Charlie Seligman
fuente
0

Para encontrar un elemento en particular presente o no, tenemos que usar el método findElements () en lugar de findElement () ..

int i=driver.findElements(By.xpath(".......")).size();
if(i=0)
System.out.println("Element is not present");
else
System.out.println("Element is present");

esto funcionó para mí ... sugiérame si estoy equivocado ...

Subbarao Gaddam
fuente
0

Esto debería hacerlo:

try {
    driver.findElement(By.id(id));
} catch (NoSuchElementException e) {
    //do what you need here if you were expecting
    //the element wouldn't exist
}
Scott Helme
fuente
0

Dando mi fragmento de código. Por lo tanto, el siguiente método verifica si existe un botón aleatorio de elemento web ' Crear nueva aplicación ' en una página o no. Tenga en cuenta que he usado el período de espera como 0 segundos.

public boolean isCreateNewApplicationButtonVisible(){
    WebDriverWait zeroWait = new WebDriverWait(driver, 0);
    ExpectedCondition<WebElement> c = ExpectedConditions.presenceOfElementLocated(By.xpath("//input[@value='Create New Application']"));
    try {
        zeroWait.until(c);
        logger.debug("Create New Application button is visible");
        return true;
    } catch (TimeoutException e) {
        logger.debug("Create New Application button is not visible");
        return false;
    }
}
Rambo7
fuente
0

Usaría algo como (con Scala [el código en el antiguo "bueno" Java 8 puede ser similar a esto):

object SeleniumFacade {

  def getElement(bySelector: By, maybeParent: Option[WebElement] = None, withIndex: Int = 0)(implicit driver: RemoteWebDriver): Option[WebElement] = {
    val elements = maybeParent match {
      case Some(parent) => parent.findElements(bySelector).asScala
      case None => driver.findElements(bySelector).asScala
    }
    if (elements.nonEmpty) {
      Try { Some(elements(withIndex)) } getOrElse None
    } else None
  }
  ...
}

por lo que entonces,

val maybeHeaderLink = SeleniumFacade getElement(By.xpath(".//a"), Some(someParentElement))
ses
fuente
0

La forma más simple que encontré en Java es:

List<WebElement> linkSearch=  driver.findElements(By.id("linkTag"));
int checkLink=linkSearch.size();
if(checkLink!=0){  //do something you want}
back2back
fuente
0

Puedes probar la espera implícita:

WebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
driver.Url = "http://somedomain/url_that_delays_loading";
IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));

O puede intentar esperar explícitamente uno:

IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
    {
        return d.FindElement(By.Id("someDynamicElement"));
    });

Explícito verificará si el elemento está presente antes de alguna acción. La espera implícita se puede llamar en todos los lugares del código. Por ejemplo después de algunas acciones AJAX.

Más puede encontrar en la página de SeleniumHQ

streser
fuente