¿Cómo puedo pedirle al Selenium-WebDriver que espere unos segundos en Java?


100

Estoy trabajando en un Java Selenium-WebDriver. yo añadí

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

y

WebElement textbox = driver.findElement(By.id("textbox"));

porque mis aplicaciones tardan unos segundos en cargar la interfaz de usuario. Así que configuré 2 segundos implícitamente. pero no pude ubicar el cuadro de texto del elemento

Luego agrego Thread.sleep(2000);

Ahora funciona bien. ¿Cuál es mejor forma?


Respuestas:


123

Bueno, hay dos tipos de espera: espera explícita e implícita. La idea de la espera explícita es

WebDriverWait.until(condition-that-finds-the-element);

El concepto de espera implícita es

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

Puede ver la diferencia en los detalles aquí .

En tales situaciones, preferiría usar una espera explícita ( fluentWaiten particular):

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    });

    return  foo;
};

fluentWaitLa función devuelve su elemento web encontrado. De la documentación en adelante fluentWait: Una implementación de la interfaz de espera que puede tener su tiempo de espera y el intervalo de sondeo configurados sobre la marcha. Cada instancia de FluentWait define la cantidad máxima de tiempo de espera para una condición, así como la frecuencia con la que se verifica. Además, el usuario puede configurar la espera para ignorar tipos específicos de excepciones mientras espera, como NoSuchElementExceptions al buscar un elemento en la página. Detalles que puede obtener aquí

El uso de fluentWaiten su caso será el siguiente:

WebElement textbox = fluentWait(By.id("textbox"));

En mi humilde opinión, este enfoque es mejor, ya que no sabe exactamente cuánto tiempo esperar y en el intervalo de sondeo puede establecer un valor de tiempo arbitrario mediante el cual se verificará la presencia del elemento. Saludos.


3
Eso es import com.google.common.base.Function;, noimport java.util.function.Function;
he verificado el

haventchecked, en realidad usando intelij IDEA para el desarrollo, está ayudando con las importaciones automáticas (cuando se trabaja en un proyecto basado en maven)
eugene.polschikov

1
Solo estaba diciendo eso para otros que pueden preguntarse cuál Functionse estaba utilizando. No fue obvio para mí al principio. Gracias por la respuesta.
comprobado el

1
O usted podría utilizar una expresión lambda: driver -> driver.findElement(locator). Al usar esto, no necesitará una declaración de importación en absoluto.
Thibstars

2
Ahora es: .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))en lugar de: .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro

16

Este hilo es un poco más antiguo, pero pensé en publicar lo que hago actualmente (trabajo en progreso).

Aunque todavía estoy en situaciones en las que el sistema está bajo una gran carga y cuando hago clic en un botón de envío (por ejemplo, login.jsp), las tres condiciones (ver más abajo) regresan, truepero la página siguiente (por ejemplo, home.jsp) no aparece. t comenzó a cargar todavía.

Este es un método de espera genérico que toma una lista de condiciones esperadas.

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

He definido varias condiciones esperadas reutilizables (tres están a continuación). En este ejemplo, las tres condiciones esperadas incluyen document.readyState = 'complete', sin "wait_dialog" presente y sin 'spinners' (elementos que indican que se están solicitando datos asíncronos).

Solo el primero se puede aplicar genéricamente a todas las páginas web.

/**
 * Returns 'true' if the value of the 'window.document.readyState' via
 * JavaScript is 'complete'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns 'true' if there is no 'wait_dialog' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id("F"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the 'spinner' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className("spinner"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

Dependiendo de la página, puedo usar uno o todos:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

También hay condiciones esperadas predefinidas en la siguiente clase: org.openqa.selenium.support.ui.ExpectedConditions


1
¡Gran respuesta! Nunca he visto a alguien pasar un elemento ExpectedCondition a través del constructor de métodos. Que buena idea. +1
djangofan

Jeff Vincent, ¿podría decirme si esto funcionará para que la página espere 5 minutos? Si es así, sugiera qué parámetro de lugar debe enviar.
Khanam

Esta es una respuesta genial. Tengo una función similar como esta, sin embargo, tengo que llamarla en cada función para que mi script espere hasta que se cargue la página (ruleta). ¿Hay alguna manera de que pueda conectar esta función waitForSpinner silenciosamente en ImplicitWait para que no tenga que llamarla cada vez en mi función? Como definir la función, engancharlo al conductor una vez y boom.
Bhuvanesh Mani

13

Si usa webdriverJs (node.js),

driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
    driver.sleep(5000);
});

El código anterior hace que el navegador espere 5 segundos después de hacer clic en el botón.


18
¿Por qué publicaría esto cuando la pregunta es específicamente sobre Java, no sobre nodo / JavaScript? Está tan fuera de tema como responder cómo hacerlo en ruby.
Thor84no

1
La recomendación de usar el sueño definitivamente no es una buena solución
Kiril S.

@ Thor84no Principalmente porque algunos de nosotros que buscamos la solución web encontramos esta respuesta
Kitanga Nday

10

Usar Thread.sleep(2000);es una espera incondicional. Si su prueba se carga más rápido, aún tendrá que esperar. Entonces, en principio, usar implicitlyWaites la mejor solución.

Sin embargo, no veo por qué implicitlyWaitno funciona en su caso. ¿Midió si en findElementrealidad tarda dos segundos antes de lanzar una excepción? Si es así, ¿puede intentar usar la espera condicional de WebDriver como se describe en esta respuesta?


3

Me gusta usar condiciones personalizadas. Aquí hay algo de código en Python:

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id("textbox")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

Siempre que necesite esperar, puede hacerlo explícitamente verificando la existencia de un determinado elemento (dicho elemento puede variar de una página a otra). find_elements_by_idlista de devoluciones: vacía o no, solo tiene que verificar.


2

el clic parece estar bloqueando? - aquí hay otra forma de esperar si está usando WebDriverJS:

driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

El código anterior espera después de hacer clic en el botón para que se cargue la página siguiente y luego toma la fuente de la página siguiente.


1
¿Qué hace que el código espere a que se cargue la página siguiente? ¿Es solo que la primera llamada en la devolución de llamada es getPageSource?
Isócrono

1

Implícitamente wait y Thread.sleep Ambos se usan solo para sincronización ... pero la diferencia es que podemos usar Implícitamente esperar para todo el programa, pero Thread.sleep funcionará solo para ese código único ... Aquí mi sugerencia es usar Implícitamente esperar una vez en el programa cuando cada vez que su página web se actualice significa que use Thread.sleep en ese momento ... será mucho mejor :)

Aquí está mi código:

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get("https://www.flipkart.com");
    WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}

0

A veces, la espera implícita parece anularse y el tiempo de espera se acorta. [@ eugene.polschikov] tenía buena documentación sobre los porqués. En mis pruebas y codificación con Selenium 2, descubrí que las esperas implícitas son buenas, pero ocasionalmente tienes que esperar explícitamente.

Es mejor evitar llamar directamente a un hilo para dormir, pero a veces no hay una buena forma de evitarlo. Sin embargo, hay otras opciones de espera proporcionadas por Selenium que ayudan. waitForPageToLoad y waitForFrameToLoad han demostrado ser especialmente útiles.


0

Espera implícita: durante la espera implícita si el controlador web no puede encontrarlo inmediatamente debido a su disponibilidad, el controlador web esperará el tiempo mencionado y no intentará encontrar el elemento nuevamente durante el período de tiempo especificado. Una vez que finaliza el tiempo especificado, intentará buscar el elemento una vez más la última vez antes de lanzar la excepción. La configuración predeterminada es cero. Una vez que establecemos una hora, el controlador web espera el período de la instancia del objeto WebDriver.

Espera explícita: puede haber una instancia en la que un elemento en particular tarda más de un minuto en cargarse. En ese caso, definitivamente no le gusta establecer un tiempo enorme para la espera implícita, ya que si lo hace, su navegador esperará el mismo tiempo para cada elemento. Para evitar esa situación, simplemente puede dedicar un tiempo separado solo al elemento requerido. Al seguir esto, el tiempo de espera implícito de su navegador sería corto para cada elemento y sería grande para un elemento específico.


0

A veces, la espera implícita falla, diciendo que un elemento existe pero en realidad no es así.

La solución es evitar el uso de driver.findElement y reemplazarlo con un método personalizado que usa una espera explícita implícitamente. Por ejemplo:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

Hay razones adicionales para evitar la espera implícita que no sean fallas esporádicas y ocasionales (consulte este enlace ).

Puede utilizar este método de "elemento" de la misma forma que driver.findElement. Por ejemplo:

    driver.get("http://yoursite.html");
    element(By.cssSelector("h1.logo")).click();

Si realmente desea esperar unos segundos para la resolución de problemas o alguna otra ocasión poco común, puede crear un método de pausa similar al que ofrece el IDE de selenio:

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

0

Respuesta : espere unos segundos antes de que la visibilidad del elemento con Selenium WebDriver siga los métodos a continuación.

implicitlyWait () : la instancia de WebDriver espera hasta que se cargue la página completa. Puede utilizar de 30 a 60 segundos para esperar la carga de la página completa.

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

ExplicitlyWait WebDriverWait () : la instancia de WebDriver espera hasta que se cargue la página completa.

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id("Year")).sendKeys(allKeys);

Nota : utilice ExplicitlyWait WebDriverWait () para manejar cualquier WebElement en particular.



-1

Prefiero que el siguiente código espere 2 segundos.

for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
   Thread.sleep(1000);
}

-1
Thread.sleep(1000);

es lo peor: siendo una espera estática, hará que el script de prueba sea más lento.

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

esta es una espera dinámica

  • es válido hasta la existencia del controlador web o tiene un alcance hasta la vida útil del controlador
  • también podemos esperar implícitamente.

Finalmente, lo que sugiero es

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

con algunas condiciones predefinidas:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • También es una espera dinámica
  • en esto la espera será solo en segundos
  • tenemos que usar la espera explícita para un elemento web en particular en el que queremos usar.

-4
Thread.Sleep(5000);

Esto me ayudó, pero la excepción InterruptedException debe solucionarse. Así que mejor rodearlo con try and catch:

try {
    Thread.Sleep(5000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

O

Agregar declaración de lanzamientos:

public class myClass {
    public static void main(String[] args) throws InterruptedException
    { ... }

Preferiría el segundo ya que luego se puede usar sleep()tantas veces como se quiera y evitar la repetición tryy el catchbloqueo cada vez que sleep()se haya usado.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.