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

Testing receiving input from other components when using setTimeout

这个问题是上一个问题 () 的延续。我仍在使用相同的文件,目的是为 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,但我现在知道这完全被忽略了。否则,我会得到错误 "Expected undefined to equal 'OnInit'/'AfterView'"。我省略了第二个勾号,因为它会导致错误“1 个计时器仍在队列中”。

如何告诉程序等待 setTimeout 函数中的值设置?

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

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

(感谢 来源的帮助!)

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

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