角度测试:使用 fakeAsync 和 async/await

JW.*_*JW. 11 unit-testing angular-material angular

Angular Material 提供了用于测试的组件线束,它允许您通过awaiting 承诺与它们的组件进行交互,如下所示:

  it('should click button', async () => {
    const matButton = await loader.getHarness(MatButtonHarness);
    await matButton.click();
    expect(...);
  });
Run Code Online (Sandbox Code Playgroud)

但是如果按钮点击触发延迟操作呢?通常我会使用fakeAsync()/tick()来处理它:

  it('should click button', fakeAsync(() => {
    mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
    // click button
    tick(1000);
    fixture.detectChanges();
    expect(...);
  }));
Run Code Online (Sandbox Code Playgroud)

但是有什么办法可以在同一个测试中同时做这两项吗?

async函数包装在里面fakeAsync()给了我“错误:代码应该在 fakeAsync 区域中运行以调用这个函数”,大概是因为一旦它完成了await,它就不再是我传递给 的同一个函数fakeAsync()

我是否需要做这样的事情——在等待之后启动一个 fakeAsync 函数?或者有更优雅的方式吗?

  it('should click button', async () => {
    mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
    const matButton = await loader.getHarness(MatButtonHarness);

    fakeAsync(async () => {
      // not awaiting click here, so I can tick() first
      const click = matButton.click(); 
      tick(1000);
      fixture.detectChanges();
      await click;
      expect(...);
    })();
  });
Run Code Online (Sandbox Code Playgroud)

Ale*_*hko 18

fakeAsync(async () => {...})是一个有效的构造。

而且,Angular Material 团队正在明确测试这种场景

it('should wait for async operation to complete in fakeAsync test', fakeAsync(async () => {
        const asyncCounter = await harness.asyncCounter();
        expect(await asyncCounter.text()).toBe('5');
        await harness.increaseCounter(3);
        expect(await asyncCounter.text()).toBe('8');
      }));
Run Code Online (Sandbox Code Playgroud)

  • 这是有效的,但也有风险。如果您的等待应用于微任务,则不会有任何问题,因为 fakeAsync 最后会刷新微任务。如果宏任务很困难,您会收到错误。在“await”之后,“tick”无法再为您提供帮助,因为它已经在该宏任务中执行了。 (4认同)

Joe*_*Joe 6

从 Angular 12 更新到 14 后,之前运行没有问题的测试开始失败。失败的具体测试取决于fakeAsyncasync

我的案例的解决方案是将以下内容添加targettsconfig.spec.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/spec",
    "module": "CommonJs",
    "target": "ES2016", // Resolved fakeAsync + async tests errors
    "types": ["jest"]
  },
  "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}
Run Code Online (Sandbox Code Playgroud)

一个人为的测试示例:

it('should load button with exact text', fakeAsync(async () => {
  const buttons = await loader.getAllHarnesses(
    MatButtonHarness.with({ text: 'Testing Button' })
  );

  tick(1000);

  expect(buttons.length).toBe(1);
  expect(await buttons[0].getText()).toBe('Testing Button');
}));
Run Code Online (Sandbox Code Playgroud)

我收到以下错误,它直接指向tick(1000)

代码应该在 fakeAsync 区域中运行来调用此函数

ES2016将目标添加到我的所有问题后都tsconfig.spec.json得到解决。

我使用 Jest,因此使用其他测试运行程序的人可能没有相同的分辨率。