Atletas ELSA

Fazendo parte de um estudo sobre saúde, estamos em continua preocupação com o bem-estar próprio. O esporte, então, acaba sendo uma das melhores opções para o mens sana in corpore sano. Alguns membros da equipe levam isso muito a sério e são também atletas. Dois deles foram documentados pelo RBS Esporte, em momentos distintos.

Tiago, o dançarino:


Gabriel, o "Runner" (a partir de 13:40):


Testes com Selenium WebDriver


Selenium WebDriver é a união de duas ferramentas e visa facilitar a criação de testes automatizados para interfaces de aplicações web. A intenção das novas versões do Selenium (a partir da 2.0) é focar no desenvolvedor para que ele gere também os códigos dos testes. Neste post vamos explicar em alguns passos como começar a fazer seus próprios testes.

No nosso exemplo vamos utilizar como linguagem de programação o Java e como ambiente de desenvolvimento o Eclipse. Para executar os testes utilizaremos o JUnit.

O primeiro passo é adicionar os JARs para que consigamos utilizar o WebDriver. Para fazer o download da última versão vá até http://code.google.com/p/selenium/downloads/list. Descompacte o arquivo e adicione os JARs ao seu projeto no Eclipse clicando com o botão direito do mouse em cima da raiz do seu projeto e depois em "Properties".


No menu esquerdo clique em "Java Build Path", selecione a aba "Libraries" e clique em "Add External JARs...". Navegue até a pasta onde estão os arquivos que você fez download, selecione todos e clique em "Abrir". Depois clique em "OK". Pronto, você já pode começar a gerar seus códigos de testes!


A partir de agora começaremos o nosso teste. Neste exemplo vamos mostrar passo a passo como criamos um teste para verificar a interface de autenticação do nosso sistema.

public class LoginTest {
 
 @Test
 public void loginTest() {
  WebDriver driver = new FirefoxDriver();
  driver.get("localhost:8080/elsa/login");
 }

}

Inicialmente nosso teste não verifica nada, apesar de ficar com a barra verde ele apenas abre uma janela do Firefox com o endereço do nosso servidor de testes. Roubamos... mas precisamos partir de algum lugar!
Após verificar que a janela do navegador abriu corretamente a tela de autenticação do sistema vamos tentar realizar a autenticação.

public class LoginTest {
 
 @Test
 public void loginTest() {
  WebDriver driver = new FirefoxDriver();
  
  driver.get("localhost:8080/elsa/login");
  
  driver.findElement(By.id("username")).sendKeys("usuario");
  driver.findElement(By.id("password")).sendKeys("senha");
  driver.findElement(By.id("loginButton")).click();
 }

}

Com o WebDriver buscamos pelos elementos exibidos na tela através dos seus identificadores e inserimos os valores desejados para usuário e senha. Além de buscar pelos elementos da página por seus id’s também é possível buscar pelo nome da tag, do name, do link e até mesmo do estilo CSS aplicado ao elemento.
A partir daqui nos damos conta que em qualquer teste do nosso sistema teremos que passar pela tela de login, então podemos utilizar o padrão chamado de Page Objects. Para tanto, criamos uma classe chamada LoginPage que inicialmente terá um método que fará login no sistema.

public class LoginPage {
 
 public void login(WebDriver driver){
  driver.findElement(By.id("username")).sendKeys("usuario");
  driver.findElement(By.id("password")).sendKeys("senha");
  driver.findElement(By.id("loginButton")).click();
 }
}

E agora sim podemos realizar nosso teste, na classe LoginTest.

public class LoginTest {
 
 public LoginPage loginPage;
 public WebDriver driver;
 
 @Before
 public void setup() {
  loginPage = new LoginPage();
  
  driver = new FirefoxDriver();
  driver.get("localhost:8080/elsa/login");
 }
 
 @Test
 public void loginTest() {
  loginPage.login(driver);
  
  String welcomeMessage = driver.findElement(
    By.xpath("/html/body/div/div[4]/div/ul/li/span")).getText();

  assertEquals("Bem vindo ao Prontuário Eletrônico Online do ELSA.",
    welcomeMessage);
 }

}


Aqui já passamos a instanciar LoginPage e o WebDriver no método setup que está anotado com @Before e, desta forma, é executado sempre antes de cada método anotado com @Test. Além disso, buscamos o valor da mensagem de boas vindas através do método findElement e utilizamos como parâmetro a busca de um elemento presente na página pelo xpath correspondente. Finalmente, fizemos uma asserção para garantir que a mensagem que aparece é a esperada.

Agora que nosso teste está pronto executamos esperando a barra verde que instantaneamente fica vermelha, informando que o nosso teste falhou. Aqui vale uma breve explicação. Como estamos trabalhando com ambiente web, devemos saber que nem sempre a resposta é imediata para as requisições feitas para os servidores onde estão as aplicações. Então o melhor a ser feito para contornarmos o problema é implementarmos uma condição esperada de parada com um timeout, desta maneira o teste pode ser executado com mais confiabilidade.

Para tanto, será necessários fazer algumas mudanças no método loginTest.

@Test
public void loginTest() {
 loginPage.login(driver);
  
 ExpectedCondition<Boolean> expectedCondition = new ExpectedCondition<Boolean>() {
  public Boolean apply(WebDriver webDriver) {
   webDriver.findElement(By.xpath("/html/body/div/div[4]/div/ul/li/span"));
   return true;
  }
 };

 Wait<WebDriver> wait = new WebDriverWait(driver, 15);
 wait.until(expectedCondition);
  
 String welcomeMessage = driver.findElement(
    By.xpath("/html/body/div/div[4]/div/ul/li/span")).getText();

 assertEquals("Bem vindo ao Prontuário Eletrônico Online do ELSA.",
    welcomeMessage);
}

Agora sim, nosso teste é executado e temos a barra verde!
Basicamente implementamos a condição de parada esperada que, neste caso, é o surgimento da própria mensagem de boas vindas do sistema. Depois, instanciamos o wait com o nosso driver e um timeout de 15 segundos e esperamos que a condição seja satisfeita por no máximo 15 segundos, caso contrário o teste falhará.
Claro que o exemplo depende das credenciais utilizadas para realizar o login e apenas ele não garante que a tela de login do nosso sistema está funcionando. Como teste complementar podemos acessar o sistema com uma senha errada e fazer uma asserção em cima da mensagem de falha de login.

PrimeFaces autoComplete weird behavior

A few weeks ago, while changing the behavior of an auto-complete field we have in our system, I came across a very weird bug. The field was supposed to suggest a list of Technicians, based on the name the user typed.

I was asked to have it accept not only the name of the Technician but also their ids.

To make the long story short: we are using a PrimeFaces AutoComplete component with the forceSelection flag set to true. The problem was that even tough the user did not selected any of the suggestions on the list, the value he typed was still being submitted to the form.

At first this was not a problem, because our Converter is using the Technician id, and when searching for a name, there was no match. But when the search includes the id, undesired thing happens, i.e. the field which as supposed to be empty, was filled with the Technician's information whose id the user typed.

With the help of Firebug, I found out that the hidden input Primefaces uses to implement the auto-completion, was not being cleaned when none of the suggestions was picked, thus, submitting a value the user didn't know was there.

To solve the problem, I hacked into Primefaces's jar, and, after formatting the autocomplete.js with the help of my friend Eclipse, I found this line:

jQuery(this).val("");

On a lucky/educated guess, I added the following line below that one:

jQuery(a.jqh).val("");

After repacking the jar, the problem was gone. I am not sure if this is a bug or the correct behavior, but it happened in Primefaces version 2.2.1.