El selenium espera hasta que el documento esté listo

¿Alguien puede decirme cómo puedo hacer que el selenium espere hasta que la página se cargue por completo? Quiero algo genérico, sé que puedo configurar WebDriverWait y llamar algo así como ‘find’ para hacerlo esperar, pero no voy tan lejos. Solo necesito probar que la página se carga correctamente y pasar a la siguiente página para probar.

Encontré algo en .net pero no pude hacerlo funcionar en Java …

IWait wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00)); wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete")); 

¿Alguna idea de alguien?

Prueba este código:

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

El código anterior esperará hasta 10 segundos para cargar la página. Si la carga de la página excede el tiempo lanzará TimeoutException . Capturas la excepción y haces tus necesidades. No estoy seguro de si sale de la carga de la página después de la excepción lanzada. No probé este código todavía. ¿Quieres simplemente probarlo?

Esta es una espera implícita. Si configura esto una vez, tendrá el scope hasta que se destruya la instancia de Web Driver.

Para más información

La solución sugerida solo espera que DOM readyState señal complete . Pero Selenium de forma predeterminada intenta esperar esos (y un poco más) en la carga de la página a través de los driver.get() y element.click() . Ya están bloqueando, esperan que la página se cargue por completo y deberían funcionar bien.

El problema, obviamente, son los redireccionamientos a través de solicitudes de AJAX y la ejecución de scripts, los cuales no pueden ser capturados por Selenium, no espera a que terminen. Además, no puede atraparlos de manera confiable a través de readyState : espera un poco, lo que puede ser útil, pero se señalizará complete mucho antes de que se descargue todo el contenido de AJAX.

No existe una solución general que funcione en todos lados y para todos, por eso es difícil y todos usan algo un poco diferente.

La regla general es confiar en WebDriver para que haga su parte, luego use esperas implícitas, luego use esperas explícitas para los elementos que desea afirmar en la página, pero hay muchas más técnicas que se pueden hacer. Debe elegir uno (o una combinación de varios) que funcione mejor en su caso, en la página probada.

Vea mis dos respuestas sobre esto para más información:

  • Cómo puedo verificar si la página está cargada por completo o no en el controlador web
  • Selenium Webdriver: espere a que se cargue la página compleja con javascript

Esta es una versión de Java que funciona del ejemplo que usted dio:

 void waitForLoad(WebDriver driver) { new WebDriverWait(driver, 30).until((ExpectedCondition) wd -> ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete")); } 

Ejemplo para c #:

 public static void WaitForLoad(this IWebDriver driver, int timeoutSec = 15) { WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec )); wait.Until(wd => wd.ExecuteScript("return document.readyState") == "complete"); } 

Aquí está mi bash de una solución completamente genérica, en Python:

Primero, una función genérica de “espera” (use un WebDriverWait si lo desea, los encuentro feos):

 def wait_for(condition_function): start_time = time.time() while time.time() < start_time + 3: if condition_function(): return True else: time.sleep(0.1) raise Exception('Timeout waiting for {}'.format(condition_function.__name__)) 

A continuación, la solución se basa en el hecho de que el selenium registra un número de identificación (interno) para todos los elementos en una página, incluido el elemento nivel superior. Cuando una página se actualiza o se carga, obtiene un nuevo elemento html con una nueva ID.

Por lo tanto, supongamos que desea hacer clic en un enlace con el texto "mi enlace", por ejemplo:

 old_page = browser.find_element_by_tag_name('html') browser.find_element_by_link_text('my link').click() def page_has_loaded(): new_page = browser.find_element_by_tag_name('html') return new_page.id != old_page.id wait_for(page_has_loaded) 

Para más ayudante Pythonic, reutilizable y genérico, puedes crear un administrador de contexto:

 from contextlib import contextmanager @contextmanager def wait_for_page_load(browser): old_page = browser.find_element_by_tag_name('html') yield def page_has_loaded(): new_page = browser.find_element_by_tag_name('html') return new_page.id != old_page.id wait_for(page_has_loaded) 

Y luego puedes usarlo en prácticamente cualquier interacción de selenium:

 with wait_for_page_load(browser): browser.find_element_by_link_text('my link').click() 

¡Creo que es a prueba de balas! ¿Qué piensas?

Más información en una publicación de blog sobre esto aquí

Tuve un problema similar. Necesitaba esperar hasta que mi documento estuviera listo, pero también hasta que todas las llamadas Ajax hubieran terminado. La segunda condición demostró ser difícil de detectar. Al final revisé las llamadas activas de Ajax y funcionó.

Javascript:

 return (document.readyState == 'complete' && jQuery.active == 0) 

Método completo de C #:

 private void WaitUntilDocumentIsReady(TimeSpan timeout) { var javaScriptExecutor = WebDriver as IJavaScriptExecutor; var wait = new WebDriverWait(WebDriver, timeout); // Check if document is ready Func readyCondition = webDriver => javaScriptExecutor .ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)"); wait.Until(readyCondition); } 
 WebDriverWait wait = new WebDriverWait(dr, 30); wait.until(ExpectedConditions.jsReturnsValue("return document.readyState==\"complete\";")); 

Para C # NUnit, debe convertir WebDriver a JSExecuter y luego ejecutar el script para verificar si el estado de document.ready está completo o no. Verifique el código a continuación para referencia:

  public static void WaitForLoad(IWebDriver driver) { IJavaScriptExecutor js = (IJavaScriptExecutor)driver; int timeoutSec = 15; WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec)); wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete"); } 

Esto esperará hasta que se cumpla la condición o se agote el tiempo de espera.

Para la carga de la página inicial, he notado que “Maximizar” la ventana del navegador prácticamente espera hasta que se complete la carga de la página (incluidas las fonts)

Reemplazar:

 AppDriver.Navigate().GoToUrl(url); 

Con:

 public void OpenURL(IWebDriver AppDriver, string Url) { try { AppDriver.Navigate().GoToUrl(Url); AppDriver.Manage().Window.Maximize(); AppDriver.SwitchTo().ActiveElement(); } catch (Exception e) { Console.WriteLine("ERR: {0}; {1}", e.TargetSite, e.Message); throw; } } 

que uso:

 OpenURL(myDriver, myUrl); 

Esto cargará la página, esperará hasta que se complete, maximizará y se enfocará en ella. No sé por qué es así, pero funciona.

Si desea esperar la carga de la página después de hacer clic en Siguiente o cualquier otra navegación de la página desencadenar otro, entonces “Navegar ()”, la respuesta de Ben Dyer (en este hilo) hará el trabajo.

Eche un vistazo al tapiz web-framework. Puede descargar el código fuente allí.

La idea es señalar que la página está lista por el atributo html del cuerpo. Puede usar esta idea para ignorar casos de sue complicados.

     

Write you page here

Y luego crea la extensión de Selenium webdriver (de acuerdo con el marco tapiz)

 public static void WaitForPageToLoad(this IWebDriver driver, int timeout = 15000) { //wait a bit for the page to start loading Thread.Sleep(100); //// In a limited number of cases, a "page" is an container error page or raw HTML content // that does not include the body element and data-page-initialized element. In those cases, // there will never be page initialization in the Tapestry sense and we return immediately. if (!driver.ElementIsDisplayed("/html/body[@data-page-initialized]")) { return; } Stopwatch stopwatch = Stopwatch.StartNew(); int sleepTime = 20; while(true) { if (driver.ElementIsDisplayed("/html/body[@data-page-initialized='true']")) { return; } if (stopwatch.ElapsedMilliseconds > 30000) { throw new Exception("Page did not finish initializing after 30 seconds."); } Thread.Sleep(sleepTime); sleepTime *= 2; // geometric row of sleep time } } 

Use la extensión ElementIsDisplayed escrita por Alister Scott .

 public static bool ElementIsDisplayed(this IWebDriver driver, string xpath) { try { return driver.FindElement(By.XPath(xpath)).Displayed; } catch(NoSuchElementException) { return false; } } 

Y finalmente crear prueba:

 driver.Url = this.GetAbsoluteUrl("/Account/Login"); driver.WaitForPageToLoad(); 

La respuesta de Ben Dryer no se compiló en mi máquina ( "The method until(Predicate) is ambiguous for the type WebDriverWait" ).

Versión de trabajo Java 8:

 Predicate pageLoaded = wd -> ((JavascriptExecutor) wd).executeScript( "return document.readyState").equals("complete"); new FluentWait(driver).until(pageLoaded); 

Versión de Java 7:

 Predicate pageLoaded = new Predicate() { @Override public boolean apply(WebDriver input) { return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete"); } }; new FluentWait(driver).until(pageLoaded); 

La espera del evento document.ready no es la solución completa a este problema, porque este código aún está en condición de carrera: a veces este código se activa antes de que se procese el evento click, por lo que esto regresa directamente, ya que el navegador no se ha iniciado cargando la nueva página todavía

Después de buscar, encontré una publicación en Obay the testing cabra , que tiene una solución para este problema. El código c # para esa solución es algo como esto:

  IWebElement page = null; ... public void WaitForPageLoad() { if (page != null) { var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page)); } var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete")); page = driver.FindElement(By.TagName("html")); } 

`Dispare este método directamente después de que el controlador.navigate.gotourl, de modo que obtenga una referencia de la página tan pronto como sea posible. ¡Diviértete con eso!

Puedes escribir algo de lógica para manejar esto. He escrito un método que devolverá WebElement y este método se llamará tres veces o puede boost el tiempo y agregar una verificación nula para WebElement Aquí hay un ejemplo

 public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.get("https://www.crowdanalytix.com/#home"); WebElement webElement = getWebElement(driver, "homekkkkkkkkkkkk"); int i = 1; while (webElement == null && i < 4) { webElement = getWebElement(driver, "homessssssssssss"); System.out.println("calling"); i++; } System.out.println(webElement.getTagName()); System.out.println("End"); driver.close(); } public static WebElement getWebElement(WebDriver driver, String id) { WebElement myDynamicElement = null; try { myDynamicElement = (new WebDriverWait(driver, 10)) .until(ExpectedConditions.presenceOfElementLocated(By .id(id))); return myDynamicElement; } catch (TimeoutException ex) { return null; } } 

Ejecuté un código de JavaScript para verificar si el documento está listo. Me ahorró mucho tiempo depurando las pruebas de selenium para los sitios que tienen representación del lado del cliente.

 public static boolean waitUntilDOMIsReady(WebDriver driver) { def maxSeconds = DEFAULT_WAIT_SECONDS * 10 for (count in 1..maxSeconds) { Thread.sleep(100) def ready = isDOMReady(driver); if (ready) { break; } } 

}

 public static boolean isDOMReady(WebDriver driver){ return driver.executeScript("return document.readyState"); } 

Intenté este código y me funciona. Llamo a esta función cada vez que me muevo a otra página

 public static void waitForPageToBeReady() { JavascriptExecutor js = (JavascriptExecutor)driver; //This loop will rotate for 100 times to check If page Is ready after every 1 second. //You can replace your if you wants to Increase or decrease wait time. for (int i=0; i<400; i++) { try { Thread.sleep(1000); }catch (InterruptedException e) {} //To check page ready state. if (js.executeScript("return document.readyState").toString().equals("complete")) { break; } } } 

En Nodejs puedes obtenerlo a través de promesas …

Si escribe este código, puede estar seguro de que la página está completamente cargada cuando llegue al …

 driver.get('www.sidanmor.com').then(()=> { // here the page is fully loaded!!! // do your stuff... }).catch(console.log.bind(console)); 

Si escribe este código, navegará, y el selenium esperará 3 segundos …

 driver.get('www.sidanmor.com'); driver.sleep(3000); // you can't be sure that the page is fully loaded!!! // do your stuff... hope it will be OK... 

De la documentación de Selenium:

this.get (url) → Thenable

Progtwig un comando para navegar a la URL dada.

Devuelve una promesa que se resolverá cuando el documento haya terminado de cargarse .

Documentación de selenium (Nodejs)

 public boolean waitForElement(String zoneName, String element, int index, int timeout) { WebDriverWait wait = new WebDriverWait(appiumDriver, timeout/1000); wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(element))); return true; } 

Al igual que Rubanov escribió para C #, lo escribo para Java, y es:

  public void waitForPageLoaded() { ExpectedCondition expectation = new ExpectedCondition() { public Boolean apply(WebDriver driver) { return (((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete")&&((Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0"))); } }; try { Thread.sleep(100); WebDriverWait waitForLoad = new WebDriverWait(driver, 30); waitForLoad.until(expectation); } catch (Throwable error) { Assert.fail("Timeout waiting for Page Load Request to complete."); } } 

En Java le gustará a continuación:

  private static boolean isloadComplete(WebDriver driver) { return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded") || ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"); } 

normalmente cuando selenium abre una nueva página desde un clic o envía u obtiene métodos, esperará a contar que la página está cargada, pero el problema es cuando la página tiene una llamada xhr (ajax) que nunca esperará a que cargue xhr, por lo que creando un nuevo método para monitorear un xhr y esperar por ellos será lo bueno. (perdón por mi mal inglés: D)

 public boolean waitForJSandJQueryToLoad() { WebDriverWait wait = new WebDriverWait(webDriver, 30); // wait for jQuery to load ExpectedCondition jQueryLoad = new ExpectedCondition() { @Override public Boolean apply(WebDriver driver) { try { Long r = (Long)((JavascriptExecutor)driver).executeScript("return $.active"); return r == 0; } catch (Exception e) { LOG.info("no jquery present"); return true; } } }; // wait for Javascript to load ExpectedCondition jsLoad = new ExpectedCondition() { @Override public Boolean apply(WebDriver driver) { return ((JavascriptExecutor)driver).executeScript("return document.readyState") .toString().equals("complete"); } }; return wait.until(jQueryLoad) && wait.until(jsLoad); } 

if $ .active == 0 entonces no hay una llamada xhrs activa (que solo funciona con jQuery). para javascript ajax llame debe crear una variable en su proyecto y simularla.

El siguiente código probablemente debería funcionar:

 WebDriverWait wait = new WebDriverWait(driver, 10); wait.until(ExpectedConditions.presenceOfAllElementsLocated(By.xpath("//*"))); 
 public void waitForPageToLoad() { (new WebDriverWait(driver, DEFAULT_WAIT_TIME)).until(new ExpectedCondition() { public Boolean apply(WebDriver d) { return (((org.openqa.selenium.JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete")); } });//Here DEFAULT_WAIT_TIME is a integer correspond to wait time in seconds 

Aquí hay algo similar, en Ruby:

 wait = Selenium::WebDriver::Wait.new(:timeout => 10) wait.until { @driver.execute_script('return document.readyState').eql?('complete') } 

Puede hacer que el hilo duerma hasta que la página se vuelva a cargar. Esta no es la mejor solución, ya que necesita un cálculo de cuánto tarda la página en cargarse.

 driver.get(homeUrl); Thread.sleep(5000); driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(userName); driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(passWord); driver.findElement(By.xpath("Your_Xpath_here")).click(); 

¿Estás usando Angular? Si lo es, es posible que el controlador de la web no reconozca que las llamadas asíncronas hayan finalizado.

Recomiendo mirar a Paul Hammants ngWebDriver . El método waitForAnularRequestsToFinish () podría ser útil.