12

den folgenden Code Da ich versuche, den ngOnChanges Lifecycle Haken von Angular2 zu testen:Testing ngOnChanges Lifecycle Haken in Angular 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)); 
    }); 
}); 

Leider ist der Test mit der Nachricht nicht Expected spy ngOnChanges to have been called. Ich weiß, dass ich nur den Inhalt überprüfen könnte das HTML-Element in diesem Beispiel, aber ich habe etwas Code, der innerhalb des ngOnChanes-Lebenszyklus-Hooks getestet werden muss, also ist das keine Lösung für mich. Ich möchte auch testComponent.ngOnChanges({someMockData}); im Test nicht direkt anrufen. Wie kann ich den TestComponent.value von einem Test so einstellen, dass ngOnChanges aufgerufen wird?

+1

I don Ich denke, du solltest einen Test für eckige, eckige Teams machen. Sie müssen nur herausfinden, warum, um Ihre Geschäfts-Codes außer dem Rahmen selbst zu testen. –

+2

Ich möchte meinen Businesscode testen, der innerhalb der 'ngOnChanges'-Funktion ist – user1448982

+0

Wenn Sie e2e testen müssen, hilft' http: // www.protractortest.org' –

Antwort

31

Raten Sie, ich bin ein wenig zu spät zur Party, aber das kann für jemanden in der Zukunft nützlich sein.

Es wurden einige Änderungen an den Tests vorgenommen, seit RC 5 of angular veröffentlicht wurde. Das Hauptproblem hier ist jedoch ngOnChanges wird nicht aufgerufen, wenn Eingaben programmgesteuert festgelegt sind. See this for more info. Grundsätzlich wird der OnChanges Haken ausgelöst, wenn Eingaben über die Ansicht nur übergeben werden.

Die Lösung wäre, eine Host-Komponente zu haben, die das Elternelement der Testkomponente wäre und Eingaben an die Vorlage der Host-Komponente weitergibt.

Dies ist die komplette Arbeitscode:

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

Gibt es heute eine andere Lösung? Ich möchte keine TestComponent für alle meine Komponenten schreiben ... :( –

+1

Nun, ich konnte bisher keinen finden :(. Tatsächlich gab es ein Problem, das zu diesem Thema angesprochen wurde: https://github.com/ angle/angular/issues/6235. Lesen Sie die Kommentare von pkozlowski-opensource zu dieser –

+1

, wenn Sie eine bestimmte Änderung wünschen: component.ngOnChanges ({ 'key': new SimpleChange (false, true) }) –

6

Sie haben auch eine Option ngOnChanges Haken manuell aufrufen und die gewünschten Änderungen passieren dort widersprechen. Dies setzt jedoch nicht die Komponenteneigenschaften, sondern nur die Änderungslogik.

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

Funktioniert als Workaround nicht vergessen, den Komponentenwert von Hand zu setzen (wie component.prop1 = currentvalue) –

2

In Angular 4, manuell ngOnChanges() auslösen, wenn Tests, werden Sie manuell den Anruf tätigen müssen (wie oben erwähnt), nur müssen Sie das Spiel 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});