Desenvolvimento

11 nov, 2014

Refatorando testes com Protractor JS e testando aplicações não-AngularJS

Publicidade

No primeiro artigo sobre o Protractor, foram apresentados os comandos para instalação da ferramenta, configuração de ambiente e algumas características básicas de seu uso.

Hoje, a ideia é ir um pouco além, criando novos testes, refatorando os testes já criados e, de sobra, aprendendo como automatizar testes de aplicações não-AngularJS com o Protractor.

Até então os seguintes testes foram criados:

it('should have a title'...  
it('should be able to type a text in the text field, press enter, and verify the result'...  
it('should clean the items from the list and verify that no items are available in the list'...

Agora será criado um teste que marca como completos os itens da to do list e os verifica na completed view.

it('should be able to complete items and verify them in the completed list', function() {  
  var todoTextField = element(by.id('new-todo'));
  var text = 'Criar teste para completed list';

  todoTextField.sendKeys(text);
  todoTextField.sendKeys(protractor.Key.ENTER);

  var completedLink = element.all(by.css('a[ng-class="{selected: status == \'completed\'}"')).last();
  var toggleAll = element(by.id('toggle-all'));
  var completedList = element(by.css('#todo-list .completed .view .ng-binding'));

  toggleAll.click();
  completedLink.click();
  expect(completedList.getText()).toContain(text);
});

No teste acima, entre as linhas 2 e 5, um item é adicionado à to do list. Na linha 7 o link completed é identificado e armazenado em uma variável. Na linha 8, o elemento para marcar todos os itens da lista como completos também é identificado e armazenado em uma variável. Na linha 9, a view somente com itens completos é identificada e armazenada em uma variável. E nas linhas 10, 11 e 12, o elemento para marcar todos itens como completos é clicado, o link para a view completed é clicado, e a verificação do item nessa view é realizada, nessa ordem.

Porém, olhando para o código de um dos testes já criados (“it should be able to type a text in the text field, press enter, and verify the result“) e comparando-o com o novo teste, percebe-se que algum código começa a ser duplicado, especificamente a inserção de um item na to do list.

E quando o código começa a ficar duplicado é a hora de refatorar, pois código duplicado é anti-pattern.

Com os helpers, é possível isolar a lógica de testes que se repetem ao longo da bateria e tornar a legibilidade e a manutenção dos testes mais serena.

Abaixo, é exibido o helper para inserção de itens à lista:

// todomvc.helper.js

module.exports = {  
 addTodoItem : function(item) {
   it('should add an item into the todo list', function() {
     var todoTextField = element(by.id('new-todo'));

     text = item;
     todoTextField.sendKeys(text);
     todoTextField.sendKeys(protractor.Key.ENTER);
   });
 }
};

Neste helper, é possível notar que um módulo é exportado, o qual executa uma função que basicamente testa a inserção de um item à lista, recebendo esse item como argumento.

E para se utilizar desse helper no arquivo spec.js, o seguinte código é adicionado antes do describe:

var todomvcHelper = require('./todomvc.helper');

E os testes “it should be able to type a text in the text field, press enter, and verify the result” e “should be able to complete items and verify them in the completed list” são refatorados conforme:

todomvcHelper.addTodoItem('Teste de digitação em campo texto');

it('should be able to add items in the to do list', function() {  
 var todoLabel = element(by.css('.view .ng-binding'));
 expect(todoLabel.getText()).toEqual(text);
});

todomvcHelper.addTodoItem('Criar teste para completed list');

it('should be able to complete items and then add them to the completed list', function() {  
 var completedLink = element.all(by.css('a[ng-class="{selected: status == \'completed\'}"')).last();
 var toggleAll = element(by.id('toggle-all'));
 var completedList = element(by.css('#todo-list .completed .view .ng-binding'));

 toggleAll.click();
 completedLink.click();
 expect(completedList.getText()).toContain(text);
});

Com a refatoração acima, oito linhas de código se transformaram em apenas duas no arquivo spec.js.

Helpers ajudam! =p

O código gerado até aqui já está disponível no GitHub.

Utilização do protractor para aplicações não-AngularJS

Testando aplicação Ember.JS com Protractor

A aplicação todomvc utilizada para a criação deste e o do primeiro artigo foi o todomvc.

Porém, esse mesmo todomvc está disponível em outros frameworks, entre eles o Ember.js.

Portanto, a ideia aqui é simplesmente refatorar os mesmos testes para que sejam executados na versão em Ember do todomvc.

Primeiro, a seguinte linha será adicionada ao início de cada um dos cenários de teste criados (inclusive no helper):

browser.ignoreSynchronization = true;

Com isso, já será possível rodar os testes, e alguns deles já devem passar (aqueles que não utilizam características específicas do AngularJS).
Porém, dois testes irão falhar, os quais utilizam o ng-binding, específico do AngularJS.

Para que eles passem, refatore-os conforme:

it('should be able to add items in the to do list', function() {  
  browser.ignoreSynchronization = true;

  var todoLabel = element(by.css('#todo-list li label'));

  expect(todoLabel.getText()).toEqual(text);
});

e

it('should be able to complete items and then add them to the completed list', function() {  
  browser.ignoreSynchronization = true;

  var completedLink = element(by.css('.selected'));
  var toggleAll = element(by.id('toggle-all'));
  var completedList = element(by.css('#todo-list .completed label'));

  toggleAll.click();
  completedLink.click();
  expect(completedList.getText()).toContain(text);
});

Pronto! Os mesmos cenários de teste agora também irão passar quando disparados contra o todomvc em Ember.

O código gerado para esta parte do artigo também está disponível no GitHub.