尽管在我的 Angular 项目测试中没有使用异步函数,但 Jasmine 测试超时 "Async callback was not invoked within 5000ms"

Jasmine test times out with "Async callback was not invoked within 5000ms" altghough no async function is used in my Angular project tests

这里是源代码:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';

import { HomePage } from './home.page';
import { LevelGridComponent } from '../level/level-grid/level-grid.component';
import { SidebarComponent } from '../sidebar/sidebar.component';
import { LevelStatusSidebarComponent } from '../level/level-status-sidebar/level-status-sidebar.component';

describe('HomePage', () => {
  let component: HomePage;
  let fixture: ComponentFixture<HomePage>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        HomePage,
        LevelGridComponent,
        SidebarComponent,
        LevelStatusSidebarComponent
      ],
      imports: [IonicModule.forRoot()]
    }).compileComponents();

    fixture = TestBed.createComponent(HomePage);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

现在测试打开浏览器,渲染组件,然后什么都不做,持续 5 秒,(因此)似乎超时:

HomePage should create FAILED Error: Timeout - Async callback was not invoked within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL) in node_modules/jasmine-core/lib/jasmine-core/jasmine.js (line 5494)

之前发生的事情

以前,我有常见的 Angular "this module is not defined" 错误,即:

'app-level-status-sidebar' is not a known element:
1. If 'app-level-status-sidebar' is an Angular component, then verify that it is part of this module.
2. If 'app-level-status-sidebar' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("

为了解决这个问题,我已将实际组件添加到 "declarations",如您在上面所见。

我认为这是因为在 HTML 中我使用了其他组件,即我在上面添加的组件。


由于测试其实很简单,我不希望这里有任何问题,而且它似乎也 运行 (我添加了 console.log 语句并且它们在 it('should create'.) 由于测试函数实际上并没有启动任何异步函数并且是 100% 同步的,所以我没想到这里会失败。

为了测试,我还向 it 测试函数添加了一个显式 done 函数调用,并在最后调用它,但这并没有改变任何东西。


编辑: 我想我已经解决了这个问题。好像是:

这里是定时器的源代码:

public timeLeft = 5;
// […]

private startTimer() {
    const counter$ = interval(1000);

    const takeFourNumbers = counter$.pipe(
      take(this.timeLeft),
      takeUntil(this.ngUnsubscribe)
    );
    takeFourNumbers.subscribe(x => {
      this.timeLeft--;
      if (this.timeLeft === 0) {
        this.levelTimeout.emit();
      }
    });
  }

这仍然没有解决定义测试内部组件的第一个问题,因为错误仍然发生,所以我仍然需要定义它们。 而且我仍然不明白为什么组件依赖链中随机未解析的 Observable 会导致组件在测试中以某种方式 "times out" 产生这种效果的技术细节。 (即使它只是被检查为 "truthy",即存在)

如果您正在对主页进行单元测试,则不应将子组件添加到您的声明中。相反,您可以只创建该组件的 Stubbed 版本。您可以将类似下面的内容放在规范文件的底部,然后将 StubLeveltatusSidebarComponent 添加到您的声明中(您可能还需要存根输入)。

@Component({ selector: 'app-level-status-sidebar', template: '' })

class StubLevelStatusSidebarComponent{}

或者,您可以尝试将以下内容添加到您的 configureTestingModule 对象中,它应该会忽略丢失的子项错误并继续进行测试。

schemas: [NO_ERRORS_SCHEMA]

我遇到了同样的问题。从“beforeEach”函数中删除“async”(或“waitForAsync”)。你不在那里使用任何“等待”:

beforeEach(() => {
  TestBed.configureTestingModule({
    declarations: [
      HomePage,
      LevelGridComponent,
      SidebarComponent,
      LevelStatusSidebarComponent
    ],
    imports: [IonicModule.forRoot()]
  }).compileComponents();

  fixture = TestBed.createComponent(HomePage);
  component = fixture.componentInstance;
  fixture.detectChanges();
});