Desenvolvimento

9 fev, 2018

Integrando Protractor com CucumberJS

Publicidade

Enquanto estamos automatizando testes, sabemos que uma boa prática dentro de um time ágil é realizar a escrita de cenários por N motivos, os quais não vou detalhar aqui, pois não é o objetivo desse artigo. Mas, como – por padrão – o Protractor não vem configurado, temos que fazer alguns ajustes no arquivo de configuração para conseguir tirar proveito de todas as vantagens que a escrita de cenários de testes nos dá, juntamente com o Cucumber.

Precisamos que o Cucumber esteja instalado na sua máquina.

npm install -g cucumber

A primeira configuração que precisamos fazer é ter a dependência do Cucumber no arquivo package.json. E para instalá-la, execute o comando abaixo dentro do diretório do seu projeto:

npm install --save-dev protractor-cucumber-framework

Vamos instalar também uma dependência para a geração do report:

npm install cucumber-html-reporter --save-dev

Vamos adicionar as seguintes configurações dentro do arquivo protractor.conf.js.

Primeiro informamos que vamos utilizar um framework customizado:

framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),

Depois informamos o caminho que vão ficar as nossas features:

specs: [
 'features/*.feature
]

O caminho onde vão ficar as implementações dos steps:

cucumberOpts: {
   require: [
         'features/step_definitions/*.step.js',
         ],
   format: ['json:results.json', 'pretty'],
   profile: false,
   'no-source': true,

E ainda a geração do Report dos testes:

afterLaunch: function() {
   var reporter = require('cucumber-html-reporter');
 
   var options = {
         theme: 'bootstrap',
         jsonFile: 'results.json',
         output: 'e2e/tests_result/cucumber_report.html',
         reportSuiteAsScenarios: true,
         launchReport: true
     };
 
     reporter.generate(options);
 
 },

O arquivo de configuração completo pode ser encontrado aqui. Com isso feito, já podemos iniciar nossos testes utilizando Cucumber e, para exemplificar, vamos utilizar uma aplicação simples de listagem de Pokémons. Você pode acessar a listagem aqui.

Agora vamos escrever nosso primeiro cenário.

Crie o features/busca.pokemon.feature:

#language:
pt

Funcionalidade: Busca de pokémons
Cenário: Pesquisa de pelo nome do pokémon
Dado que eu estou na tela de listagem de pokémons
Quando eu digito "mew" no campo de pesquisa
Então devo visualizar dois pokémons no resultado

Agora vamos executar o comando:

protractor cucumber-example/protractor.conf

O Cucumber vai gerar os steps que precisam ser implementados:

this.Given(/^que eu estou na tela de listagem de pokémons$/, function (callback) {
   // Write code here that turns the phrase above into concrete actions
         callback(null, 'pending');
       });
this.When(/^eu digito "([^"]*)" no campo de pesquisa$/, function (args1, callback) {
   // Write code here that turns the phrase above into concrete actions
         callback(null, 'pending');
       });
this.Then(/^devo visualizar dois pokémons no resultado$/, function (args1, callback) {
   // Write code here that turns the phrase above into concrete actions
         callback(null, 'pending');
       });

Agora precisamos implementar esses steps em ações concretas, mas para isso, é preciso criar um arquivo chamado busca.pokemon.step.js dentro de features/step_definitions/. Dentro desse arquivo crie a seguinte função:

module.exports = function(){
}

Dentro dela, cole os snippets gerados.

Veja abaixo o resultado final do arquivo busca.pokemon.step.js já com as implementações necessárias:

const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const ListagemPage = require('../../../pages/listagem.po.js');
chai.use(chaiAsPromised);
const expect = chai.expect;
module.exports = function(){
 const listagemPage = new ListagemPage();
  this.Given(/^que eu estou na tela de listagem de pokémons$/, function (callback) {
   listagemPage.visit().then(callback);
 });
 this.When(/^eu digito "([^"]*)" no campo de pesquisa$/, function (nome, callback) {
   const filtro = listagemPage.filtro;
   const EC = protractor.ExpectedConditions;
   browser.wait(EC.presenceOf(filtro));
   listagemPage.pesquisarPokemon(nome).then(callback);
 });
 this.Then(/^devo visulizar dois pokémons no resultado$/, function (callback) {
   expect(listagemPage.resultados.count()).to.eventually.equal(2).and.notify(callback);
 });
}

Inicialmente importamos os módulos do chai.js, biblioteca de assertions que lida de forma bem completa com a questão das Promises do Protractor. Fizemos também o import de nosso PageObject (veja o primeiro artigo no qual falo sobre a utilização de PageObject).

Alguns detalhes que são importantes:

  • Função de callback: Todos steps gerados possuem uma função de callback, que nada mais é do que um “link” para o próximo passo;
  • Timeout: Em algumas situações, precisamos especificar um timeout para os steps. Nesse exemplo, especificamente, não foi necessário, mas para adicionar um, basta passarmos mais um parâmetro dentro do step.

Fica dessa forma:

this.Given(/^que eu estou  na tela de listagem de pokémons$/, {timeout: 60 * 1000} , function (callback) {
   listagemPage.visit().then(callback);
 });
  • Promise: Todos os métodos do nosso PageObject precisam retornar algo para que possamos tirar proveito do encadeamento dos steps:
listagemPage.visit().then(callback);

Esse then(callback); está informando que o próximo step só vai ser executado após o método visit do nosso PageObject ser finalizado. Caso contrário você vai ter uma dor de cabeça terrível, pois se não fizer isso, quando estiver rodando o teste em todos os passos, os steps vão informar que já foram executados sem ainda terem sido, por causa da execução assíncrona.

  • Chai: Utilizar o Chai.js para fazer as validações é uma ótima escolha, pois ele é simples de ser utilizado e possui uma boa documentação com muita flexibilidade. Repare que em nosso Then, utilizamos o expect:
expect(listagemPage.resultados.count()).to.eventually.equal(2).and.notify(callback);

Esse notify(callback) vai apenas informar que os testes terminaram.

Agora que aprendemos como utilizar o CucumberJS com o Protractor, recomendo que utilizem essa forma de documentação viva e todos seus benefícios. Dessa forma, o seu time – do PO aos Devs – vão ter um guia de utilização de cada funcionalidade, o que ajudará muito à todos no dia a dia.

Espero que tenham gostado e até a próxima!

Referências

***

Este artigo foi publicado originalmente em: https://www.concrete.com.br/2018/02/01/integrando-protractor-com-cucumberjs/