Dev (Back & Front)ARTIGO

Manipulação de listas com Protractor

Neste artigo, o autor apresenta os métodos de manipulação de listas do Protractor, suas vantagens e como usa-los.

Você, como profissional de QA, já deve ter trabalhado com listas, certo? Um exemplo clássico desse tipo de trabalho é uma tela de listagem de resultados que precisam ser validados, validação essa que é bastante trabalhosa. Uma das vantagens do Protractor (se você não sabe do que eu estou falando, clique aqui) são seus métodos de manipulação de listas do JavaScriptJavaScript116 conteúdosJavaScript em 2020: O que esperarDev (Back & Front) · jan 2020Campos públicos e privados em classes JavaScript – O que vem por aí no ESNextDev (Back & Front) · abr 201929 anos de JavaScript!Dev (Back & Front) · jan 2025Ver tudo em Dev (Back & Front) , que facilitam muito quando temos esse tipo de cenário.

Vamos ver um exemplo? Veja a listagem abaixo:

<tr ng-repeat="item in PokemonsController.pokemons|filter: PokemonsController.filtro">
   <td>
       <a href="#!/details/{{item.id}}">
           <strong>
               #{{item.id}}
           </strong>
       </a>
   </td>
   <td>
       <a href="#!/details/{{item.id}}">
           <img ng-src="{{item.image}}" width="60px" alt="">
       </a>
   </td>
   <td>
       <a href="#!/details/{{item.id}}">
           <span ng-bind="item.name"></span>
       </a>
   </td>
   <td>
       <a href="#!/details/{{item.id}}">
           <span class="label bg-{{item.type1}}" ng-bind="item.type1"></span>
           <span class="label bg-{{item.type2}}" ng-bind="item.type2"></span>
       </a>
   </td>
</tr>

Obs: Para visualizar essa listagem renderizada é só clicar aqui.

Vamos pegar esses resultados da seguinte forma:

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

Com a listagem em mãos, já podemos começar a trabalhar com esses dados. Para isso, vamos ver os principais métodos para manipulação de listas dos Protractor:

Filter

Bem, como o próprio nome sugere, com esse método é possível filtrarmos um resultado. Utilizá-lo é bem simples, veja um exemplo:

resultados.filter(function(elem, index) {
     elem.getText().then(function(txt){
       console.log(txt)
     });
     return elem.element(by.binding('item.name')).getText().then(function(txt){
       return txt === "Mew";
       });
   }).first().element(by.css('tr > td > a')).click();

O filter recebe dois parâmetros: o elemento (que nesse nosso exemplo serão as linhas da listagem, ou seja, as TRs da tabela) e o índice. Nesse exemplo ainda tem um detalhe interessante, um encadeamento de elementos, ou seja, fazemos uma “pesquisa” dentro de outro elemento.

A partir do elemento que recebemos como parâmetro (a TR) realizamos uma nova “pesquisa” para encontrarmos um elemento que tenha a diretiva ng-bind (que aprendemos como manipular nesse artigo aqui). Em seguida, pegamos o valor deste elemento e comparamos com um resultado que esperamos. No fim, dentro do elemento encontrado, realizamos a ação de click.

Obs: Para deixar mais claro, deixei propositalmente um console.log do elemento que recebemos como parâmetro para entender o que está acontecendo. Neste caso, o resultado desse log será o seguinte:

  • #1 Bulbasaur grama veneno
  • #6 Charizard fogo voador
  • #38 Ninetales fogo
  • #150 Mewtwo psiquico
  • #151 Mew psiquico

Get

O Get é um método bem tranquilo de entender e provavelmente você já deve utilizá-lo. O get retorna um elemento pelo índice passado como parâmetro. Por exemplo:

resultados.get(3).element(by.binding('item.name')).getText().then(function(val){
     console.log(val);
   });

Aqui estamos acessando o elemento na posição de número 4 da nossa listagem e em seguida utilizamos a técnica de encadeamento de elementos para encontrarmos o texto do nome do pokémon.

O resultado será Mewtwo

First

Similar ao Get, mas retorna o primeiro item da lista.

resultados.first().element(by.binding('item.name')).getText().then(function(val){
     console.log(val);
   });

O resultado será Bulbasaur

Last

Retorna o último item da lista.

resultados.last().element(by.binding('item.name')).getText().then(function(val){
     console.log(val);
   });

O resultado será Mew

Each

Esse método é utilizado quando queremos iterar em uma lista:

resultados.each(function(elem, index) {
       return elem.element(by.binding('item.name')).getText().then(function(txt){
         console.log(index, txt)
         });
     });

O resultado será:

  • 0 ‘Bulbasaur’
  • 1 ‘Charizard’
  • 2 ‘Ninetales’
  • 3 ‘Mewtwo’
  • 4 ‘Mew’

MAP

Com esse método podemos montar um objeto chave-valor, da seguinte maneira:

consultarPokemons(){
      return resultados.map(function(elem, index){
     return {
         indice : index,
         nome : elem.element(by.binding('item.name')).getText()
     }
   });
  }

E poderíamos validar esse resultado em nosso teste, dessa forma:

const lista =  listagemPage.consultarPokemons();
expect(lista).toEqual([
     { indice: 0, nome: 'Bulbasaur' },
     { indice: 1, nome: 'Charizard' },
     { indice: 2, nome: 'Ninetales' },
     { indice: 3, nome: 'Mewtwo' },
     { indice: 4, nome: 'Mew' }

Reduce

O reduce é utilizado quando queremos obter um valor acumulado ou fazer algum tipo de operação com todos os elementos, como concatenar os valores da lista. No exemplo, o reduce recebe como parâmetro uma função de callback com o valor acumulado e o elemento (que no nosso caso é a TR):

return this.resultados.reduce(function(valorAcumulado, elemento){
     return elemento.element(by.binding('item.name')).getText().then(function(txt){
         console.log('acc: '+  valorAcumulado + ' txt ' +txt);
         return valorAcumulado + ', ' + txt ;
       });

     }, 'Todos Pokemons: ');

O resultado do console.log será o seguinte:

  • acc: Todos Pokemons: txt: Bulbasaur
  • acc: Todos Pokemons: , Bulbasaur txt: Charizard
  • acc: Todos Pokemons: , Bulbasaur, Charizard txt: Ninetales
  • acc: Todos Pokemons: , Bulbasaur, Charizard, Ninetales txt: Mewtwo
  • acc: Todos Pokemons: , Bulbasaur, Charizard, Ninetales, Mewtwo txt: Mew

O Protractor oferece muitas opções para manipular listas, como pudemos observar. Com ele, é possível economizar muito trabalho! Saber em que situação utilizar cada um desses métodos é muito importante e ajuda muito no dia a dia. Portanto, entenda bem quando e como podemos utilizá-lo, isso deve te poupar algumas dores de cabeça.

Até a próxima!

***

Este artigo foi publicado originalmente em: https://www.concrete.com.br/2018/01/04/manipulacao-de-listas-com-protractor/

Líder do capítulo de QA na Concrete, Cássio Alves é formado em Ciência da Computação e em adestramento de cães. Nas horas vagas está cozinhando ou ensinando um truque novo para as cachorras dele, muitas das vezes na praia.

Ver perfil