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...

Copy of Curso de Testing con Angular

By Yhoan Andres Galeano Urrea