Given the following code I try to test the ngOnChanges
lifecycle hook of Angular2:
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));
});
});
Unfortunately the test fails with the message Expected spy ngOnChanges to have been called.
I know that I could just check the contents of the HTML Element in this example, but I have some code that needs to be tested inside of the ngOnChanes lifecycle hook, so thats not a solution for me. I also don't want to call testComponent.ngOnChanges({someMockData});
in the test directly.
How can I set the TestComponent.value
from a test so that ngOnChanges
is called?
In Angular 4, to manually trigger
ngOnChanges()
when testing, you'll have to manually make the call (as pointed out above), only you need to match the new call signature of SimpleChange():Guess I'm a little late to the party, However this may be useful to some one in the future.
There have been a few changes to testing since RC 5 of angular has been released. However the main issue over here is
ngOnChanges
is not called when inputs are set programmatically. See this for more info . Basically theOnChanges
hook is triggered when inputs are passed via the view only.The solution to this would be to have host component which would be the parent of the test component and pass inputs to through the host component's template.
Here is the complete working code :
You also have an option to call ngOnChanges hook manually and pass desired changes object there. But this doesn't set the component properties, only call change logic.