Como você faz o Selenium 2.0 aguardar o carregamento da página?
Como você faz o Selenium 2.0 aguardar o carregamento da página?
Respostas:
Você também pode verificar o carregamento de página usando o seguinte código
IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
Use a classe WebDriverWait
Veja também aqui
Você pode esperar mostrar algum elemento. algo como em C #:
WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));
_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement"));
Se você definir a espera implícita do driver e chamar o findElement
método em um elemento que você espera estar na página carregada, o WebDriver pesquisará esse elemento até encontrar o elemento ou atingir o valor do tempo limite.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
fonte: espera implícita
Em geral, com o Selenium 2.0, o driver da web deve retornar o controle apenas ao código de chamada depois de determinar que a página foi carregada. Caso contrário, você pode ligar waitforelemement
, que executa o ciclo de chamadas findelement
até que seja encontrado ou expire (o tempo limite pode ser definido).
If click() causes a new page to be loaded via an event or is done by sending a native event (which is a common case on Firefox, IE on Windows) then the method will not wait for it to be loaded and the caller should verify that a new page has been loaded.
JavascriptExecutor
, aguardando document.readyState estar "completo". Por causa da ida e volta do selênio ao navegador, acho que as condições da corrida são atenuadas, e isso "sempre" funciona para mim. Após "click ()", quando espero que uma página seja carregada, espero explicitamente (usando o WebDriverWait) pelo readystate. ]
Implementação Ruby:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
Você pode remover a System.out
linha. É adicionado para fins de depuração.
WebDriver driver_;
public void waitForPageLoad() {
Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
System.out.println("Current Window State : "
+ String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
return String
.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
.equals("complete");
}
});
}
Todas essas soluções são válidas para casos específicos, mas elas sofrem de pelo menos um dos dois possíveis problemas:
Eles não são genéricos o suficiente - eles querem que você saiba, antecipadamente, que alguma condição específica será verdadeira para a página que você está acessando (por exemplo, algum elemento será exibido)
Eles estão abertos a uma condição de corrida em que você usa um elemento que está realmente presente na página antiga e na nova página.
Aqui está minha tentativa de uma solução genérica que evita esse problema (em Python):
Primeiro, uma função genérica de "espera" (use um WebDriverWait, se quiser, acho-os feios):
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 selênio registra um número de identificação (interno) para todos os elementos em uma página, incluindo o nível superior <html>
elemento de . Quando uma página é atualizada ou carregada, ela obtém 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 um auxiliar genérico Python, reutilizável e reutilizável, 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 selênio:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Eu acho que é à prova de balas! O que você acha?
Mais informações em um post sobre isso aqui
Você também pode usar a classe: ExpectedConditions
para aguardar explicitamente a exibição de um elemento na página da web antes de executar qualquer ação.
Você pode usar a ExpectedConditions
classe para determinar se um elemento está visível:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
Veja ExpectedConditions class Javadoc
a lista de todas as condições que você pode verificar.
A resposta de Imran foi reformulada para o Java 7:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState"
).equals("complete");
}
});
Essa parece ser uma limitação séria do WebDriver. Obviamente, esperar por um elemento não implica que a página esteja sendo carregada, em particular, o DOM pode ser totalmente construído (estado onready) no qual o JS ainda está em execução e o CSS e as imagens ainda estão sendo carregados.
Acredito que a solução mais simples é definir uma variável JS no evento onload depois que tudo for inicializado e verificar e aguardar essa variável JS no Selenium.
Se você desejar aguardar o carregamento de um elemento específico, poderá usar o isDisplayed()
método em RenderedWebElement
:
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
(Exemplo do Guia de introdução de 5 minutos )
RenderedWebElement
na API. No entanto, o isDisplayed()
método agora está disponível diretamente no WebElement
.
Aguarde explicitamente ou espera condicional nessa espera até receber essa condição.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Isso aguardará cada elemento da web por 60 segundos.
Use aguardar implicitamente a espera de todos os elementos da página até o momento especificado.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Isso aguardará cada elemento da web por 60 segundos.
Use aguardar implicitamente a espera de todos os elementos da página até o tempo determinado.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
aguarde cada elemento da página por 30 segundos.
Outra espera é a espera explicitamente ou a espera condicional nessa espera até a condição especificada.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Em id, forneça o ID do elemento estático que é exibido de forma diferente na página, assim que a página for carregada.
Estou surpreso que os predicados não tenham sido a primeira escolha, pois você normalmente sabe com quais elementos você irá interagir na página que espera carregar. Minha abordagem sempre foi criar predicados / funções como waitForElementByID(String id)
ewaitForElemetVisibleByClass(String className)
etc., e depois usá-los e reutilizá-los onde eu precisar, seja para carregar uma página ou alterar o conteúdo da página que estou esperando.
Por exemplo,
Na minha aula de teste:
driverWait.until(textIsPresent("expectedText");
No meu pai da classe de teste:
protected Predicate<WebDriver> textIsPresent(String text){
final String t = text;
return new Predicate<WebDriver>(){
public boolean apply(WebDriver driver){
return isTextPresent(t);
}
};
}
protected boolean isTextPresent(String text){
return driver.getPageSource().contains(text);
}
Embora isso pareça muito, ele cuida da verificação repetidamente para você e o intervalo de quantas vezes a verificação pode ser definido juntamente com o tempo de espera máximo antes do tempo limite. Além disso, você reutilizará esses métodos.
Neste exemplo, a classe pai definiu e iniciou oe WebDriver driver
the WebDriverWait driverWait
.
Eu espero que isso ajude.
A melhor maneira de aguardar o carregamento da página ao usar as ligações Java para o WebDriver é usar o padrão de design do Objeto de Página com o PageFactory. Isso permite que você utilize o AjaxElementLocatorFactory
que colocar, simplesmente age como uma espera global para todos os seus elementos. Possui limitações em elementos como caixas de seleção ou transições complexas de javascript, mas reduz drasticamente a quantidade de código necessária e acelera os tempos de teste. Um bom exemplo pode ser encontrado neste post do blog. O entendimento básico do Core Java é assumido.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
Solução NodeJS:
No Nodejs você pode obtê-lo através de promessas ...
Se você escrever esse código, pode ter certeza de que a página está totalmente carregada quando 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 esse código, navegará e o selênio 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) → Regenerável
Agenda um comando para navegar para o URL fornecido.
Retorna uma promessa que será resolvida quando o documento terminar de carregar .
Aqui está uma versão do Java 8 da resposta mais votada atualmente :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Onde myDriver
está um WebDriver
objeto (declarado anteriormente).
Nota : Esteja ciente de que este método ( document.readyState
) verifica apenas o DOM.
Ligue abaixo Função no seu script, isso irá esperar até que a página não seja carregada usando javascript
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
/**
* Call this method before an event that will change the page.
*/
private void beforePageLoad() {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.mpPageReloaded='notYet';");
}
/**
* Call this method after an event that will change the page.
*
* @see #beforePageLoad
*
* Waits for the previous page to disappear.
*/
private void afterPageLoad() throws Exception {
(new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object obj = js.executeScript("return document.mpPageReloaded;");
if (obj == null) {
return true;
}
String str = (String) obj;
if (!str.equals("notYet")) {
return true;
}
return false;
}
});
}
Você pode mudar do documento para um elemento, no caso em que apenas parte de um documento está sendo alterada.
Esta técnica foi inspirada na resposta de sincebasic.
SeleniumWaiter :
import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SeleniumWaiter {
private WebDriver driver;
public SeleniumWaiter(WebDriver driver) {
this.driver = driver;
}
public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
}
public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}
E para você usá-lo :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Você pode usar o método existente abaixo para definir o tempo para o pageeLoadTimeout no exemplo abaixo, se a página estiver demorando mais de 20 segundos para carregar, em seguida, haverá uma exceção do recarregamento da página
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Você pode esperar explicitamente que um elemento seja exibido na página da web antes de executar qualquer ação (como element.click ())
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});
Isto é o que eu usei para um cenário semelhante e funciona bem.
A melhor maneira que eu vi é utilizar o stalenessOf
ExpectedCondition, para aguardar a página antiga ficar obsoleta.
Exemplo:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Esperará dez segundos até que a tag HTML antiga fique obsoleta e, em seguida, lançará uma exceção se isso não acontecer.
Eu uso o node + selenium-webdriver (que é a versão 3.5.0 agora). o que eu faço para isso é:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Você pode esperar. existem basicamente 2 tipos de espera em selênio
- espera implícita
Isso é muito simples, veja a sintaxe abaixo:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Espera explícita
Aguarde explicitamente ou espera condicional nessa espera até que uma determinada condição ocorra.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Você pode usar outras propriedades como visblityOf()
,visblityOfElement()
Se alguém usa selenida:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Mais condições podem ser encontradas aqui: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
No meu caso, usei o seguinte para conhecer o status de carregamento da página. Em nosso aplicativo, os gifs de carregamento estão presentes e os ouço da seguinte maneira para eliminar o tempo de espera indesejado no script.
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}
Onde o xpath localiza o gif no HTML DOM. Depois disso, você também pode implementar seus métodos de ação Clique em.
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}
Cara, todas essas respostas requerem muito código. Isso deve ser uma coisa simples, pois é bastante comum.
Por que não injetar um javascript simples com o driver da web e verificar. Este é o método que eu uso na minha classe de webscraper. O javascript é bastante básico, mesmo se você não conhece js.
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state.
More Info: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
"""
ready_state = self.driver.execute_script('return document.readyState')
if ready_state == 'loading':
self.logger.info("Loading Page...")
elif ready_state == 'interactive':
self.logger.info("Page is interactive")
elif ready_state == 'complete':
self.logger.info("The page is fully loaded!")
return ready_state
Como fazer com que o Selenium aguarde o carregamento da página após um clique fornece a seguinte abordagem interessante:
WebElement
partir da página antiga.WebElement
até que StaleElementReferenceException
seja lançada.Código de amostra:
WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
try
{
link.isDisplayed();
return false;
}
catch (StaleElementReferenceException unused)
{
return true;
}
});
new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(element))
.