Las pruebas EndToEnd son de gran utilidad ya que garantiza que la aplicación hace lo que tiene que hacer, y además ayuda mucho a automatizar tareas que de otra forma llevaría mucho tiempo si se realiza de forma manual.
La herramienta con la que vamos a realizar este tipo de pruebas (y que viene por defecto en Angular-cli) se llama Protractor, y nos permite programar la interacción con el navegador como si fuésemos un usuario.
Imaginemos un formulario que tiene bastantes campos y tenemos que testear su comportamiento. Realizar esto de manera manual lleva tiempo y es tedioso, y en este punto (y en otros muchos) es donde Protractor nos puede ahorrar mucho tiempo...y es lo que vamos a ver en la entrada de hoy. Vamos a crear un típico formulario de un pedido de un producto y veremos como hacer el testeo del mismo.
Por simplificar vamos a crear un formulario con 4 campos. En una situación "real" con muchos más campos el ahorro de esfuerzo al usar Protractor sería mucho mayor. En cualquier caso haciendo pruebas end to end nos aseguramos de que el componente se comporta como se espera.
Nuestro app.component es muy sencillo (he obviado temas de css, y no he usado reactiveForms por centrar la atención en las pruebas) y tiene el siguiente aspecto:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h3>Formulario de pedido</h3>
Producto: <select id="producto" [(ngModel)]="producto">
<option value="">Seleccionar</option>
<option value="1">Producto-1</option>
<option value="2">Producto-2</option>
<option value="3">Producto-3</option>
</select><br>
Cantidad: <input type="text" id="cantidad" [(ngModel)]="cantidad"><br>
Email: <input type="email" id="email" [(ngModel)]="email">
<input type="checkbox" [(ngModel)]="chkTerminos" id="chkTerminos"> He leido los términos y condiciones<br>
<button [disabled]="!chkTerminos" id="btnSend">Solicitar producto</button>
`
})
export class AppComponent {
chkTerminos: false;
producto = '';
cantidad: number = null;
email = '';
}
Hay un botón de "Solicitar producto" que se habilita únicamente si se ha marcado el checkbox de "He leido las condiciones...."
En una situación "real" no habilitaríamos el botón si el email no es válido, si la cantidad no es válida o si no se ha seleccionado un producto, pero para hacernos una idea de uso, vamos a chequear únicamente que se haya marcado el checkbox.
La carpeta donde se encuentran las pruebas que angular nos crea por defecto, y donde dejaremos las nuestras es la carpeta e2e.
Dentro de esta carpeta nos encontramos el fichero app.e2e-spec.ts y el fichero app.po.ts además del fichero de configuración de Protractor.
Si abrimos el fichero app.e2e-spec.ts veremos que tiene una sintaxis similar al de las pruebas unitarias con karma-jasmine. Tiene un "describe" que es un agrupador de pruebas sobre algo concreto (en las pruebas end-to-end normalmente es un describe por página) y dentro del describe es donde meteremos los "it" que queremos testar.
Si ejecutamos las pruebas con el comando ng e2e veremos que fallan (se abrirá el navegador, hace una interacción muy rápida y se vuelve a cerrar mostrando el resultado en la terminal). Y fallan porque la prueba que nos trae por defecto es la siguiente:
it('should display message saying app works', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('app works!');
});
y nosotros hemos quitado el mensaje de "app works" que es lo que la prueba espera obtener.
En el código anterior, la instancia de la pagina llama al método navigateTo() que esta dentro del fichero app.po.ts como veremos posteriormente. Una vez que la página se ha dirigido a la ruta establecida en dicho metodo, llama al método getParagraphText() que obtiene un elemento cuyo selector es especificado y devuelve el texto de dicho elemento, y comprueba (espera) que el texto devuelto sea igual a "app works!"
Vamos a crear una prueba a modo de ejemplo que nos indique que el título de la página se muestra correctamente, pero antes de eso vamos a explicar brevemente algunos cosas:
Junto al fichero app.e2e-spec.ts se encuentra el fichero app.po.ts. Este fichero (tendremos un fichero .po.ts por cada página que queremos testear) contiene los métodos mencionados anteriormente y todos aquellos métodos que nosotros queramos añadir para nuestras validaciones.
En nuestro ejemplo el fichero app.po.ts, (correspondiente al app.component) tiene el siguiente aspecto:
import { browser, element, by } from 'protractor';
export class HomePage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('h3')).getText();
}
}
Como hemos comentado inicialmente consta de dos métodos. uno para "navegar" a la url especificada (en nuestro ejemplo a la ruta raíz) y otro que viene por defecto que es el getParagraphText que devuelve el texto del selector css especificado, es decir, en este ejemplo el "h3" que contiene el título del formulario.
Si ahora en la página app.e2e-spec.ts creamos un método "it" como el que sigue a continuación (y eliminamos el que había anteriormente ya que fallaba) y lanzamos el test de nuevo (ng e2e) debería devolver un resultado satisfactorio.
it('should display form title', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Formulario de pedido');
});
Hasta aquí únicamente hemos comprobado que la página contiene un título que es el que nosotros esperamos. Vamos a ver ahora como podemos validar el formulario.
En primer lugar crearemos un método como el siguiente:
submitForm() {
element(by.cssContainingText('option', 'Producto-1')).click();
element(by.css('input[id="cantidad"]')).sendKeys('2');
element(by.css('input[id="email"]')).sendKeys('jorgetriguerosfalque@gmail.com');
element(by.css('[id="chkTerminos"]')).click();
element(by.css('[id="btnSend"]')).click();
}
Este método selecciona la opción del despegable "Producto-1" y hace clic sobre ella.
Selecciona el elemento input cuyo id="cantidad" y escribe sobre él el número 2
Selecciona el elemento email cuyo id="email" y escribe sobre él un email.
Selecciona el elemento cuyo id="chkTerminos" y hace clic sobre el, es decir, marca el checkbox, y por último, hacemos click en el botón (esto es posible porque previamente hemos seleccionado el checkbox, si no no estaría habilitado)
Sólo nos queda crear el "it" en la página app.e2e-spec.ts:
it('should Show button when checkbox is checked', () => {
page.navigateTo();
page.submitForm();
});
Si lanzamos las pruebas (ng e2e) veremos como se levanta una instancia del navegador y se cumplimenta el formulario con los datos que hemos establecido y se procede a la pulsación del botón de envío.
En el siguiente pantallazo se observa como las pruebas han sido satisfactorias.
Código fuente disponible: https://github.com/jorgetrigueros/ng4-protractor-forms-test