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