Seu primeiro tutorial do aplicativo AngularJS Parte 2: Ferramentas para andaimes, construção e teste

Publicados: 2022-03-11

Introdução

Com as muitas ferramentas disponíveis para auxiliar no desenvolvimento de aplicações AngularJS, muitas pessoas têm a impressão de que é um framework extremamente complicado, o que não é o caso. Essa é uma das principais razões pelas quais comecei esta série de tutoriais.

Na primeira parte, abordamos o básico do framework AngularJS e começamos escrevendo nosso primeiro aplicativo. Este post foi desenvolvido para iniciantes. Se você é um desenvolvedor AngularJS mais experiente, pode estar mais interessado em desmistificar diretivas ou uma história de AngularJS em uso em uma startup em crescimento.

Neste tutorial, vamos deixar de lado a camada lógica do aplicativo e aprender como conduzir a configuração adequada do projeto AngularJS, incluindo scaffolding, gerenciamento de dependências e prepará-lo para testes (unidade e ponta a ponta). Faremos isso usando essas ferramentas AngularJS: Yeoman, Grunt e Bower. Em seguida, revisaremos o processo de escrita e execução de testes do Jasmine usando o Karma.

Karma, Jasmine, Grunt, Bower, Yeoman… Quais são todas essas ferramentas?

Existem muitas ferramentas de desenvolvimento para ajudar no scaffolding do AngularJS, testando o AngularJS e construindo um aplicativo corretamente.

Se você trabalha com JavaScript, é muito provável que já conheça pelo menos algumas dessas ferramentas, mesmo que seja novo no Angular. Mas, para ajudar a garantir uma linha de base comum, evitarei fazer suposições. Vamos revisar brevemente cada uma dessas tecnologias e para que elas são úteis:

  • Karma (anteriormente conhecido como Testacular) é o executor de testes JavaScript do Google e a escolha natural para testar o AngularJS. Além de permitir que você execute seus testes em navegadores reais (incluindo navegadores de telefone/tablet), também é agnóstico de estrutura de teste ; o que significa que você pode usá-lo em conjunto com qualquer framework de teste de sua escolha (como Jasmine, Mocha ou QUnit, entre outros).

  • Jasmine será nosso framework de teste de escolha, pelo menos para este post. Sua sintaxe é bem parecida com a do RSpec, se você já trabalhou com isso. (Se você não tiver, não se preocupe; vamos verificar com mais detalhes posteriormente neste tutorial.)

  • Grunt é um executor de tarefas que ajuda a automatizar várias tarefas repetitivas, como minificação, compilação (ou compilação), teste e configuração de uma visualização do seu aplicativo AngularJS.

  • Bower é um gerenciador de pacotes que ajuda você a encontrar e instalar todas as dependências do seu aplicativo, como estruturas CSS, bibliotecas JavaScript e assim por diante. Ele roda sobre o git, bem como o empacotador Rails, e evita a necessidade de baixar e atualizar manualmente as dependências.

  • Yeoman é um conjunto de ferramentas contendo 3 componentes principais: Grunt, Bower e a ferramenta de andaimes Yo. Yo gera código clichê com a ajuda de geradores (que são apenas modelos de andaimes) e configura automaticamente o Grunt e o Bower para o seu projeto. Você pode encontrar geradores para quase qualquer framework JavaScript (Angular, Backbone, Ember, etc.), mas como estamos focando aqui no Angular, vamos usar o projeto generator-angular.

Então por onde começamos?

Bem, a primeira coisa que precisamos fazer é instalar as ferramentas que vamos precisar.

Se você ainda não tem git, node.js e npm instalados, vá em frente e instale-os.

Em seguida, iremos para a linha de comando e executaremos o seguinte comando para instalar as ferramentas do Yeoman:

 npm install -g yo grunt-cli bower

Ah, e não se esqueça, vamos usar o gerador AngularJS, então você precisará instalá-lo também:

 npm install -g generator-angular

OK, agora estamos prontos para…

Scaffold/gerar nosso aplicativo AngularJS

Da última vez, pegamos emprestado manualmente nosso código clichê do projeto angular-seed. Desta vez, vamos deixar yo (em conjunto com generator-angular) fazer isso por nós.

Tudo o que precisamos fazer é criar nossa nova pasta de projeto, navegar até ela e executar:

 yo angular

Serão apresentadas algumas opções, como incluir ou não o Bootstrap e o Compass. Por enquanto, digamos não ao Compass e sim ao Bootstrap. Então, quando solicitado sobre quais módulos incluir (recurso, cookies, sanitização e rota), selecionaremos apenas angular-route.js .

Nosso scaffold de projeto já deve ser criado (pode demorar um minuto), integrado ao Karma e todo pré-configurado.

Observação: lembre-se de que estamos restringindo os módulos aqui aos que usamos no aplicativo que construímos na parte um deste tutorial. Quando você estiver fazendo isso para seu próprio projeto, caberá a você determinar quais módulos você precisará incluir.

Agora, já que vamos usar o Jasmine, vamos adicionar o adaptador karma-jasmine ao nosso projeto:

 npm install karma-jasmine --save-dev

Caso queiramos que nossos testes sejam executados em uma instância do Chrome, vamos adicionar também o karma-chrome-launcher :

 npm install karma-chrome-launcher --save-dev

OK, se fizemos tudo certo, nossa árvore de arquivos do projeto agora deve ficar assim:

Uma árvore de arquivos de projeto de amostra usando essas ferramentas AngularJS terá esta aparência.

Nosso código de aplicativo estático vai para o diretório app/ e o diretório test/ conterá (sim, você adivinhou!) nossos testes. Os arquivos que vemos na raiz são nossos arquivos de configuração do projeto. Há muito a ser aprendido sobre cada um deles, mas por enquanto vamos ficar com a configuração padrão. Então vamos rodar nosso aplicativo pela primeira vez, o que podemos fazer simplesmente com o seguinte comando:

 grunt serve

E voilá! Nosso aplicativo agora deve aparecer na nossa frente!

Um pouco sobre Bower para AngularJS

Antes de entrar na parte realmente importante (ou seja, o teste), vamos tirar um minuto para aprender um pouco mais sobre Bower. Como mencionado anteriormente, Bower é nosso gerenciador de pacotes. Adicionar uma lib ou plugin ao nosso projeto pode ser feito simplesmente usando o comando bower install . Por exemplo, para incluir modernizr , tudo o que precisamos fazer é o seguinte (dentro do nosso diretório do projeto, é claro):

 bower install modernizr

Observe, no entanto, que, embora isso torne o modernizr parte do nosso projeto (ele estará localizado no diretório app/bower_components ), ainda somos responsáveis ​​por incluí-lo em nosso aplicativo (ou gerenciar quando ele deve ser incluído), pois precisaríamos a ver com qualquer lib adicionada manualmente. Uma maneira de fazer isso seria simplesmente adicionar a seguinte tag <script> ao nosso index.html :

 <script src="bower_components/modernizr/modernizr.js"></script>

Como alternativa, podemos usar o arquivo bower.json para gerenciar nossas dependências. Depois de seguir cuidadosamente todas as etapas até agora, o arquivo bower.json deve ficar assim:

 { "name": "F1FeederApp", "version": "0.0.0", "dependencies": { "angular": "1.2.15", "json3": "~3.2.6", "es5-shim": "~2.1.0", "jquery": "~1.11.0", "bootstrap": "~3.0.3", "angular-route": "1.2.15" }, "devDependencies": { "angular-mocks": "1.2.15", "angular-scenario": "1.2.15" } }

A sintaxe é bastante autoexplicativa, mas mais informações estão disponíveis aqui.

Podemos então adicionar quaisquer novas dependências adicionais que desejarmos e, em seguida, tudo o que precisamos é o seguinte comando para instalá-las:

 bower install

Agora vamos escrever alguns testes!

OK, agora é hora de realmente continuar de onde paramos na primeira parte e escrever alguns testes para nosso aplicativo AngularJS.

Mas primeiro, há um pequeno problema que precisamos resolver: Embora os desenvolvedores do generator-angular tenham baseado seu modelo de projeto no projeto angular-seed (que é o clichê oficial do Angular), por algum motivo que eu realmente não entendo, eles decidiram para alterar as convenções de nomenclatura da pasta do app (alterando css para styles , js para scripts e assim por diante).

Como resultado, o aplicativo que escrevemos originalmente agora tem caminhos inconsistentes com o scaffold que acabamos de gerar. Para contornar isso, vamos baixar o código do aplicativo daqui e trabalhar com essa versão a partir de agora (é basicamente o mesmo aplicativo que escrevemos originalmente, mas com os caminhos atualizados para corresponder à nomenclatura do gerador-angular).

Após baixar o aplicativo, navegue até a pasta tests/spec/controllers e crie um arquivo chamado drivers.js contendo o seguinte:

 describe('Controller: driversController', function () { // First, we load the app's module beforeEach(module('F1FeederApp')); // Then we create some variables we're going to use var driversController, scope; beforeEach(inject(function ($controller, $rootScope, $httpBackend) { // Here, we create a mock scope variable, to replace the actual $scope variable // the controller would take as parameter scope = $rootScope.$new(); // Then we create an $httpBackend instance. I'll talk about it below. httpMock = $httpBackend; // Here, we set the httpBackend standard reponse to the URL the controller is // supposed to retrieve from the API httpMock.expectJSONP( "http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK").respond( {"MRData": {"StandingsTable": {"StandingsLists" : [{"DriverStandings":[ { "Driver": { "givenName": 'Sebastian', "familyName": 'Vettel' }, "points": "397", "nationality": "German", "Constructors": [ {"name": "Red Bull"} ] }, { "Driver": { "givenName": 'Fernando', "familyName": 'Alonso' }, "points": "242", "nationality": "Spanish", "Constructors": [ {"name": "Ferrari"} ] }, { "Driver": { "givenName": 'Mark', "familyName": 'Webber' }, "points": "199", "nationality": "Australian", "Constructors": [ {"name": "Red Bull"} ] } ]}]}}} ); // Here, we actually initialize our controller, passing our new mock scope as parameter driversController = $controller('driversController', { $scope: scope }); // Then we flush the httpBackend to resolve the fake http call httpMock.flush(); })); // Now, for the actual test, let's check if the driversList is actually retrieving // the mock driver array it('should return a list with three drivers', function () { expect(scope.driversList.length).toBe(3); }); // Let's also make a second test checking if the drivers attributes match against // the expected values it('should retrieve the family names of the drivers', function () { expect(scope.driversList[0].Driver.familyName).toBe("Vettel"); expect(scope.driversList[1].Driver.familyName).toBe("Alonso"); expect(scope.driversList[2].Driver.familyName).toBe("Webber"); }); });

Este é o conjunto de testes para nosso driverscontroller . Pode parecer muito código, mas a maior parte é, na verdade, apenas declaração de dados simulada. Vamos dar uma olhada rápida nos elementos realmente importantes:

  • O método describe() define nosso conjunto de testes.
  • Cada it() é uma especificação de teste adequada.
  • Cada função beforeEach() é executada imediatamente antes de cada um dos testes.

O elemento mais importante (e potencialmente confuso) aqui é o serviço $httpBackend que instanciamos na variável httpMock . Esse serviço atua como um back-end falso e responde às nossas chamadas de API nas execuções de teste, assim como nosso servidor real faria em produção. Nesse caso, usando a função expectJSONP() , configuramos para interceptar qualquer solicitação JSONP para a URL fornecida (a mesma que usamos para obter as informações do servidor) e, em vez disso, retornamos uma lista estática com três drivers, imitando o resposta real do servidor. Isso nos permite saber com certeza o que deve retornar do controlador. Podemos, portanto, comparar os resultados com os esperados, usando a função expect() . Se eles corresponderem, o teste será aprovado.

A execução dos testes é feita simplesmente com o comando:

 grunt test

O conjunto de testes para o controlador de detalhes do driver ( drivercontroller ) deve ser bastante semelhante ao que acabamos de ver. Eu recomendo que você tente descobrir por si mesmo como um exercício (ou você pode dar uma olhada aqui, se você não estiver apto).

E quanto aos testes AngularJS de ponta a ponta?

A equipe Angular introduziu recentemente um novo runner para testes de ponta a ponta chamado Protractor. Ele usa o webdriver para interagir com o aplicativo em execução no navegador e também usa a estrutura de teste Jasmine por padrão, portanto, a sintaxe será altamente consistente com a de nossos testes de unidade.

Como o Protractor é uma ferramenta relativamente nova, sua integração com a pilha Yeoman e generator-angular ainda requer uma boa quantidade de trabalho de configuração. Com isso em mente, e minha intenção de manter este tutorial o mais simples possível, meu plano é dedicar um post futuro exclusivamente para cobrir os testes de ponta a ponta em AngularJS em profundidade.

Conclusão

Neste ponto da série de tutoriais, aprendemos como estruturar nosso aplicativo Angular com yo , gerenciar suas dependências com bower e escrever/executar alguns testes usando karma e protractor . Tenha em mente, porém, que este tutorial é apenas uma introdução a essas ferramentas e práticas do AngularJS; não analisamos nenhum deles aqui com grande profundidade.

Nosso objetivo foi simplesmente ajudá-lo a começar neste caminho. A partir daqui, cabe a você continuar e aprender tudo o que puder sobre essa incrível estrutura e conjunto de ferramentas.

Adendo: Algumas notas (importantes) do autor

Depois de ler este tutorial, algumas pessoas podem perguntar: “Espere. Você não deveria fazer tudo isso antes de começar a codificar seu aplicativo? Isso não deveria ter sido a primeira parte deste tutorial?”

Minha resposta curta para isso é não . Como vimos na primeira parte, você não precisa saber tudo isso para codificar seu primeiro aplicativo Angular. Em vez disso, a maioria das ferramentas que discutimos neste post foi projetada para ajudá-lo a otimizar seu fluxo de trabalho de desenvolvimento e praticar o Desenvolvimento Orientado a Testes (TDD).

E por falar em TDD, o conceito mais básico de TDD é certamente sólido; ou seja, escreva seus testes antes de escrever seu código. Algumas pessoas, no entanto, levam esse conceito longe demais. TDD é uma prática de desenvolvimento, não um método de aprendizagem. Assim, escrever seus testes antes de escrever seu código faz muito sentido, enquanto aprender a escrever seus testes antes de aprender a codificar não faz.

Pessoalmente, acho que essa é a principal razão pela qual os tutoriais oficiais do Angular podem parecer tão complicados e podem ser quase impossíveis de seguir para pessoas sem experiência anterior em MVC / TDD em front-end. Essa é uma das principais razões pelas quais eu comecei esta série de tutoriais.

Meu conselho pessoal para aqueles que estão aprendendo a navegar no mundo AngularJS é: Não seja muito duro consigo mesmo. Você não precisa aprender tudo de uma vez (apesar das pessoas dizerem o contrário!). Dependendo de sua experiência anterior com outros frameworks de front-end/teste, o AngularJS pode ser bem difícil de entender inicialmente. Portanto, aprenda tudo o que você precisa aprender até ser capaz de escrever seus próprios aplicativos simples e, quando estiver confortável com o básico da estrutura, poderá se preocupar em selecionar e aplicar as práticas de desenvolvimento de longo prazo que funcionam melhor para tu.

Claro, essa é minha humilde opinião e nem todo mundo vai concordar com essa abordagem (e a equipe de desenvolvimento Angular pode enviar um assassino contratado atrás de mim assim que eu publicar isso), mas essa é a minha visão e tenho certeza de que muitas pessoas lá fora quem vai concordar comigo.

Relacionado: Tutorial Angular 6: Novos recursos com novo poder