Tu primer tutorial de la aplicación AngularJS Parte 2: herramientas para andamiaje, construcción y prueba

Publicado: 2022-03-11

Introducción

Con las muchas herramientas disponibles para ayudar en el desarrollo de aplicaciones AngularJS, muchas personas tienen la impresión de que es un marco extremadamente complicado, lo cual no es el caso en absoluto. Esa es una de las principales razones por las que comencé esta serie de tutoriales.

En la primera parte, cubrimos los conceptos básicos del marco AngularJS y comenzamos escribiendo nuestra primera aplicación. Esta publicación está diseñada para principiantes. Si es un desarrollador de AngularJS con más experiencia, es posible que le interese más desmitificar las directivas o una historia de AngularJS en uso en una startup en crecimiento.

En este tutorial, dejaremos de lado la capa lógica de la aplicación y aprenderemos cómo realizar la configuración adecuada del proyecto AngularJS, incluido el andamiaje, la administración de dependencias y la preparación para la prueba (tanto unitaria como de extremo a extremo). Haremos esto usando estas herramientas de AngularJS: Yeoman, Grunt y Bower. Luego, revisaremos el proceso de escribir y ejecutar pruebas de Jasmine usando Karma.

Karma, Jasmine, Grunt, Bower, Yeoman… ¿Qué son todas estas herramientas?

Hay tantas herramientas de desarrollo para ayudar en el andamiaje de AngularJS, probar AngularJS y construir una aplicación correctamente.

Si trabaja con JavaScript, es muy probable que ya conozca al menos algunas de estas herramientas, incluso si es nuevo en Angular. Pero para ayudar a garantizar una línea de base común, evitaré hacer suposiciones. Repasemos brevemente cada una de estas tecnologías y para qué sirven:

  • Karma (anteriormente conocido como Testacular) es el ejecutor de pruebas de JavaScript de Google y la elección natural para probar AngularJS. Además de permitirle ejecutar sus pruebas en navegadores reales (incluidos los navegadores de teléfonos/tabletas), también es independiente del marco de prueba ; lo que significa que puede usarlo junto con cualquier marco de prueba de su elección (como Jasmine, Mocha o QUnit, entre otros).

  • Jasmine será nuestro marco de prueba de elección, al menos para esta publicación. Su sintaxis es bastante similar a la de RSpec, si alguna vez has trabajado con eso. (Si no lo ha hecho, no se preocupe; lo revisaremos con mayor detalle más adelante en este tutorial).

  • Grunt es un ejecutor de tareas que ayuda a automatizar varias tareas repetitivas, como minificación, compilación (o creación), pruebas y configuración de una vista previa de su aplicación AngularJS.

  • Bower es un administrador de paquetes que lo ayuda a encontrar e instalar todas las dependencias de su aplicación, como marcos CSS, bibliotecas JavaScript, etc. Se ejecuta sobre git, al igual que Rails bundler, y evita la necesidad de descargar y actualizar manualmente las dependencias.

  • Yeoman es un conjunto de herramientas que contiene 3 componentes principales: Grunt, Bower y la herramienta de andamiaje Yo. Yo genera código repetitivo con la ayuda de generadores (que son solo plantillas de andamiaje) y configura automáticamente Grunt y Bower para su proyecto. Puede encontrar generadores para casi cualquier marco de JavaScript (Angular, Backbone, Ember, etc.), pero como nos estamos enfocando aquí en Angular, usaremos el proyecto generator-angular.

¿Así que por dónde empezamos?

Bien, lo primero que tendremos que hacer es instalar las herramientas que vamos a necesitar.

Si aún no tiene instalados git, node.js y npm, continúe e instálelos.

Luego iremos a la línea de comando y ejecutaremos el siguiente comando para instalar las herramientas de Yeoman:

 npm install -g yo grunt-cli bower

Ah, y no olvides que vamos a usar el generador AngularJS, por lo que también deberás instalarlo:

 npm install -g generator-angular

Bien, ahora estamos listos para...

Scaffold/generar nuestra aplicación AngularJS

La última vez, tomamos prestado manualmente nuestro código repetitivo del proyecto angular-seed. Esta vez, dejaremos que yo (junto con generator-angular) lo haga por nosotros.

Todo lo que tenemos que hacer es crear nuestra nueva carpeta de proyecto, navegar hasta ella y ejecutar:

 yo angular

Se nos presentarán algunas opciones, como incluir o no Bootstrap y Compass. Por ahora, digamos no a Compass y a Bootstrap. Luego, cuando se nos pregunte qué módulos incluir (recurso, cookies, desinfección y ruta), seleccionaremos solo angular-route.js .

Nuestro andamio de proyecto ahora debe estar creado (puede tomar un minuto), integrado con Karma y todo preconfigurado.

Nota: tenga en cuenta que estamos restringiendo los módulos aquí a los que usamos en la aplicación que construimos en la primera parte de este tutorial. Cuando esté haciendo esto para su propio proyecto, dependerá de usted determinar qué módulos necesitará incluir.

Ahora, como vamos a usar Jasmine, agreguemos el adaptador karma-jasmine a nuestro proyecto:

 npm install karma-jasmine --save-dev

En caso de que queramos que nuestras pruebas se ejecuten en una instancia de Chrome, agreguemos también karma-chrome-launcher :

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

Bien, si hicimos todo bien, nuestro árbol de archivos del proyecto ahora debería verse así:

Un árbol de archivos de proyecto de muestra que usa estas herramientas de AngularJS se verá así.

Nuestro código de aplicación estático va al directorio app/ y el directorio test/ contendrá (¡sí, lo adivinó!) nuestras pruebas. Los archivos que vemos en la raíz son los archivos de configuración de nuestro proyecto. Hay mucho que aprender sobre cada uno de ellos, pero por ahora nos quedaremos con la configuración predeterminada. Entonces, ejecutemos nuestra aplicación por primera vez, lo que podemos hacer simplemente con el siguiente comando:

 grunt serve

¡Y voilá! ¡Nuestra aplicación ahora debería aparecer frente a nosotros!

Un poco sobre Bower para AngularJS

Antes de entrar en la parte realmente importante (es decir, las pruebas), tomemos un minuto para aprender un poco más sobre Bower. Como se mencionó anteriormente, Bower es nuestro administrador de paquetes. Agregar una lib o un complemento a nuestro proyecto se puede hacer simplemente usando el comando bower install . Por ejemplo, para incluir modernizr , todo lo que tenemos que hacer es lo siguiente (dentro de nuestro directorio de proyectos, por supuesto):

 bower install modernizr

Tenga en cuenta, sin embargo, que si bien esto hace que modernizr forme parte de nuestro proyecto (se ubicará en el directorio app/bower_components ), aún somos responsables de incluirlo en nuestra aplicación (o administrar cuándo debe incluirse) según sea necesario. que ver con cualquier lib agregada manualmente. Una forma de hacer esto sería simplemente agregar la siguiente etiqueta <script> a nuestro index.html :

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

Alternativamente, podemos usar el archivo bower.json para administrar nuestras dependencias. Después de seguir cuidadosamente cada paso hasta ahora, el archivo bower.json debería verse así:

 { "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" } }

La sintaxis se explica por sí misma, pero hay más información disponible aquí.

Luego podemos agregar las nuevas dependencias adicionales que queramos, y luego todo lo que necesitamos es el siguiente comando para instalarlas:

 bower install

¡Ahora escribamos algunas pruebas!

Bien, ahora es el momento de continuar desde donde lo dejamos en la primera parte y escribir algunas pruebas para nuestra aplicación AngularJS.

Pero primero, hay un pequeño problema que debemos abordar: aunque los desarrolladores de generator-angular basaron su plantilla de proyecto en el proyecto angular-seed (que es el modelo oficial de Angular), por alguna razón que realmente no entiendo, decidieron para cambiar las convenciones de nomenclatura de las carpetas de la app (cambiar css a styles , js a scripts , etc.).

Como resultado, la aplicación que escribimos originalmente ahora tiene rutas que son inconsistentes con el andamio que acabamos de generar. Para evitar esto, descarguemos el código de la aplicación desde aquí y trabajemos con esa versión a partir de ahora (es casi exactamente la misma aplicación que escribimos originalmente, pero con las rutas actualizadas para que coincidan con la denominación angular del generador).

Después de descargar la aplicación, vaya a la carpeta tests/spec/controllers y cree un archivo llamado drivers.js que contenga lo siguiente:

 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 es el conjunto de pruebas para nuestro controlador de driverscontroller . Puede parecer mucho código, pero la mayor parte es en realidad una declaración de datos simulada. Echemos un vistazo rápido a los elementos realmente importantes:

  • El método describe() define nuestro conjunto de pruebas.
  • Cada it() es una especificación de prueba adecuada.
  • Cada función beforeEach() se ejecuta justo antes de cada una de las pruebas.

El elemento más importante (y potencialmente confuso) aquí es el servicio $httpBackend que creamos en la variable httpMock . Este servicio actúa como un back-end falso y responde a nuestras llamadas API en las ejecuciones de prueba, tal como lo haría nuestro servidor real en producción. En este caso, usando la función expectJSONP() , la configuramos para interceptar cualquier solicitud JSONP a la URL dada (la misma que usamos para obtener la información del servidor) y en su lugar, devuelve una lista estática con tres controladores, imitando la respuesta real del servidor. Esto nos permite saber con certeza qué se supone que debe regresar del controlador. Por tanto, podemos comparar los resultados con los esperados, utilizando la función expect() . Si coinciden, la prueba pasará.

La ejecución de las pruebas se realiza simplemente con el comando:

 grunt test

El conjunto de pruebas para el controlador de detalles del controlador ( drivercontroller ) debería ser bastante similar al que acabamos de ver. Te recomiendo que intentes resolverlo por ti mismo como un ejercicio (o simplemente puedes echar un vistazo aquí, si no estás preparado).

¿Qué pasa con las pruebas de AngularJS de extremo a extremo?

El equipo de Angular introdujo recientemente un nuevo corredor para pruebas de extremo a extremo llamado Protractor. Utiliza webdriver para interactuar con la aplicación que se ejecuta en el navegador y también utiliza el marco de prueba Jasmine de forma predeterminada, por lo que la sintaxis será muy coherente con la de nuestras pruebas unitarias.

Sin embargo, dado que Protractor es una herramienta bastante nueva, su integración con la pila de Yeoman y generator-angular todavía requiere una buena cantidad de trabajo de configuración. Con eso en mente, y mi intención de mantener este tutorial lo más simple posible, mi plan es dedicar una publicación futura exclusivamente a cubrir en profundidad las pruebas de extremo a extremo en AngularJS.

Conclusión

En este punto de la serie de tutoriales, hemos aprendido a montar nuestra aplicación Angular con yo , administrar sus dependencias con bower y escribir/ejecutar algunas pruebas usando karma y protractor . Sin embargo, tenga en cuenta que este tutorial solo pretende ser una introducción a estas herramientas y prácticas de AngularJS; no analizamos ninguno de ellos aquí en gran profundidad.

Nuestro objetivo ha sido simplemente ayudarlo a comenzar por este camino. A partir de aquí, depende de usted continuar y aprender todo lo que pueda sobre este increíble marco y conjunto de herramientas.

Anexo: Algunas notas (importantes) del autor

Después de leer este tutorial, algunas personas pueden preguntar: “Espera. ¿No se supone que debes hacer todo esto antes de comenzar a codificar tu aplicación? ¿No debería haber sido esta la primera parte de este tutorial?

Mi respuesta corta a eso es no . Como vimos en la primera parte, en realidad no necesitas saber todo esto para codificar tu primera aplicación Angular. Más bien, la mayoría de las herramientas que hemos discutido en esta publicación están diseñadas para ayudarlo a optimizar su flujo de trabajo de desarrollo y practicar el desarrollo basado en pruebas (TDD).

Y hablando de TDD, el concepto más básico de TDD es ciertamente sólido; es decir, escriba sus pruebas antes de escribir su código. Algunas personas, sin embargo, llevan ese concepto demasiado lejos. TDD es una práctica de desarrollo, no un método de aprendizaje. En consecuencia, escribir sus pruebas antes de escribir su código tiene mucho sentido, mientras que aprender a escribir sus pruebas antes de aprender a codificar no lo tiene.

Personalmente, creo que esta es la razón principal por la que los tutoriales oficiales de Angular pueden parecer tan complicados y pueden ser casi imposibles de seguir para las personas sin experiencia previa en MVC/TDD de front-end. Esa es una de las razones principales por las que comencé esta serie de tutoriales.

Mi consejo personal para quienes están aprendiendo a navegar por el mundo de AngularJS es: no sean demasiado duros con ustedes mismos. No necesitas aprender todo de una vez (¡a pesar de que la gente te diga lo contrario!). Dependiendo de su experiencia previa con otros marcos de prueba/front-end, AngularJS puede ser bastante difícil de entender inicialmente. Así que aprenda todo lo que necesita aprender hasta que pueda escribir sus propias aplicaciones simples y luego, una vez que se sienta cómodo con los conceptos básicos del marco, puede preocuparse por seleccionar y aplicar las prácticas de desarrollo a largo plazo que funcionan mejor para usted.

Por supuesto, esa es mi humilde opinión y no todos estarán de acuerdo con ese enfoque (y el equipo de desarrollo de Angular puede enviar a un asesino a sueldo una vez que publique esto), pero esa es mi visión y estoy bastante seguro de que hay muchas personas por ahí quién estará de acuerdo conmigo.

Relacionado: Tutorial de Angular 6: Nuevas funciones con nueva potencia