Testes e2e com Protractor

No post Testando JavaScript com Jasmine mostrei como fazer testes unitários, visualizar os resultados e entendemos que com os testes unitários testamos pequenas partes do nosso código. Agora veremos um pouco sobre o teste e2e (end-to-end).

O foco do teste e2e (end-to-end) é testar aplicações como se fosse o usuário final, ou seja, abrindo o browser, preenchendo campos, enviando formulários, lendo valores, etc.

Para este exemplo vamos usar a aplicação TodoMVC AngularJS

Instalação

Como o Protractor é uma ferramenta que roda no Node.js podemos fazer a instalação usando o NPM.
A instalação deve ser feita global usando o parâmetro -g.

1
npm install -g protractor

Esse comando irá instalar o Protractor e o webdriver-manager.
O webdriver-manager cria uma instancia do Selenium Server que é aonde interagimos com o browser via comandos…vamos ver isso daqui a pouco :)

O próximo passo é atualizar o webdriver-manager

1
webdriver-manager update

webdriver-manager

Inicialize o servidor com o comando abaixo que irá rodar o selenium server

1
webdriver-manager start

No console pode se ver que o servidor esta acessível em http://127.0.0.1:4444/wd/hub
1
INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub

Ao abrir a url podemos criar sessões de outros browsers, carregar scripts, e até tirar prints.
O Protractor faz essa interação com o webdriver-manager/Selenium Server via comandos nos testes.

Protractor

Assim como fizemos no Karma devemos criar um arquivo de configuração aonde podemos informar qual o navegador vai ser utilizado, quais os arquivos de testes serão executados, qual a url do Selenium Server etc.

conf.js
1
2
3
4
5
6
7
8
9
10
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec/**/*.js'],
framework: 'jasmine',
capabilities: { browserName: 'chrome' },
jasmineNodeOpts: {
showColors: true,
isVerbose: true,
}
}

Agora podemos chamar o comando protractor conf.js para executar os testes.

Iniciando os testes

No primeiro teste vamos interagir com o navegador acessando a url da aplicação e comparando o título da página.

O acesso ao navegador é feito através da variável global browser quem contem o método get que faz a requisição da página e o método getTitle que retorna o título da página.

todomvc-spec.js
1
2
3
4
5
6
7
describe('TodoMVC', function() {
it('Deve ter um titulo', function() {
browser.get('http://todomvc.com/examples/angularjs-perf');
expect(browser.getTitle()).toEqual('AngularJS • TodoMVC');
});
//...
});

Como todos os testes vão acessar a página, vamos adicionar o código no beforeEach
todomvc-spec.js
1
2
3
4
5
6
describe('TodoMVC', function() {
beforeEach(function() {
browser.get('http://todomvc.com/examples/angularjs-perf');
});
//...
});

Interagindo com os elementos da página

Para que possamos trabalhar com os elementos da página o Protractor nos fornece a função global element. Podemos pensar nessa função como a função $() da biblioteca Jquery aonde podemos manipular o DOM e executar ações como click e outras.

Veja abaixo alguns exemplos de como podemos fazer a seleção dos elementos.

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
//Seleciona o elemento via CSS
//<div class="class-exemplo">
//O mesmo que $('.class-exemplo') do Jquery
element(by.css('.class-exemplo'));

//Seleciona o elemento pelo ID
//<div id="id-exemplo">
//O mesmo que $('#class-exemplo') do Jquery
element(by.id('id-exemplo'));

//Seleciona o elemento pelo Model do AngularJS
//<div data-ng-model="Usuario.Nome">
element(by.model('Usuario.Nome'));

//Seleciona o elemento que esta vinculado ao Model
//<p>{{Usuario.Nome}}</p>
element(by.binding('Usuario.Nome'));

//Podemos fazer a seleção de vários elementos utilizando o `element.all`
element.all(by.css('.class-exemplo')).then(function(item) {
//...
});

//Seleciona os elementos de um ng-repeat
//<li ng-repeat="todo in todos">
element.all(by.repeater('todo in todos'));

Veja abaixo alguns exemplos de ações que podemos fazer com os elementos.
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
/*ELEMENTOS*/
var BtnEnviar = element(by.id('BtnEnviar')); //<input id="BtnEnviar" type="submit" value="Submit">
var TxtNome = element(by.id('Nome')); //<input id="Nome" type="text" name="Nome" value="">
var VariosItens = element.all(by.css('.item'));

/*AÇÕES*/
//Informa se o elemento esta presente na página
TxtNome.isPresent();

//Efetua um click no botão
BtnEnviar.click();

//Preenche o campo com o texto
TxtNome.sendKeys('Hello World!!!');

//Limpa o campo de texto
TxtNome.clear();

//faz a leitura do atributo value do elemento
TxtNome.getAttribute('value');

//Retorna a quantidade de itens
VariosItens.count();

//Retorna o elemento por index
VariosItens.get(index);

//Retorna o primeiro elemento
VariosItens.first();

//Retorna o último elemento
VariosItens.last();

Agora que sabemos localizar os elementos e conhecemos algumas funções vamos ver como ficaria um teste para adicionar um novo item.
todomvc-spec.js
1
2
3
4
5
6
7
8
9
10
11
12
it('Adiciona novo item', function() {
//Elementos
var newTodo = element(by.model('newTodo'));
var todos = element.all(by.repeater('todo in todos'));

//Adiciona o texto e apertamos Enter para enviar o formulário
newTodo.sendKeys('Hello World!!!');
newTodo.sendKeys(protractor.Key.ENTER);

//Contamos os itens da lista
expect(todos.count()).toEqual(1);
});

Pronto! Aqui foi somente uma introdução mostrando o que podemos fazer com o Protractor.

Veja a documentação completa para mais detalhes: http://angular.github.io/protractor

Até os próximos artigos!