使用setTimeout时测试从其他组件接收输入

时间:2019-07-11 22:43:38

标签: angular typescript unit-testing karma-runner

该问题是上一个问题(linked here)的延续。我仍在为编写Angular测试的简单教程而使用相同的文件。新问题与setTimeout函数有关。

在ngOnInit和ngAfterViewInit上,我都实现了setTimeout(我将在以后编写的其他测试中做到这一点,因此,这只是创建一个基本示例)。内部的函数设置通过HTML文件传递给子组件的变量的值。然后检查该子组件的变量的特定值。

我已经尝试使用tick(value)和Fixture.detectChanges()来尝试触发setTimeout函数的内容,但是该值仍未定义(请参见代码段)。

random.test.component.ts

public dataThatGetsDelayed: any;

constructor() {

}

ngOnInit() {
    setTimeout(() => {
        this.dataThatGetsDelayed = "OnInit";
    }, 100);
}

ngAfterViewInit() {
    setTimeout(() => {
        this.dataThatGetsDelayed = "AfterView";
    }, 100);
}

random.test.component.html

[variableThatStoresDelayedData]="dataThatGetsDelayed"

random.test.component.child.ts

@Input() variableThatStoresDelayedData: any;

random.test.file.spec.ts

it('Testing if receiving input works properly with a time delay in ngOnInit', fakeAsync(() => {
    const componentInThePage: TestComponentChild = fixture.debugElement.query(By.directive(TestComponentChild)).componentInstance;
    expect(componentInThePage).toBeTruthy();

    tick(100);
    fixture.detectChanges();

    fixture.whenStable().then(() => {
        expect(componentInThePage.variableThatStoresDelayedData).toEqual("OnInit");
    });
}));

it('Testing if receiving input works properly with a time delay in ngAfterViewInit', fakeAsync(() => {
    const componentInThePage: TestComponentChild = fixture.debugElement.query(By.directive(TestComponentChild)).componentInstance;
    expect(componentInThePage).toBeTruthy();

    //tick(100);
    //component.ngAfterViewInit();

    fixture.whenStable().then(() => {
        expect(componentInThePage.variableThatStoresDelayedData).toEqual("AfterView");
    });
}));

我读到我应该在最后使用whenStable,但是我现在知道这完全被忽略了。否则,我将收到错误消息“预期未定义的值等于'OnInit'/'AfterView'”。我省略了第二个刻度,因为它会导致错误“ 1个计时器仍在队列中”。

如何告诉程序等待,直到在setTimeout函数中设置了值?

1 个答案:

答案 0 :(得分:0)

好的,因此,通过一些研究和实验,我找到了解决方案。代码注释解释了更详细的信息:

random.test.component.ts

public dataThatGetsDelayed: any = "Initial value"; //This is just to show how the value changes.

constructor(private detectorReference: ChangeDetectorRef) {
    //The detectorReference is used in ngAfterViewInit
}

ngOnInit() {
    setTimeout(() => {
        this.dataThatGetsDelayed = "OnInit";
    }, 100);
}

ngAfterViewInit() {
    setTimeout(() => {
        this.dataThatGetsDelayed = "AfterView";
        this.detectorReference.detectChanges(); //Needed to stop the error about changing the value.
    }, 200);
}

(感谢this的帮助!)

random.test.file.spec.ts

//This test is for the ngOnInit function
it('Testing if receiving input works properly with a time delay in ngOnInit', fakeAsync(() => {
    const componentInThePage: TestComponentChild = fixture.debugElement.query(By.directive(TestComponentChild)).componentInstance;
    expect(componentInThePage).toBeTruthy();

    expect(componentInThePage.variableThatStoresDelayedData).toEqual("Initial value");

    component.ngOnInit();
    //tick(99); - This doesn't /quite/ run out the setTimeout function from the ngOnInit function.
    tick(100); //This does, though.
    fixture.detectChanges();

    expect(componentInThePage.variableThatStoresDelayedData).toEqual("OnInit");
}));

//This test is for the ngAfterViewInit function. Note that the value isn't set with ngOnInit first;
//only the explicit method call will perform the desired action.
it('Testing if receiving input works properly with a time delay in ngAfterViewInit', fakeAsync(() => {
    const componentInThePage: TestComponentChild = fixture.debugElement.query(By.directive(TestComponentChild)).componentInstance;
    expect(componentInThePage).toBeTruthy();

    expect(componentInThePage.variableThatStoresDelayedData).toEqual("Initial value");

    component.ngAfterViewInit();
    //tick(199); - Again, this doesn't /quite/ run out the setTimeout.
    tick(200); //But, once again, this does.
    fixture.detectChanges();

    expect(componentInThePage.variableThatStoresDelayedData).toEqual("AfterView");
}));

希望这对以后的人有帮助!