O selenium espera até que o documento esteja pronto

Alguém pode me deixar como posso fazer o selenium esperar até o momento em que a página carrega completamente? Eu quero algo genérico, eu sei que posso configurar WebDriverWait e chamar algo como ‘encontrar’ para fazer isso esperar, mas eu não vou tão longe. Eu só preciso testar se a página é carregada com sucesso e passar para a próxima página para testar.

Eu encontrei algo em .net mas não consegui fazer funcionar em 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")); 

Qualquer pensamento alguém?

Experimente este código:

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

O código acima irá aguardar até 10 segundos para o carregamento da página. Se o carregamento da página exceder o tempo, o TimeoutException será lançado. Você pega a exceção e faz suas necessidades. Não tenho certeza se o carregamento da página é encerrado após a exceção ser lançada. Eu não tentei este código ainda. Quer apenas tentar.

Esta é uma espera implícita. Se você definir isso uma vez, ele terá o escopo até que a instância do Driver da Web seja destruída.

Para mais informações.

Sua solução sugerida aguarda apenas que o DOM readyState sinalize como complete . Mas o Selenium, por padrão, tenta esperar por esses (e um pouco mais) nos carregamentos de página através dos driver.get() e element.click() . Eles já estão bloqueando, eles esperam que a página carregue totalmente e eles devem estar funcionando ok.

O problema, obviamente, são redirecionamentos via requisições AJAX e execução de scripts – aqueles que não podem ser capturados pelo Selenium, não esperam que eles sejam concluídos. Além disso, você não pode capturá-los de forma confiável via readyState – ele aguarda um pouco, o que pode ser útil, mas será complete longo antes que todo o conteúdo do AJAX seja baixado.

Não há uma solução geral que funcione em todos os lugares e para todos, é por isso que é difícil e todos usam algo um pouco diferente.

A regra geral é confiar no WebDriver para fazer sua parte, usar esperas implícitas e usar esperas explícitas para elementos que você deseja afirmar na página, mas há muito mais técnicas que podem ser feitas. Você deve escolher um (ou uma combinação de vários deles) que funcione melhor no seu caso, na sua página testada.

Veja minhas duas respostas sobre isso para mais informações:

  • Como posso verificar se a página está carregada completamente ou não no driver da web
  • Selenium Webdriver: Aguarde a página complexa com o JavaScript para carregar

Esta é uma versão Java funcional do exemplo que você deu:

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

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

Aqui está minha tentativa de uma solução completamente genérica, em Python:

Primeiro, uma function genérica de “espera” (use um WebDriverWait se você quiser, eu acho feio):

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

Em seguida, a solução se baseia no fato de que o selenium registra um número de identificação (interno) para todos os elementos em uma página, incluindo o elemento de nível superior . Quando uma página é atualizada ou carregada, ela recebe um novo elemento html com um novo ID.

Então, supondo que você queira clicar em um link com o texto "meu link", por exemplo:

 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 mais ajudante genérico, reutilizável e Python, você pode criar um gerenciador 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) 

E então você pode usá-lo em praticamente qualquer interação de selenium:

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

Eu acho que isso é à prova de balas! O que você acha?

Mais informações em um post sobre isso aqui

Eu tive um problema parecido. Eu precisava esperar até que meu documento estivesse pronto, mas também até que todas as chamadas do Ajax terminassem. A segunda condição provou ser difícil de detectar. No final, verifiquei as chamadas ativas do Ajax e funcionou.

Javascript:

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

Método C # completo:

 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, você precisa converter o WebDriver em JSExecuter e, em seguida, executar o script para verificar se o estado document.ready está completo ou não. Confira abaixo o código para referência:

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

Isso esperará até que a condição seja satisfeita ou o tempo limite.

Para o carregamento de página inicial, observei que “Maximizar” a janela do navegador praticamente aguarda até que o carregamento da página seja concluído (incluindo origens)

Substituir:

 AppDriver.Navigate().GoToUrl(url); 

Com:

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

do que usar:

 OpenURL(myDriver, myUrl); 

Isso carregará a página, aguardará até que seja concluída, maximizará e focalizará nela. Eu não sei porque é assim, mas funciona.

Se você quiser esperar pelo carregamento da página depois de clicar no próximo ou em qualquer outro acionador de navegação de página diferente de “Navigate ()”, a resposta de Ben Dyer (neste thread) fará o trabalho.

Dê uma olhada no framework web de tapeçaria . Você pode baixar o código-fonte lá.

A ideia é sinalizar que a página está pronta pelo atributo html do corpo. Você pode usar essa ideia para ignorar casos de processos complicados.

     

Write you page here

E, em seguida, criar extensão de webdriver Selenium (de acordo com o quadro de tapeçaria)

 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 extension ElementIsDisplayed escrito por Alister Scott .

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

E finalmente crie teste:

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

A resposta de Ben Dryer não compilou na minha máquina ( "The method until(Predicate) is ambiguous for the type WebDriverWait" ).

Trabalhando a versão 8 do Java:

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

Versão do 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); 

A espera pelo evento document.ready não é a correção completa para esse problema, porque esse código ainda está em uma condição de corrida: Às vezes, esse código é triggersdo antes que o evento click seja processado, o que retorna diretamente, pois o navegador não foi iniciado carregando a nova página ainda.

Depois de algumas pesquisas, encontrei um post no Obay, a cabra de testes , que tem uma solução para esse problema. O código c # para essa solução é algo assim:

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

`Eu disparo este método diretamente após o driver.navigate.gotourl, para que ele obtenha uma referência da página o mais rápido possível. Divirta-se com isso!

Você pode escrever alguma lógica para lidar com isso. Eu tenho escrever um método que irá retornar o WebElement e este método será chamado três vezes ou você pode aumentar o tempo e adicionar uma verificação nula para WebElement Aqui está um exemplo

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

Eu executei um código javascript para verificar se o documento está pronto. Economizei muito tempo na debugging de testes de selenium para sites com renderização no lado do 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"); } 

Eu tentei esse código e funciona para mim. Eu chamo essa function toda vez que eu passo para outra 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; } } } 

No Nodejs você pode obter através de promises …

Se você escrever este código, você pode ter certeza que a página está totalmente carregada quando você chegar ao …

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

Se você escrever este código, você navegará e o selenium aguardará 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... 

Da documentação do Selenium:

this.get (url) → Thenable

Programa um comando para navegar para o URL fornecido.

Retorna uma promise que será resolvida quando o documento terminar de carregar .

Documentação de Selênio (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; } 

Como Rubanov escreveu para C #, eu escrevo para Java, e é:

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

Em Java vai gostar abaixo: –

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

normalmente quando o selenium abre uma nova página a partir de um clique ou submete ou obtém methods, ele irá aguardar que a página seja carregada mas o problema é quando a página tiver uma chamada xhr (ajax) ele nunca esperará o xhr ser carregado, então criar um novo método para monitorar um xhr e esperar por ele será bom. (desculpe pelo meu mau 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); } 

se $ .active == 0, então a chamada não é ativa xhrs (que funcionam apenas com jQuery). para javascript ajax call você precisa criar uma variável em seu projeto e simulá-la.

O código a seguir provavelmente deve 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 

Aqui está algo parecido, em Ruby:

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

Você pode fazer com que o fio durma até que a página seja recarregada. Esta não é a melhor solução, porque você precisa ter uma estimativa de quanto tempo a página demora para carregar.

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

Você está usando Angular? Se você é, é possível que o webdriver não reconheça que as chamadas assíncronas terminaram.

Eu recomendo olhar para Paul Hammants ngWebDriver . O método waitForAngularRequestsToFinish () pode ser útil.