Angular / Karma单元测试错误“队列中还有1个计时器”

时间:2019-10-16 15:34:53

标签: angular typescript unit-testing karma-jasmine

这几乎不是我第一次接触"1 timer(s) still in the queue"时遇到的,但通常我会找到某种方法来使用tick()detectChanges()等来摆脱它。

在我尝试测试我知道应该引发异常的条件之前,下面的测试工作正常:

  it('should be able to change case', fakeAsync(() => {
    expect(component).toBeTruthy();

    fixture.whenStable().then(fakeAsync(() => {
      component.case = 'lower';
      fixture.autoDetectChanges();
      tick(500);
      const input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
      typeInElement('abcDEF', input);
      fixture.autoDetectChanges();
      tick(500);
      expect(component.text).toEqual('abcdef');

      component.case = 'upper';
      fixture.autoDetectChanges();
      tick(500);
      typeInElement('abcDEF', input);
      fixture.autoDetectChanges();
      tick(500);
      expect(component.text).toEqual('ABCDEF');

      // Everything above works fine. Here's where the trouble begins
      expect(() => {
        component.case = 'foo';
        fixture.autoDetectChanges();
        tick(500);
      }).toThrowError(/Invalid case attribute/);
    }));
  }));

我正在测试的是一个Angular组件,该组件是Material输入字段的包装。该组件具有许多可选属性,其中大多数只是通用输入字段功能的直通属性,但也有一些自定义属性,例如我上面测试的用于大写/小写转换的属性。

case属性的可接受值为upperlowermixed(带有空字符串,空值或未定义为mixed的值) 。该组件应该为其他任何东西抛出异常。显然可以,并且测试成功,但是随着成功,我得到了:

ERROR: 'Unhandled Promise rejection:', '1 timer(s) still in the queue.', '; Zone:', 'ProxyZone', '; Task:', 'Promise.then', '; Value:', Error: 1 timer(s) still in the queue.
Error: 1 timer(s) still in the queue.
   ...

任何人都可以告诉我我可能做错了什么,或者是清除挥之不去的计时器的好方法吗?

免责声明:当我寻求有关Karma单元测试的最大问题是,即使我明确搜索“ karma”,我也大多会找到Pr0tractor,Pr0tractor以及更多Pr0tractor的答案。这不是Pr0tractor! (故意将零误拼写为零,因此它不会获得搜索匹配项。)

更新:我可以这样解决我的问题:

      expect(() => {
        component.inputComp.case = 'foo';
      }).toThrowError(/Invalid camp-input case attribute/);

这不像通过测试组件模板中的HTML属性分配(错误)值那样好的测试,因为我只是将值直接强加到属性本身的组件设置器中,但是,直到我有更好的解决方案为止。

2 个答案:

答案 0 :(得分:13)

我也遇到过类似的问题。解决方案是使用flush函数。

import { fakeAsync, flush } from '@angular/core/testing';

it('test something', fakeAsync(() => {

  // ...

  flush();
}));

答案 1 :(得分:11)

我最近遇到了同样的问题-为了解决我在discardPeriodicTasks()函数结尾处从@angular/core/testingit的问题,此后我的测试通过了。

在这种情况下,您可能希望将其插入到最终expect

之前
 it('should be able to change case', fakeAsync(() => {
    expect(component).toBeTruthy();

    fixture.whenStable().then(fakeAsync(() => {
      component.case = 'lower';
      fixture.autoDetectChanges();
      tick(500);
      const input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
      typeInElement('abcDEF', input);
      fixture.autoDetectChanges();
      tick(500);
      expect(component.text).toEqual('abcdef');

      component.case = 'upper';
      fixture.autoDetectChanges();
      tick(500);
      typeInElement('abcDEF', input);
      fixture.autoDetectChanges();
      tick(500);
      expect(component.text).toEqual('ABCDEF');

      discardPeriodicTasks() <-------------------- try here

      // Everything above works fine. Here's where the trouble begins
      expect(() => {
        component.case = 'foo';
        fixture.autoDetectChanges();
        tick(500);
      }).toThrowError(/Invalid case attribute/);

    }));