Podemos utilizar um tempo de espera para mitigar erros ao tentar acessar elementos utilizando o Selenium WebDriver.
Como exemplo usamos a linguagem Java e levarei em consideração que já utiliza o WebDriver, apresentando este recurso avançado.
Imaginamos que você tenha um teste automatizado que acessa os elementos da página de login e no botão de "OK" é enviado a ação de clicar.
Depois é redirecionado para outra página do sistema, onde tenho que clicar em outro botão confirmando o meu login.
Por infelicidade do destino, apresenta um erro ao tentar acessar o elemento do botão da segunda página.
Para ilustrar, repare no código abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class LoginPage { WebDriver driver; //Mapeamento dos Elementos da Página de Login @FindBy(id="Login") WebElement usuario; @FindBy(how=How.NAME,using="Senha") WebElement password; @FindBy(how=How.ID, using="BtnOK") WebElement botaoOK; @FindBy(how=How.ID, using="BtnConfirmaOK") WebElement confirmacaoBotaoSucess; public LoginPage(WebDriver driver) { super(); this.driver = driver; } public void fazerLogin(String uid, String pass){ // Define os valores de Login e Senha. usuario.sendKeys(uid); password.sendKeys(pass); // Envia ação de clicar no botão OK e redireciona para outra página. botaoOK.click(); // Erro ocorre ao tentar acessar o elemento do botão que está em outra página. confirmacaoBotaoSucess.click(); } } |
O erro é o bendito abaixo:
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element
O erro é claro que não conseguiu localizar o elemento.
Acontece que quando redireciona de uma página para a outra, não temos um tempo de espera entre os passos (steps).
Este tempo seria o de renderizar a página, podendo neste tempo ocorrer lentidão na rede, servidores, etc.
Uma grande parcela de automatizadores utilizam o método Thread.sleep(), esta abordagem é errada, não sendo eficiente.
O sleep espera o tempo definido, assim podendo aumentar muito o tempo do seu teste e não evitando se tivermos uma demora maior na renderização da página.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public void fazerLogin(String uid, String pass){ // Define os valores de Login e Senha. usuario.sendKeys(uid); password.sendKeys(pass); // Envia ação de clicar no botão OK e redireciona para outra página. botaoOK.click(); //Abordagem errada é definir um tempo de espera fixo, utilizando o método abaixo. Thread.sleep(3000); // Erro ocorre ao tentar acessar o elemento do botão que está em outra página. confirmacaoBotaoSucess.click(); } } |
A documentação do WebDriver recomenda duas formas de definir um tempo de espera.
O "Explicit and Implicit Waits" tem duas abordagens distintas.
Primeiramente, vamos definir o que é Implícito e Explícito.
Nosso velho amigo dicionário diz:
Implícito
O adjetivo implícito indica algo que não está claramente expresso, que está subentendido.
É sinônimo de subentendido, subjacente, latente, tácito e velado.
Explícito
O adjetivo explícito indica algo que está expresso de forma clara e precisa, sem ambiguidades ou restrições. É sinônimo de claro, manifesto, patente, preciso, categórico, terminante, declarado e compreensível.
O implícito é o mais usual e simples.
Defininos um tempo de timeout para todo o escopo de nossos testes.
Conforme o código abaixo, definimos o tempo de 60 segundos de timeout.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public void fazerLogin(String uid, String pass){ //define um TimeOut para em caso de não encontrar elementos na página. driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS); // Define os valores de Login e Senha. usuario.sendKeys(uid); password.sendKeys(pass); // Envia ação de clicar no botão OK e redireciona para outra página. botaoOK.click(); // Não irá occorer erro ao tentar acessar o elemento do botão que está em outra página. confirmacaoBotaoSucess.click(); } |
Definindo o driver.manage().timeouts().implicitlyWait(), o WebDriver irá demorar o tempo definido para gerar a exceção de erro.
Ele verifica a cada 500 milissegundo se o elemento referenciado foi criado.
Assim evitando o erro de NoSuchElementException e sendo uma forma eficiente, evitando de utilizar o Thread.sleep().
O valor do método implicitlyWait() pode ser definido logo após a criação do objeto driver, não sendo necessário definir esse valor toda hora.
A forma explícita é definida pelo tempo de espera para cada elemento.
No código abaixo, identificamos a criação do objeto WebDriverWait.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void fazerLogin(String uid, String pass){ // Define os valores de Login e Senha. usuario.sendKeys(uid); password.sendKeys(pass); // Envia ação de clicar no botão OK e redireciona para outra página. botaoOK.click(); //Segunda Tela onde é redirecionado depois do login. //===> Usando recurso de Wait, para evitar exception de encontrar elemento na tela. WebDriverWait wait = new WebDriverWait(driver, 10); WebElement btnConfirmarOK = wait.until(ExpectedConditions.visibilityOf(confirmacaoBotaoSucess)); btnConfirmarOK.click(); } |
Utilizando o objeto WebDriverWait definimos o tempo de timeout e através do método until dizemos a condição que esperamos.
Em casos que a aplicação fica processando um lote por tempo indefinido, onde irá cair por timeout implícito, a utilização do tempo de espera explícito é necessário.
ATENÇÃO:
Não misture os tempos de espera implícito e explícito.
O tempo de espera fica imprevisível, assim não sendo possível dizer quanto tempo irá demorar.
Quando for necessário utilizar o tempo de espera explícito, defina como:
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);