Testing ngOnChanges lifecycle hook in Angular 2

一笑奈何 提交于 2019-11-29 03:00:23
Kiran Yallabandi

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 the OnChanges 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 :

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', ()=> {
        const fixture = TestBed.createComponent(TestHostComponent);
        const hostComponent = fixture.componentInstance;
        hostComponent.valueFromHost = 'Test';
        const component = hostComponent.testComponent;
        spyOn(component, 'ngOnChanges').and.callThrough();
        fixture.detectChanges();
        expect(component.ngOnChanges).toHaveBeenCalled();
    })


});
s-f

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.

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);

Be aware that this approach will work fine to test the logic inside ngOnChanges, but it will not test that the @Input decorators are properly set.

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():

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});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!