簡體   English   中英

在 Angular 2 中測試 ngOnChanges 生命周期鈎子

[英]Testing ngOnChanges lifecycle hook in Angular 2

鑒於以下代碼,我嘗試測試 Angular2 的ngOnChanges生命周期鈎子:

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

不幸的是,測試失敗並顯示消息Expected spy ngOnChanges to have been called. 我知道我可以在這個例子中檢查 HTML 元素的內容,但是我有一些代碼需要在 ngOnChanes 生命周期鈎子中進行測試,所以這不是我的解決方案。 我也不想調用testComponent.ngOnChanges({someMockData}); 直接在測試中。

如何從測試中設置TestComponent.value以便調用ngOnChanges

猜猜我參加聚會有點晚了,但是這可能對將來的某些人有用。

自 Angular RC 5 發布以來,測試發生了一些變化。 然而,這里的主要問題是以編程方式設置輸入時不會調用ngOnChanges 有關更多信息,請參閱此內容 基本上,當僅通過視圖傳遞輸入時,會觸發OnChanges掛鈎。

解決這個問題的方法是讓宿主組件成為測試組件的父組件,並通過宿主組件的模板傳遞輸入。

這是完整的工作代碼:

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


});

您還可以選擇手動調用ngOnChanges掛鈎並在那里傳遞所需的更改對象。 但這不會設置組件屬性,只會調用更改邏輯。

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

請注意,這種方法可以很好地測試ngOnChanges內部的邏輯,但它不會測試@Input裝飾器是否正確設置。

在 Angular 4 中,要在測試時手動觸發ngOnChanges() ,您必須手動進行調用(如上所述),只需要匹配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),
});

我們正在使用這個實用程序 function:

 import {OnChanges, SimpleChange, SimpleChanges} from '@angular/core'; export function updateComponentInputs<T extends OnChanges>( component: T, changes: Partial<T> ) { const simpleChanges: SimpleChanges = {}; Object.keys(changes).forEach(changeKey => { component[changeKey] = changes[changeKey]; simpleChanges[changeKey] = new SimpleChange( null, changes[changeKey], false ); }); component.ngOnChanges(simpleChanges); }

你會像這樣使用它:

testComponent.updateComponentInputs({value: 'test'});

這會將 testComponent.value 設置為“test”,並且還會使用適當的更改事件調用 ngOnChanges。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM