Angular 使用 asyncScheduler 和 flush 进行测试 - 为什么使用 flush() 失败?

Angular test with asyncScheduler and flush - why it fails with flush()?

有这个Angular组件:

import { Component, OnDestroy, OnInit } from '@angular/core';
import { asyncScheduler, Observable, of, queueScheduler, scheduled } from 'rxjs';

@Component({
  selector: 'test-component',
  templateUrl: './test-component.component.html'
})
export class TestComponentComponent implements OnInit {
  value: string;

  constructor() { }

  ngOnInit(): void {
    const data$ = this.fetchDataScheduler();

    data$
      .subscribe(value => {
        this.value = value;
      });
  }

  private fetchDataScheduler(): Observable<string> {
    return scheduled(of('foo'), asyncScheduler);
  }

}

测试失败:

it('async - test setTimeout', fakeAsync(() => {
    expect(component.value).toBeFalsy();

    fixture.detectChanges(); // ngOnInit

    expect(component.value).toBeFalsy();
    flush();

    expect(component.value).toBe('foo');  // <- fails here
  }));

flush() 应该刷新所有宏任务,但事实并非如此。为什么? 如果我使用 tick(),则测试通过。

(以上截图由 Jest 和 Wallaby 插件提供。)

为什么不通过 flush() 而通过 tick()

flush:

Simulates the asynchronous passage of time for the timers in the fakeAsync zone by draining the macrotask queue until it is empty. The returned value is the milliseconds of time that would have been elapsed.

回购在这里:https://stackblitz.com/github/felikf/angular-testing-examples

asyncScheduler 是一个 setInterval,它是一个周期性的 macroTask,目前 flush() API 只flush setTimeout()等非周期宏任务

现在你应该使用 tick() 来让它工作。

您可以阅读更多相关信息here