Angular2中使用setTimeout时的异步测试问题

3
我正在使用Angular2.0.1,并尝试编写针对带有异步任务的Angular组件的单元测试。我认为这是相当常见的事情。即使他们最新的测试示例也包括这些类型的异步测试(请参见此处)。然而,我的测试总是失败,并显示以下消息:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

长话短说,我花了几个小时才找到问题的真正来源。 我使用的是angular2-moment库,其中我使用了一个名为amTimeAgo的管道。这个管道包含一个window.setTimeout(...),它永远不会被移除。 如果我删除amTimeAgo管道,则测试成功,否则测试失败。
以下是一些非常基本的代码来重现此问题:

testcomponent.html:

{{someDate | amTimeAgo}}

testcomponent.ts:

import { Component } from "@angular/core";
import * as moment from "moment";

@Component({
    moduleId: module.id,
    templateUrl: "testcomponent.html",
    providers: [],
})
export class TestComponent{
    someDate = moment();

    constructor() {
    }
}

testmodule.ts

import { NgModule }      from "@angular/core";
import {MomentModule} from 'angular2-moment';
import { TestComponent } from './testcomponent';

@NgModule({
    imports: [
        MomentModule,
    ],
    declarations: [
        TestComponent,
    ]
})
export class TestModule {
}

testcomponent.spec.ts:

import { async, TestBed, ComponentFixture } from "@angular/core/testing";
import { TestComponent } from './testcomponent';
import { TestModule } from './testmodule';

let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;

function createComponent() {
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;

    fixture.detectChanges();
    return Promise.resolve();
}

describe("TestComponent", () => {
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [
                TestModule],
        }).compileComponents();
    }));

    it('should load the TestComponent', async(() => {
        createComponent().then(() => {
            expect(component).not.toBe(null);            
        });
    }));

});

有没有人知道如何成功地测试这个问题?我能否在afterEach中某种方式杀死所有“剩余”的超时?或者,我能否重置异步代码运行的区域以摆脱这个问题?

有人遇到过这个问题,或者知道如何成功测试吗?任何提示都将不胜感激。

更新: 在@peeskillet提示使用 fixture.destroy()的解决方案后,我尝试在我的实际测试中使用此方法(这里的示例只是为了重现问题所需的最小代码)。实际测试包含嵌套的promises,否则我不需要asyncdetectChanges 方法。

虽然销毁建议很好并且有助于解决简单测试中的问题,但我的实际测试包含以下语句,以确保嵌套的promises被正确解析:

it('should check values after nested promises resolved', async(() => {
    createComponent().then(() => {
        fixture.whenStable().then(() => {
            component.selectedToolAssemblyId = "2ABC100035";

            expect(component.selectedToolAssembly).toBeDefined();
            expect(component.selectedToolAssembly.id).toBe("2ABC100035");

            fixture.destroy();
        });
        fixture.detectChanges();
    });
}));

问题在于,页面中使用了amTimeAgo管道,fixture.whenStable()承诺从未得到解决,因此我的断言代码从未执行,测试仍然以相同的超时失败。
因此,即使销毁建议在给定的简化测试中起作用,它也不能让我修复实际测试。
谢谢
1个回答

3

参考: 这里是问题所在的管道

我认为问题在于组件在有待处理的异步任务时,即管道的情况下,async区域永远不会被销毁。 因此,管道的ngOnDestroy(删除超时)从未被调用,并且超时被挂起,这使区域等待。

有几个方法可以解决这个问题:

  1. I don't know what else you have in your component, but just from what you are showing, the test doesn't need to be using async. The only reason it does is because you are returning a promise from your createComponent method. If you forget the promise (or just call the method without thening) then the test will be synchonous and no need for async. The component gets destroyed after the test finishes. The test passes.

  2. This is the better solution though: Simply destroy the component yourself!

     fixture.destroy();
    

    Everyone's happy!

我测试了这两种解决方案,它们都有效。


更新

因此,对于这种情况达成一致的解决方案是模拟管道。 管道不会影响任何组件行为,因此我们不应该关心它的作用,因为它仅用于显示。 该管道已经由库的作者测试过,因此我们没有必要在组件内测试其行为。

@Pipe({
  name: 'amTimeAgo'
})
class MockTimeAgoPipe implements PipeTransform {
  transform(date: Date) {
    return date.toString();
  }
}

接下来只需从TestBed配置中移除MomentModule,并将MockTimeAgoPipe添加到declarations里即可。


嘿@peeskillet,感谢你的帮助。请查看我在问题上的更新。简要回顾:这解决了简单测试,但我的实际异步测试仍然存在相同的超时问题。 - Ben
我刚刚更新了问题中的代码,抱歉。问题在于 destroy 没有被执行,因为 whenStable 承诺从未被解决。 - Ben
1
稍后我会试着调试一下。我发现当任务仍在执行时,whenStable无法正常工作。也许我们需要一些绕过whenStable的方法。 - Paul Samsotha
1
说实话,如果我处于这种情况下,我会只是对管道进行模拟。管道不会影响任何组件的行为,它仅用于显示。你并不真正需要测试管道是否有效,因为这已经由库完成了。所以,只需进行模拟即可。 - Paul Samsotha
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Ben
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接