Back-End

30 nov, 2017

Primeiros passos com Protractor

Publicidade

Atualmente, estou automatizando testes utilizando o Protractor, então decidi escrever uma série de artigos com algumas dicas do que tenho aprendido.

Primeiro: o que é o Protractor e para quê ele serve?

O Protractor é um framework de testes automatizados e2e para aplicações AngularJS, que roda no Node e foi criado baseado no WebDriverJS para interagir com elementos da página web.

Apesar de ter sido desenvolvido para aplicações AngularJS, ele funciona muito bem para aplicações que não foram feitas utilizando AngularJS, bastando apenas adicionar em seu arquivo de configuração uma linha para informar isso. A grande vantagem de utilizarmos o Protractor para aplicações AngularJS, é que ele já tem suporte nativo para seletores específicos do AngularJS como, por exemplo, um model, repeat, binding, etc.

Hands On

Como já foi falado, o Protractor roda no Node, então precisamos que ele esteja instalado na máquina (para instalar o Node, clique aqui). Mas, para instalar o Protractor, vamos executar o seguinte comando:

npm install -g protractor

Após instalado, vamos criar nossa aplicação de teste simples. Uma lista de Pokémons.

A aplicação que será testada é essa: https://pokedex-angular-example.herokuapp.com

E este é o repositório da aplicação (caso queira rodar no localhost): https://github.com/cassioafs/pokedex

A estrutura de pastas que vamos utilizar é a seguinte:

├── e2e
│   ├── jasmine-example
│   │   ├── protractor.conf.js
│   │   └── specs
│   │       └── pokemon.spec.js
│   └── pages
│       └── listagem.po.js
└── package.json

Dentro da pasta e2e/jasmine-example/specs estarão nossos testes. Já dentro da pasta e2e/pages, estão nossos PageObject, que servem para encapsular cada página acessada dentro de uma classe para definirmos atributos e métodos, seguindo o conceito de orientação à objetos. Com o PageObject, separamos mais as responsabilidades, temos maior reaproveitamento de código, um muito mais limpo e simples de entender.

Arquivo package.json

Nele, informamos quais são as dependências que nossos testes vão utilizar.

{
 "name": "protractor-style-guide",
 "version": "1.0.0",
 "devDependencies": {
   "jasmine-spec-reporter": "^3.2.0",
   "protractor": "^4.0.3"
 }
}

Arquivo protractor.conf.js

Esse é o arquivo de configuração do Protractor. É nele que vamos colocar todo o tipo de configuração que utilizaremos em nossos testes, como, por exemplo, o browser, a url padrão que acessaremos, a pasta na qual estão nossos testes e etc.

'use strict'

const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
module.exports.config = {
  directConnect: true,
  capabilities: {
    'browserName': 'chrome',
  },
  specs: ['specs/*.spec.js'],
  baseUrl: 'https://pokedex-angularjs.herokuapp.com',
  onPrepare() {
    jasmine.getEnv().addReporter(new SpecReporter({
      displayFailuresSummary: true,
      displayFailedSpec: true,
      displaySuiteNumber: true,
      displaySpecDuration: true
    }));
  }
};

Na linha 3 estamos importando o módulo SpecReporter, para termos uma visualização melhor do resultado dos testes. Dentro do module.exports.config estão as configurações que vamos utilizar para a execução dos testes.

Na linha 5, temos o directConnect: true, no qual os testes vão executar no driver do próprio Chrome da máquina de onde os testes vão rodar.

Na linha 6, capabilities é onde definimos em qual browser os testes vão ser executados e onde podemos especificar se vai rodar no Chrome, Firefox ou até mesmo em um dispositivo móvel.

Na linha 9, specs é a configuração que informamos ao Protractor em qual diretório vão estar os testes, no nosso caso, dentro da pasta specs todos os arquivos com extensão .spec.js.

Na linha 10, baseUrl é a url base na qual o Protractor vai executar os testes. Essa configuração é bastante útil, pois com ela, não precisamos informar toda a url que vamos acessar em nossos testes, basta colocarmos o path que vamos acessar.

Na linha 12 fica a configuração do SpecReporter gerada pelos testes.

Arquivo pokemon.spec.js

'use strict'
const ListagemPage = require('../../pages/listagem.po.js');

describe('Listagem de pokémons', ()=> {
 const listagemPage = new ListagemPage();
 it('Deve pesquisar um pokémon de acordo com o texto pesquisado', ()=>{
   listagemPage.visit();
   listagemPage.filtro.sendKeys('mew');
   expect(listagemPage.resultados.count()).toEqual(2);
 });
}); 

Estamos utilizando a versão ES6 do JavaScript.

Na linha 2 importamos nosso arquivo ListagemPage seguindo o padrão PageObject.

Na linha 4 começa o teste, com o describe (do Jasmine) definimos uma suíte de testes, passando como primeiro parâmetro uma descrição e o segundo parâmetro é um callback onde vão ter os testes.

Na linha 5 criamos uma instância do nosso PageObject.

Na linha 6 definimos um it (do Jasmine) que é o teste em si, que vai ser executado. Ele recebe dois parâmetros também, uma descrição do teste e um callback.

Na linha 7 chamamos o método visit() do nosso PageObject que vai acessar a página.

Na linha 8 utilizamos o método sendKeys para digitar um texto.

E finalmente na linha 9 é o nosso expect, ou seja, o que estamos esperando do nosso teste. Nesse caso, esperamos que o resultado da pesquisa seja igual a dois Pokémons.

Arquivo listagem.po.js

'use strict'

class ListagemPage{
 constructor(){
   this.filtro = element(by.model('PokemonsController.filtro'));
   this.resultados = element.all(by.repeater('item in PokemonsController.pokemons'));
 }

 visit(){
   return browser.get('/#!/list');
 }
}
module.exports = ListagemPage;

Na linha 3 definimos uma class para representar nosso PageObject.

Na linha 4 temos o nosso construtor com as definições dos elementos.

Dentro do construtor temos:

element(by.model('PokemonsController.filtro'));

O element é uma função auxiliar que encontra um elemento na tela para que seja possível interagir com tal elemento. Ele recebe como parâmetro um locator para encontrar o elemento (vou fazer um post sobre locators do Protractor em breve). O by.model encontra o elemento que possui a diretiva ng-model=”PokemonsController.filtro”.

Na linha 6:

element.all(by.repeater('item in PokemonsController.pokemons'));;

O .all encontra todos os elementos da tela que possuem o locator passado como parâmetro, nesse caso o by.repeater encontra os elementos que possuem a diretiva do Angular ng-repeat=”item in PokemonsController.pokemons”

Na linha 9 o método visit() utiliza um wrapper browser.get de uma instância do WebDriver, usado para navegação e informações em toda a página. Para utilizá-lo é necessário que a lib do Angular esteja presente na página, caso contrário vai dar um erro informando que não foi possível encontrar o Angular. Para acessar páginas que não possuem a lib do Angular é necessário utilizar diretamente o browser.driver.

Na linha 13 exportamos o módulo ListagemPage, para que ele possa ser utilizado em nossa aplicação.

Por fim, para rodarmos o teste, basta executarmos o comando via terminal dentro da raiz do projeto:

protractor e2e/jasmine-example/protractor.conf.js

O resultado final vai ser algo como a imagem abaixo:

Link do repositório do https://github.com/cassioafs/protractor-guide-line

Bom, é isso pessoal. Espero que tenham gostado dessa pequena introdução sobre como criar o seu primeiro teste utilizando Protractor e que eu tenha conseguido ajudar a entender alguns detalhes de configuração.

Referências

***

Este artigo foi publicado originalmente em: https://www.concrete.com.br/2017/11/06/primeiros-passos-com-protractor/