Curso de Testing con Angular

by @nicobytes

Desarrollar aplicaciones que incluyan métodos de pruebas como parte del proceso de desarrollo nos permite tener un producto maduro, escalable y estable.





http://www.duety.co/



http://www.nicobytes.com/talks

https://www.ion-book.com/blog/

Aplicar las técnicas de unit testing y e2e, para asegurar la funcionalidad y calidad del producto y llevar tus desarrollos a un nuevo nivel de calidad.

Objetivo General

1. Aplicar TDD y Mocks.
3. Correr pruebas con karma y usando jasmine para escribir las pruebas.
4. Escribir y correr pruebas unitarias y e2e.
6. Testing en todos los artefactos de Angular: pipes, components, services, routers y directives.
7. Proceso de pruebas con integración continua.

Objetivos Específicos

Para sacar el máximo partido a esta iniciativa necesitas tener conocimientos de desarrollo en Angular

pre requisitos

Clase 1: ¿Qué es TDD?
Clase 2: Escribiendo pruebas en Angular.
Clase 3: Pruebas unitarias en Servicios y Providers.
Clase 4: Pruebas unitarias en components, pipes y directives.
Clase 5: Pruebas unitarias para router y CLI.

Contenido

Las pruebas unitarias reducen el riesgo en el software y una de las estrategias es: Desarrollo guiado por pruebas, más conocido por sus siglas en inglés TDD (Test Driven Development).

¿cÓMO LO HACEMOS?
Crear productos que agreguen valor y mantener la calidad del mismo es un gran reto.


Crear productos que agreguen valor y mantener la calidad del mismo es un gran reto.
los problemas siempre van a existir


Crear productos que agreguen valor y mantener la calidad del mismo es un gran reto.
gestionar el riesgo


Crear productos que agreguen valor y mantener la calidad del mismo es un gran reto.

Acceptance Testing ¿Estamos construyendo el producto correcto?
Usability Testing ¿Construimos el producto correcto?
Unit Testing ¿Lo estamos construyendo correctamente?
Performance Testing ¿Lo construimos de manera correcta?
Aprenderás a desarrollar aplicaciones guiadas por pruebas y testing para Angular y da un salto como profesional del desarrollo de aplicaciones con una de las tecnología más relevante en el panorama frontend.

¿qué Lograras?


i know TDD

CLASE 1


¿Qué es TDD?

Es una metodología donde se basa en tres pasos
Escribir pruebas
Escribir código
Refactorización








2 = Pruebas Unitarias
0 = Pruebas de INTEGRACIÓN




Herramientas








Primeras pruebas

let calculator = new Calculator();
let result = calculator.multiply(3,3);
console.log(result === 9);//'Test passed'
console.log(result !== 12);//'Test passed'


export class Calculator {
multiply(numberA: number, numberB: number): number{
return numberA * numberB;
}
}


let result2 = calculator.divide(6,2);
console.log(result2 === 3);//'Test passed'
console.log(result2 !== 34);//'Test passed'


divide(numberA: number, numberB: number): number{
return numberA / numberB;
}


divide(numberA: number, numberB: number): number{
if(numberB === 0){
return null;
}
return numberA / numberB;
}

Refactorizar

let calculator = new Calculator();
let result1 = calculator.multiply(3,3);
console.log(result1 === 9);//'Test passed'
console.log(result1 !== 12);//'Test passed'
let result2 = calculator.divide(6,2);
console.log(result2 === 3);//'Test passed'
console.log(result2 !== 34);//'Test passed'
let result3 = calculator.divide(6,0);
console.log(result3 === null);//'Test passed'



KARMA + JASMINE


Correr pruebas
npm test
ng test
ng test --single-run
ng test --code-coverage
ng test --single-run --code-coverage
http-server coverage


jasmine


The A's Mantra
(Arrange, Act, Assert)
(Preparar, Actuar, Verificar)

import { Calculator } from './calculator';
describe('Test for Calculator', () => {
describe('Test for multiply', () => {
it("multiply for 3", ()=>{
//Arrange
let calculator = new Calculator();
//Act
let number = calculator.multiply(3,3);
//Assert
expect(number).toEqual(9);
})
});
});

calculator.spec.ts


coverage report


describe('Test for divide', () => {
it("divide for a number", ()=>{
//Arrange
let calculator = new Calculator();
//Act && Assert
expect(calculator.divide(6,3)).toEqual(2);
expect(calculator.divide(5,2)).toEqual(2.5);
})
});

calculator.spec.ts


coverage report


it("divide for zero", ()=>{
//Arrange
let calculator = new Calculator();
//Act && Assert
expect(calculator.divide(6,0)).toBeNull();
expect(calculator.divide(5,0)).toBeNull();
expect(calculator.divide(1212,0)).toBeNull();
expect(calculator.divide(-23,0)).toBeNull();
})

calculator.spec.ts


coverage report


it("test of matchers", ()=>{
let name = 'nicolas'
let name2;
expect(name).toBeDefined();
expect(name2).toBeUndefined();
expect(1+2 == 3).toBeTruthy();
expect(1+1 == 3).toBeFalsy();
expect(5).toBeLessThan(10);
expect(20).toBeGreaterThan(10);
expect('1234567').toMatch(/123/);
expect(["apples", "oranges", "pears"]).toContain("oranges")
});

jasmime api

let calculator;
//Arrange
beforeEach(()=>{
calculator = new Calculator();
})

beforeEach

fdescribe('Test for Calculator', () => {...});
fit("multiply for 3", ()=>{...});

focus tests


https://jasmine.github.io/api/2.6/global


CLase 2


en el capítulo anterior...


- TDD
- Herramientas: Karma + Jasmine
- Coverage report
- Arrange, Act and Assert
- Escribir pruebas en Jasmine
- Correr pruebas





requerimientos
Diseñar una clase persona, que tenga los siguientes atributos:
- nombre, apellido, talla, peso, altura, edad
Debe calcular lo siguiente:
- calcular IMC: (Indice de masa corporal)





Peso (kg) | Altura (m) | IMC | Result |
---|---|---|---|
40 | 1.65 | 14 | 'down' |
58 | 1.65 | 21 | 'normal' |
68 | 1.65 | 25 | 'overweight' |
75 | 1.65 | 27 | 'overweight level 1' |
90 | 1.65 | 33 | 'overweight level 2' |
120 | 1.65 | 44 | 'overweight level 2' |


Peso (kg) | Altura (m) | IMC | Result |
---|---|---|---|
-78 | 1.65 | -28 | 'no found' |
-45 | -1.65 | -16 | 'no found' |


let person;
//Arrange
beforeEach(()=>{
person = new Person(
'nicolas',
'molina',
23,
40,
1.65
);
});
describe('test for data', ()=>{
it('attributes', ()=>{
expect(person.name).toEqual('nicolas');
expect(person.lastname).toEqual('molina');
expect(person.age).toEqual(23);
expect(person.weight).toEqual(40);
expect(person.height).toEqual(1.65);
})
});


describe('test for calcIMC', ()=>{
it('should return a string: down', ()=>{
person.weight = 40
expect(person.calcIMC()).toEqual('down');
});
it('should return a string: normal', ()=>{
person.weight = 58;
expect(person.calcIMC()).toEqual('normal');
});
it('should return a string: overweight', ()=>{
person.weight = 68;
expect(person.calcIMC()).toEqual('overweight');
});
it('should return a string: overweight level 1', ()=>{
person.weight = 75;
expect(person.calcIMC()).toEqual('overweight level 1');
});
it('should return a string: overweight level 2', ()=>{
person.weight = 90;
expect(person.calcIMC()).toEqual('overweight level 2');
});
it('should return a string: overweight level 3', ()=>{
person.weight = 120;
expect(person.calcIMC()).toEqual('overweight level 3');
});
it('should return a string: no found', ()=>{
person.weight = -48;
expect(person.calcIMC()).toEqual('no found');
person.weight = -48;
person.height = -1.70;
expect(person.calcIMC()).toEqual('no found');
})
});


ng test --code-coverage
http-server coverage


export class Person {
constructor(
public name: string,
public lastname: string,
public age: number,
public weight: number,
public height: number
){}
calcIMG(){
}
}


calcIMC(): string{
let result = this.weight / ((this.height) * (this.height));
if(result < 18){
return 'down';
}else if(result >= 18 && result <= 24){
return 'normal';
}else if(result >= 25 && result <= 26){
return 'overweight';
}else if(result >= 27 && result <= 29){
return 'overweight level 1';
}else if(result >= 30 && result <= 39){
return 'overweight level 2';
}else if(result >= 40){
return 'overweight level 3';
}
}


calcIMC(): string{
let result = Math.round(this.weight / ((this.height) * (this.height)));
if(result < 18){
return 'down';
}else if(result >= 18 && result <= 24){
return 'normal';
}else if(result >= 25 && result <= 26){
return 'overweight';
}else if(result >= 27 && result <= 29){
return 'overweight level 1';
}else if(result >= 30 && result <= 39){
return 'overweight level 2';
}else if(result >= 40){
return 'overweight level 3';
}
}


calcIMC(): string{
let result = Math.round(this.weight / ((this.height) * (this.height)));
if(result < 0){
return 'no found';
}else if(result >=0 && result < 18){
return 'down';
}else if(result >= 18 && result <= 24){
return 'normal';
}else if(result >= 25 && result <= 26){
return 'overweight';
}else if(result >= 27 && result <= 29){
return 'overweight level 1';
}else if(result >= 30 && result <= 39){
return 'overweight level 2';
}else if(result >= 40){
return 'overweight level 3';
}
}







ANGULAR UNIT TESTING FRAMEWORK


TEST FOR SERVICES


ng g s users
ng generate service users


import { TestBed, inject } from '@angular/core/testing';
import { UsersService } from './users.service';
describe('UsersService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [UsersService]
});
});
it('should be created',
inject([UsersService], (service: UsersService) => {
expect(service).toBeTruthy();
}));
});


import { inject,
fakeAsync,
tick,
TestBed
} from '@angular/core/testing';


import {MockBackend} from '@angular/http/testing';
import {
Http,
ConnectionBackend,
BaseRequestOptions,
Response,
ResponseOptions
} from '@angular/http';


consideraciones
1. Hacer solicitudes reales haría que nuestros test sean muy tardados
2. Ciertas API tiene limite de solitudes que si las corremos en test las vamos a sobrepasar innecesariamente.
3. Necesitamos correr pruebas de forma offline


¿Qué es Mocking?
Son objetos simulados (pseudoobjetos, mock object, objetos de pega) a los objetos que imitan el comportamiento de objetos reales de una forma controlada.


arrange
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
BaseRequestOptions,
MockBackend,
UsersService,
{
provide: Http,
deps: [MockBackend, BaseRequestOptions],
useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
},
]
});
});


test for HTTP
describe('test for getUser', ()=>{
it("should return the user's data with an id", ()=>{
})
});


test for HTTP
it('.....', inject([.....], fakeAsync( (....)=>{} ));


test for HTTP
it("should return the user's data with an id",
inject([UsersService, MockBackend], fakeAsync((userService, mockBackend)=>{
}))
)


test for HTTP
it("should return the user's data with an id",
inject([UsersService, MockBackend], fakeAsync((userService, mockBackend)=>{
}))
)
Cada vez que escribimos pruebas a clases con dependencias debemos usar con inject para que Angular nos proporcione las instancias de estas clases.


test for HTTP
it("should return the user's data with an id",
inject([UsersService, MockBackend], fakeAsync((userService, mockBackend)=>{
}))
)
Cuando probamos código que devuelve una Promise o un Observable podemos usar fakeAsync para probar código como si fuera de forma sincrona.
Para que las Promises y Observables se cumplan/notifiquen se debe llamar la función tick()


test for HTTP
let dataResponse;
mockBackend.connections
.subscribe(connection => {
expect(connection.request.url)
.toBe('http://jsonplaceholder.typicode.com/users/1');
});


test for HTTP



test for HTTP
let userMock = {
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
let mockResponse = new ResponseOptions({body: JSON.stringify(userMock)});


test for HTTP
mockBackend.connections.subscribe(connection => {
expect(connection.request.url).toBe('http://jsonplaceholder.typicode.com/users/1');
connection.mockRespond(new Response(mockResponse));
});


test for HTTP
userService.getUser(1)
.subscribe(response => {
dataResponse = response;
});
tick();
expect(dataResponse.id).toBeDefined();
expect(dataResponse.name).toBeDefined();
expect(dataResponse.address).toBeDefined();


test for HTTP
let dataResponse, dataError;
let mockResponse = new ResponseOptions({body: JSON.stringify(userMock)});
mockBackend.connections.subscribe((connection: MockConnection) => {
expect(connection.request.url).toBe('http://jsonplaceholder.typicode.com/users/1');
connection.mockError(new Error('error'));
});


test for HTTP
userService.getUser(1)
.subscribe(
response => { // success
dataResponse = response;
},
error => { //error
dataError = error;
}
);
tick();
expect(dataResponse).toBeUndefined();
expect(dataError).toBeDefined();


CLase 3


en el capítulo anterior...


- Karma mocha reporter (terminal)
- Angular Unit Test Framework
- Mocks
- Test for HTTP


test for http
- Mocks: Objetos simulados
- Http: se hace una intercepción de la petición con un mock de respuesta.
- inject, fakeAsync y tick


arrange for angular
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
BaseRequestOptions,
MockBackend,
UsersService,
{
provide: Http,
deps: [MockBackend, BaseRequestOptions],
useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
},
]
});
});


arrange for it
it("should return the user's data with an id",
inject([UsersService, MockBackend], fakeAsync((usersService, mockBackend)=>{
// Your TEST
}))
);


arrange for it
//Arrange
let dataResponse;
let userMock ={...}
let mockResponse = new ResponseOptions({body: JSON.stringify(userMock)});
mockBackend.connections.subscribe(connection =>{
expect(connection.request.url).toBe('http://jsonplaceholder.typicode.com/users/3');
connection.mockRespond(new Response(mockResponse));
});


act for it
//Act
usersService.getUser(3)
.subscribe(response =>{
dataResponse = response;
});
tick();


assert for it
//Assert
expect(dataResponse.id).toBeDefined();
expect(dataResponse.name).toBeDefined();
expect(dataResponse.address).toBeDefined();


test for http
- Test for GET
- Test for POST
- Test for PUT
- Test for DELETE


red: write a test



test for post
it("should return the user's data",
inject([UsersService, MockBackend], fakeAsync((userService, mockBackend)=>{
//YOUR TEST
}))
);


test for post
//Arrange
let dataResponse, dataError;
let userMock = {
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz"
}
let mockResponse = new ResponseOptions({body: JSON.stringify(userMock)});
mockBackend.connections.subscribe((connection: MockConnection) => {
expect(connection.request.url).toBe('http://jsonplaceholder.typicode.com/users');
connection.mockRespond(new Response(mockResponse));
});


test for post
//Act
let newUser = {
name: "Leanne Graham",
username: "Bret",
email: "Sincere@april.biz"
}
userService.createUser(newUser)
.subscribe(
response => { // success
dataResponse = response;
},
error => { //error
dataError = error;
}
);
tick();


test for post
//Assert
expect(dataError).toBeUndefined();
expect(dataResponse.id).toBeDefined();
expect(dataResponse.name).toEqual('Leanne Graham');
expect(dataResponse.username).toEqual('Bret');
expect(dataResponse.email).toEqual('Sincere@april.biz');


test for post error
mockBackend.connections.subscribe((connection: MockConnection) => {
expect(connection.request.url).toBe('http://jsonplaceholder.typicode.com/users');
connection.mockError(new Error('error'));
});


test for post error
//Assert
expect(dataError).toBeDefined();
expect(dataResponse).toBeUndefined();


CHECK: JASMINE report



green: make the code



code
createUser(newUser: any){
let body = JSON.stringify(newUser);
return this.http.post(`${this.path}`, body)
.map(response => response.json());
}


check: jasmine report



write test for put and delete


put and delete



test for type and headers
expect(c.request.method).toBe(RequestMethod.Delete);
expect(c.request.headers.get('X-API-TOKEN')).toEqual('xxxxx');


make header
makeRequestOptions(): RequestOptionsArgs{
let headers = new Headers();
headers.append('API-TOKEN', 'xxxyyy');
return {
headers: headers
};
}


code
updateUser(user: any){
let id = user.id;
let body = JSON.stringify(user);
return this.http.put(`${this.path}/${id}`, body)
.map(response => response.json());
}
deleteUser(id: number){
return this.http.delete(`${this.path}/${id}`)
.map(response => response.json());
}


jasmine reporter



test for components


test for components
ng g c user-row
ng generate component user-row


test for components
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { UserRowComponent } from './user-row.component';


test for components
describe("UserRowComponent", ()=>{
let component: UserRowComponent;
let fixture: ComponentFixture<UserRowComponent>;
let de: DebugElement;
let el: HTMLElement;
//Arrange
beforeEach(()=>{
TestBed.configureTestingModule({
declarations: [ UserRowComponent ], // declare the test component
});
fixture = TestBed.createComponent(UserRowComponent);
component = fixture.componentInstance;
de = fixture.debugElement.query(By.css('h1'));
el = de.nativeElement;
});
});


test for components
it("should the name be 'nicolas'", ()=>{
expect(component.name).toEqual('nicolas');
})


test for components
it("should the name be 'nicolas'", ()=>{
expect(component.name).toEqual('nicolas');
})


test for components
it('should display original title', () => {
fixture.detectChanges();
expect(el.textContent).toContain(component.name);
});


test for components
it('should display original title', () => {
fixture.detectChanges();
expect(el.textContent).toContain(component.name);
});


test for components
it('should display a different test name', () => {
component.name = 'Test name';
fixture.detectChanges();
expect(el.textContent).toContain('Test name');
});


test for components
//Arrange
beforeEach(async(()=>{
TestBed.configureTestingModule({
declarations: [ UserRowComponent ]
})
.compileComponents();
}));
beforeEach(()=>{
fixture = TestBed.createComponent(UserRowComponent);
component = fixture.componentInstance;
de = fixture.debugElement.query(By.css('h1'));
el = de.nativeElement;
})


test for components
//Arrange
it('should display original lastname', () => {
let de = fixture.debugElement.query(By.css('.lastname'));
fixture.detectChanges();
expect(de.nativeElement.textContent).toContain('molina');
});
it('should display original lastname', () => {
component.lastname = 'otro apellido';
let de = fixture.debugElement.query(By.css('.lastname'));
fixture.detectChanges();
expect(de.nativeElement.textContent).toContain('otro apellido');
});


test for components
//Arrange
it('should display original lastname', () => {
let de = fixture.debugElement.query(By.css('.lastname'));
fixture.detectChanges();
expect(de.nativeElement.textContent).toContain('molina');
});
it('should display original lastname', () => {
component.lastname = 'otro apellido';
let de = fixture.debugElement.query(By.css('.lastname'));
fixture.detectChanges();
expect(de.nativeElement.textContent).toContain('otro apellido');
});


test for components
beforeEach(()=>{
fixture = TestBed.createComponent(UserRowComponent);
component = fixture.componentInstance;
component.person = new Person(
'nicolas',
'molina',
12,
12,
12
);
de = fixture.debugElement.query(By.css('h1'));
el = de.nativeElement;
})


clase 4


en el capítulo anterior...


- Test for HTTP: Delete, Put, Delete
- Test for components
- Test for components + inputs


TEST FOR COMPONENTS
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { UserRowComponent } from './user-row.component';
import { Person } from './../person';


TEST FOR COMPONENTS
let component: UserRowComponent;
let fixture: ComponentFixture<UserRowComponent>;
let de: DebugElement;
let el: HTMLElement;
//Arrange
beforeEach(async(()=>{
TestBed.configureTestingModule({
declarations: [ UserRowComponent ]
})
.compileComponents();
}));
beforeEach(()=>{
component.person = new Person(
'nicolas',
'molina',
12,
12,
12
);
})


TEST FOR COMPONENTS
it('should display original lastname', () => {
component.person.lastname = 'otro apellido';
let de = fixture.debugElement.query(By.css('.lastname'));
fixture.detectChanges();
expect(de.nativeElement.textContent).toContain('otro apellido');
});


TEST FOR COMPONENTS: Click
it('should display un text for imc', () => {
let button = fixture.debugElement.query(By.css('.btn-imc')); // find hero element
button.triggerEventHandler('click', null);
fixture.detectChanges();
expect(button.nativeElement.textContent == '').toBeFalsy();
expect(component.imc== '').toBeFalsy();
});


TEST FOR COMPONENTS: output
it('should raise selected event when clicked', () => {
let selectedPerson: Person;
component.onSelected.subscribe((person: Person) => {
selectedPerson = person
});
let button = fixture.debugElement.query(By.css('.btn-person')); // find hero element
button.triggerEventHandler('click', null);
fixture.detectChanges();
expect(selectedPerson.name).toEqual('nicolas');
});


TEST FOR COMPONENTS
ng g c users-list
ng generate component users-list


TEST FOR COMPONENTS
ng g c users-list
ng generate component users-list


TEST FOR COMPONENTS
it('should have an user-row', () => {
let de = fixture.debugElement.query(By.css('app-user-row'));
expect(de).toBeTruthy();
});


TEST FOR COMPONENTS
it('should raise selected event when clicked', () => {
let button = fixture.debugElement.query(By.css('app-user-row .btn-person')); // find hero element
button.triggerEventHandler('click', null);
fixture.detectChanges();
// selected hero should be the same data bound hero
expect(component.selectedPerson.name).toBe('nicolas');
});


TEST FOR COMPONENTS: services
it('should raise selected event when clicked', () => {
let button = fixture.debugElement.query(By.css('app-user-row .btn-person')); // find hero element
button.triggerEventHandler('click', null);
fixture.detectChanges();
// selected hero should be the same data bound hero
expect(component.selectedPerson.name).toBe('nicolas');
});


clase 5


en el capítulo anterior


- Testing components with inside components
- Testing compones with services: MockServices
- Testing for pipes


Spies: services


Spies: services
let component: UsersListComponent;
let fixture: ComponentFixture<UsersListComponent>;
let userService: UsersService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ UsersListComponent, UserRowComponent ],
imports: [ HttpModule ],
providers: [
{provide: UsersService, useClass: UsersService}
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(UsersListComponent);
component = fixture.componentInstance;
userService = fixture.debugElement.injector.get(UsersService);
});


Spies: services
it('should be created', ()=>{
let spy = spyOn(userService, 'getAll')
.and.returnValue(Observable.of([
new Person('Nicolas NICO','asas',12,12,12)
]));
fixture.detectChanges();
expect(userService.getAll).toHaveBeenCalled();
});


Spies: services
it('should get user', ()=>{
fixture.detectChanges();
spyOn(userService, 'getUser')
.and.returnValue(Observable.of(
new Person('Nicolas NICO','asas',12,12,12)
));
component.getUser();
//fixture.detectChanges();
expect(userService.getUser).toHaveBeenCalled();
expect(userService.getUser).toHaveBeenCalledWith(23);
expect(component.persons[0].name).toEqual('Nicolas NICO');
});


TEST FOR forms
it('validates errors', async(() => {
fixture = TestBed.createComponent(FormSkuComponent);
component = fixture.componentInstance;
component.skuField.setValue('123');
expect(component.skuField.valid).toBeTruthy();
component.skuField.setValue('123234');
expect(component.skuField.valid).toBeTruthy();
component.skuField.setValue('');
expect(component.skuField.invalid).toBeTruthy();
component.skuField.setValue('234');
expect(component.skuField.invalid).toBeTruthy();
}));


TEST FOR forms
it('test', ()=>{
let mockControl = new FormControl();
mockControl.setValue('nicolas');
let response = MyValidators.skuValidator(mockControl);
expect(response.invalidSku).toBeDefined();
expect(response.invalidSku).toBeTruthy();
});
it('test 2', ()=>{
let mockControl = new FormControl();
mockControl.setValue('123');
let response = MyValidators.skuValidator(mockControl);
expect(response).toBeNull();
});


TEST FOR forms
it('validates and triggers events', async(() => {
fixture = TestBed.createComponent(FormSkuComponent);
component = fixture.componentInstance;
el = fixture.debugElement.nativeElement;
input = fixture.debugElement.query(By.css('input#skuInput')).nativeElement;
form = fixture.debugElement.query(By.css('form')).nativeElement;
fixture.detectChanges();
fixture.whenStable()
.then(() => { // wait for async getQuote
input.value = 'asas';
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
return fixture.whenStable();
})
.then(() =>{
let msgs = el.querySelectorAll('.ui.message');
expect(msgs[0].innerHTML).toContain('SKU is invalid');
})
}));


TEST FOR forms
it('validates and triggers events for form', async(() => {
fixture = TestBed.createComponent(FormSkuComponent);
component = fixture.componentInstance;
el = fixture.debugElement.nativeElement;
input = fixture.debugElement.query(By.css('input#skuInput')).nativeElement;
form = fixture.debugElement.query(By.css('form')).nativeElement;
fixture.detectChanges();
fixture.whenStable()
.then(() => {
component.nameField.setValue('nicolas');
component.skuField.setValue('123');
form.dispatchEvent(new Event('submit'));
fixture.detectChanges();
return fixture.whenStable();
})
.then(() =>{
expect(component.skuForm.invalid).toBeTruthy();
})
}));

GRACIAS...
Curso de Testing con Angular
By Nicolas Molina
Curso de Testing con Angular
- 4,148