Al finalizar este tutorial el estudiante estará en capacidad de desarrollar pruebas de integración para una aplicación Angular.
La prueba de integración del componente BookListComponent. La Figura 1 presenta la vista del componente que se va a probar.
Figura 1. Aplicación en ejecución |
Es necesario que conozca:
En la aplicación de ejemplo el componente BookListComponente
inyecta un servicio que conecta por medio de HTTP a un backend
, guarda los datos en la variable books
, y usa estos datos para mostrar en la vista un conjunto de imágenes que representan las carátulas de los libros. A continuación tenemos el el código de ese componente:
import { Component, OnInit } from '@angular/core';
import { Book } from '../book';
import { BookService } from '../book.service';
@Component({
selector: 'app-book-list',
templateUrl: './book-list.component.html',
styleUrls: ['./book-list.component.css']
})
export class BookListComponent implements OnInit {
books: Array<Book> = [];
constructor(private bookService: BookService) { }
getBooks(): void {
this.bookService.getBooks().subscribe((books) => {
this.books = books;
});
}
ngOnInit() {
this.getBooks();
}
}
La prueba de integración la haremos sobre el componente BookListComponent. En la prueba crearemos unos datos (books
) de prueba y comprobaremos que la lista de libros se despliega correctamente.
La especificación de la prueba la haremos en el archivo book-list.component.spec.ts
el cual debe tener el siguiente código base:
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { BookListComponent } from './book-list.component';
describe('BookListComponent', () => {
let component: BookListComponent;
let fixture: ComponentFixture<BookListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BookListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BookListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Para el test requerimos crear un arreglo de libros que almacenaremos en la variable books del componente; luego detectaremos los cambios en el DOM y guardaremos el contenido del DOM en una variable; finalmente consultaremos esa variable para verificar si los datos de los libros están presentes en el DOM.
Iniciaremos la prueba incluyendo en la suite de pruebas (bloque describe
) una variable denominada debug de tipo DebugElement, e importamos la librería: import { DebugElement } from '@angular/core';
El propósito de la variable debug es acceder a los elementos del DOM.
describe('BookListComponent', () => {
let component: BookListComponent;
let fixture: ComponentFixture<BookListComponent>;
let debug: DebugElement;
...
Antes de ejecutar cada prueba necesitamos crear unos datos de libros ficticios. Para esto nos ayudaremos de la librería Faker la cual se instala con el comando npm install @faker-js/faker --save-dev.
Definimos entonces un atributo editorial
de tipo Editorial
. Luego a la variable books
del componente listar le asignamos un arreglo de libros. A este libro se le asigna como editorial la variable creada previamente.
beforeEach(() => {
fixture = TestBed.createComponent(BookListComponent);
component = fixture.componentInstance;
let editorial = new Editorial(
faker.datatype.number(),
faker.lorem.sentence()
);
component.books = [
new Book(
faker.datatype.number(),
faker.lorem.sentence(),
faker.lorem.sentence(),
faker.lorem.sentence(),
faker.image.imageUrl(),
faker.date.past(),
editorial
),
];
fixture.detectChanges();
debug = fixture.debugElement;
});
Al cambiar el valor de la variable books, el componente se actualiza, por lo tanto necesitamos detectar los cambios que han ocurrido en el componente; por esta razón incluimos un llamado a la función fixture.detectChanges();
Tenga en cuenta que la variable fixture
contiene una instancia del componente BookListComponent
y que el atributo debugElement
tiene una referencia al DOM que representa la vista de ese componente.
Ahora es posible obtener una referencia a cualquier elemento del DOM haciendo consultas (queries
) a la variable debug
. Una de las formas más simples de hacer estas consultas es mediante la clase By
. Las consultas se pueden especificar usando los selectores CSS. De este modo se pueden consultar elementos por selector de tipo (e.g., h1, p, img, table, entre otros), por selector de clases (e.g., .myClass), por selector id (e.g., #identifier), entre otros.
A continuación creamos la prueba (método it) que analiza el DOM y verifica que exista una imagen (que corresponde al libro creado) en la que el atributo alt tenga como valor el nombre de la imagen.
Para esto hacemos una consulta a la variable debug
con la función debug.query
. Esta función recibe como parámetro la consulta que queremos realizar. En este caso la consulta es By.css(‘im
g'); esto significa que vamos a buscar en el documento un elemento de tipo img
. El método debug.query(By.css('img'))
retorna una instancia de un objeto HTML. Como el objeto es una imagen debe contener el atributo alt.
Recordemos que en la vista la imagen que representa el libro tiene un atributo alt cuyo valor corresponde al nombre del libro.
<img
class="card-img-top"
src="{{ book.image }}"
alt="{{ book.name }}"
/>
Así que en la prueba verificaremos que ese atributo "alt" sea igual (toEqual) al nombre del libro: component.books[0].name. Si esto se cumple la expectativa también se cumple y la prueba se ejecutará correctamente.
it('should have an img element ', () => {
expect(debug.query(By.css('img')).attributes['alt']).toEqual(
component.books[0].name
);
});
Para la ejecución de la prueba se debe correr el comando ng test
. En la consola de VSCode debe aparecer el resultado de la ejecución.