E2E Testing En Angular 2 De Cero A Héroe (Parte Final)
Estimados futuros Maestros de Angular 2 E2E Testing.
Esto es todo. Al final de esta lección finalmente tendrás todas las herramientas para crear pruebas funcionales para tus aplicaciones de Angular 2. Ya no hay excusas:
Primero nos familiarizaremos con los Locators, luego veremos lo impresionante que pueden ser los Page Objects, seguido de cómo manejar la asincronía y finalmente la parte más fácil que es el triggering de Actions.
Si no tienes lo básico bien, dirígete allí, de lo contrario estarás un poco perdido.
Localizadores
Una de las cosas más importantes en las pruebas E2E, si no la más importante, es encontrar los elementos que quieres probar en tu vista. La mayoría de las veces, te preguntarás «¿por qué no puedo encontrar este elemento ****?» seguido de un «oooohhhhh».
Tienes muchas formas de hacerlo. La mayoría de ellas dependen de tu aplicación. Para obtener tus elementos, utilizarás una serie de localizadores. La mayoría de las veces, usted puede encontrar sus elementos por:
- Nombre de la clase.
- Id.
- Modelo.
- Binding.
Para las próximas pruebas, vamos a utilizar esta plantilla.html:
<div class="parent2"> <div class="parent1"> <div class="nested-class" style="color:blue;"> I am a nested element </div> </div></div>
Centrémonos en nested-class y nested-id.
By Class:
Agarramos aquí nuestro elemento usando element(by.css(selector)) y luego comprobamos si está presente o no.
Por Id:
it("should find the nested id", () => { let elem = element(by.id("nested-id")); expect(elem.getText()).toBe("I am a nested element");});
Agarramos aquí nuestro elemento usando element(by.id(elem-id)) y luego comprobamos si está presente o no.
Los siguientes localizadores son muy útiles en AngularJS pero aún no están implementados en Angular 2 así que por ahora mantenlos al margen.
Por Modelo:
it("should find the model", () => { let elem = element(by.model("modelToFind")); expect(elem.isPresent()).toBeTruthy();});
Por Bindings:
it("should find the binding", () => { let elem = element(by.model("bindingToFind")); expect(elem.isPresent()).toBeTruthy();});
Para depurar tus tests, puedes simplemente añadir «browser.pause()» en tu test, podrás ejecutar todas las instrucciones anteriores y parar donde quieras.
Una vez que llegue a su pausa, tendrá una pantalla similar a esta:
Como puede ver en esta imagen, para entrar en el asiento del conductor necesita escribir repl.
Ahora digamos que no tiene ninguna prueba y sólo quiere jugar con Protractor. Puedes simplemente escribir en tu terminal:
protractor --elementExplorer
Si tienes algunos problemas con tu ruta, puedes escribir:
./node_modules/protractor/bin/elementexplorer.js
¡No necesitas escribir repl esta vez, sólo usa el objeto browser y estás listo para navegar!
Objetos de página
¿Y si tienes pruebas que comparten el mismo escenario? Vas a copiar y pegar tu código en todas partes? ¿Y si este escenario cambia? Ahora tienes que ir a través de cada archivo y hacer las modificaciones.
Ahí es donde los Objetos de Páginas se vuelven muy útiles. Escribir una vez, compartir en todas partes!
Un Objeto de Página es un objeto que contiene los elementos y escenarios relativos a una página.
Primero un Page Object muy simple:
export class HomePage { nestedClass; constructor() { this.nestedClass = element(by.css(".nested-class")); }}
Luego lo usamos en nuestra prueba:
Importamos el Page Object, creamos una instancia y luego usamos su propiedad.
Aventuras asíncronas
Ahora mis amigos, ¡puedes acceder a cualquier elemento de tu página! Quiero decir casi :).
Habrá algunos casos especiales.
Si tuviste la (des)suerte de trabajar con jQuery, debes estar familiarizado con document.ready().
Por la naturaleza asíncrona de JavaScript, habrá casos en los que intentarás acceder a un elemento antes de que aún haya aparecido en la página.
Para manejar eso, tendrás que usar una característica de Protractor para esperar a que tu elemento esté listo antes de buscarlo.
Aquí hay un ejemplo que muestra un botón después de un tiempo de expiración.
Primero la clase que contiene el timeout:
export class Home { isHidden = true; triggerTimeOut = ((){ setTimeout(() => this.isHidden = false, 2250) })}
Luego la plantilla.html:
Tenemos aquí un botón que disparará nuestro timeout, una vez que el timeout expira, se muestra el texto.
Aquí están las pruebas.
Encontramos nuestro botón, hacemos clic en él, intentamos encontrar nuestro texto PERO esperamos que no esté presente.
Y aquí está la forma de manejar este caso ;).
Usamos «browser.wait» combinado con «browser.isElementPresent» probando nuestro Locator. Después de 5 segundos se ejecuta el resto del código. ¡No te olvides de poner un temporizador aquí, de lo contrario tus pruebas se bloquearán para siempre!
Así que si uno de tus elementos se supone que está aquí pero no lo consigues, tu instinto debería decirte que recuerdes lo que acabas de leer aquí.
Acciones
Ahora que tienes tu preciado elemento, ¡has hecho el 90% del trabajo!
Si no lo encuentras, es que tu aplicación no funciona como debería (para eso hacemos pruebas) o necesitas mejorar en las pruebas y pasar menos tiempo en Pokemon GO cazando dratinis cerca de un río a la 1 de la madrugada (todos hemos pasado por eso…).
Continuemos con las acciones que puedes utilizar sobre un elemento. Aquí están:
Estamos usando Protractor que se apoya en WebDriver. Si necesitas acciones más rebuscadas, puedes echar un vistazo a lo que hay disponible aquí.
Vamos a probar algunas de ellas.
Para la plantilla.html:
<input type="text" />
Jugaremos un poco con la entrada de texto. Prueba rápida, ¿qué hace esta prueba (no leas la descripción)?
Solución: Obtenemos nuestro input, escribimos «Some text» dentro, probamos que tenemos el valor establecido, lo borramos y finalmente probamos que el valor está vacío.
Legítimamente podemos preguntarnos ¿cuál es la mejor forma de disparar acciones? Este enlace muestra uno de los defectos de usar JavaScript en lugar de WebDriver.
Claro que escribir en JavaScript es mucho más compacto pero conlleva algunos riesgos.
Puedes hacer cualquier cosa que quieras con un elemento. La mejor manera de probarlo es usar los matchers que están disponibles. ¿Por qué? Porque son elegantes y cercanos al lenguaje humano, ejemplo:
expect(apples.length !== 0).toBe(true);
expect(apples).not.toBeEmpty();
Conclusión
Este ha sido el último post de esta serie, ahora mismo tienes el 90% de los conocimientos para probar tus aplicaciones de Angular 2. El otro 10% lo conseguirás con la experiencia. Recuerda, primero obtener tus elementos usando Locators, luego poner el que podría ser replicado en un Page Object, si no encuentras tu elemento y estás seguro de que está aquí, podría ser porque aún no ha aparecido y necesitas manejar la asincronía. Finalmente pruebe el **** fuera de sus elementos con Actions.