12

Dato il seguente codice provo a testare il gancio ngOnChanges ciclo di vita dei Angular2:test ngOnChanges gancio del ciclo di vita in angolare 2

import { 
    it, 
    inject, 
    fdescribe, 
    beforeEachProviders, 
} from '@angular/core/testing'; 

import {TestComponentBuilder} from '@angular/compiler/testing'; 

import {Component, OnChanges, Input} from '@angular/core'; 

@Component({ 
    selector: 'test', 
    template: `<p>{{value}}</p>`, 
}) 
export class TestComponent implements OnChanges { 
    @Input() value: string; 

    ngOnChanges(changes: {}): any { 
     // should be called 
    } 
} 

fdescribe('TestComponent',() => { 
    let tcb: TestComponentBuilder; 

    beforeEachProviders(() => [ 
     TestComponentBuilder, 
     TestComponent, 
    ]); 

    beforeEach(inject([TestComponentBuilder], _tcb => { 
     tcb = _tcb; 
    })); 

    it('should call ngOnChanges', done => { 
     tcb.createAsync(TestComponent).then(fixture => { 
      let testComponent: TestComponent = fixture.componentInstance; 

      spyOn(testComponent, 'ngOnChanges').and.callThrough(); 

      testComponent.value = 'Test'; 
      fixture.detectChanges(); 

      expect(testComponent.ngOnChanges).toHaveBeenCalled(); 
      done(); 
     }).catch(e => done.fail(e)); 
    }); 
}); 

Purtroppo la prova non riesce con il messaggio Expected spy ngOnChanges to have been called. so che ho potuto solo controllare il contenuto della l'elemento HTML in questo esempio, ma ho un codice che deve essere testato all'interno dell'hook del ciclo di vita di ngOnChanes, quindi questa non è una soluzione per me. Inoltre, non voglio chiamare direttamente il numero testComponent.ngOnChanges({someMockData}); nel test.

Come è possibile impostare TestComponent.value da un test in modo da chiamare ngOnChanges?

+1

I don Pensa che dovresti fare un test angolare, il suo team angolare. hai solo bisogno di trovare qualsiasi motivo per testare i tuoi codici commerciali diversi dal framework stesso. –

+2

Voglio testare il mio codice aziendale che si trova all'interno della funzione 'ngOnChanges' – user1448982

+0

se è necessario eseguire test di e2e, forse' http: // www.protractortest.org' aiuta –

risposta

31

Indovina che sono un po 'in ritardo per la festa, tuttavia questo potrebbe essere utile per qualcuno in futuro.

Ci sono state alcune modifiche ai test da quando è stato rilasciato RC 5 di angolare. Tuttavia il problema principale qui è ngOnChanges non viene chiamato quando gli ingressi sono impostati a livello di programmazione. See this for more info. Fondamentalmente il gancio OnChanges viene attivato quando gli input vengono passati tramite la visualizzazione solo.

La soluzione per questo sarebbe avere un componente host che sarebbe il genitore del componente di test e passare gli input attraverso il modello del componente host.

Ecco il codice di lavoro completo:

import {Component, OnChanges, Input, ViewChild} from '@angular/core'; 
import { TestBed }  from '@angular/core/testing'; 

@Component({ 
    selector: 'test', 
    template: `<p>{{value}}</p>`, 
}) 
export class TestComponent implements OnChanges { 
    @Input() value: string; 

    ngOnChanges(changes: {}): any { 
     // should be called 
    } 
} 
/* In the host component's template we will pass the inputs to the actual 
* component to test, that is TestComponent in this case 
*/ 
@Component({ 
    selector : `test-host-component`, 
    template : 
    `<div><test [value]="valueFromHost"></test></div>` 
}) 
export class TestHostComponent { 
    @ViewChild(TestComponent) /* using viewChild we get access to the TestComponent which is a child of TestHostComponent */ 
    public testComponent: any; 
    public valueFromHost: string; /* this is the variable which is passed as input to the TestComponent */ 
} 

describe('TestComponent',() => { 

    beforeEach(() => { 
     TestBed.configureTestingModule({declarations: [TestComponent,TestHostComponent]}); /* We declare both the components as part of the testing module */ 
    }); 

    it('should call ngOnChanges',()=> { 
     let fixture = TestBed.createComponent(TestHostComponent); 
     let testHostComponent = fixture.componentInstance; 
     testHostComponent.valueFromHost = 'Test'; 
     spyOn(testHostComponent.testComponent, 'ngOnChanges').and.callThrough(); 
     fixture.detectChanges(); 
     expect(testHostComponent.testComponent.ngOnChanges).toHaveBeenCalled(); 
    }) 


}); 
+0

Esiste un'altra soluzione disponibile oggi? Non voglio scrivere un TestComponent per tutti i miei componenti ... :( –

+1

Beh, non ne ho trovato uno finora :(. Infatti c'era un problema sollevato proprio su questo argomento: https://github.com/ angolare/angolare/problemi/6235. Leggere i commenti di pkozlowski-opensource su questo –

+1

se si desidera una modifica specifica: component.ngOnChanges ({ 'chiave': nuovo SimpleChange (false, true) }) –

6

Hai anche l'opzione di chiamare gancio ngOnChanges manualmente e passano cambiamenti desiderati là oggetto. Ma questo non imposta le proprietà del componente, ma chiama solo la logica di cambiamento.

const previousValue = moment('2016-03-01T01:00:00Z'); 
const currentValue = moment('2016-02-28T01:00:00Z'); 

const changesObj: SimpleChanges = { 
    prop1: new SimpleChange(previousValue, currentValue) 
}; 

component.ngOnChanges(changesObj); 
+1

Funziona come soluzione temporanea. non dimenticare di impostare il valore dei componenti a mano (come component.prop1 = currentvalue) –

2

In angolare 4, per far scattare manualmente ngOnChanges() quando il test, si dovrà effettuare manualmente la chiamata (come sottolineato in precedenza), hai solo bisogno di abbinare il new call signature of SimpleChange():

let prev_value = "old"; 
let new_value = "new"; 
let is_first_change: boolean = false; 

component.ngOnChanges({prop1: new SimpleChange(prev_value, new_value, is_first_change}); 
Problemi correlati