我正在使用Angular2.0.1并尝试使用一些异步任务围绕角度组件编写单元测试。我要说,这是一件相当普遍的事情。甚至他们最新的测试示例也包括这些异步测试(参见here)。
我自己的测试永远不会成功,但总是没有消息
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);
});
}));
});
有没有人知道如何成功测试这个?我可以以某种方式杀死所有&#34;剩下的&#34;在afterEach中超时?或者我可以以某种方式重置异步代码运行的区域以摆脱这个问题吗?
是否有其他人遇到此问题或知道如何成功测试?任何提示都将不胜感激。
更新
@peeskillet在使用fixture.destroy()
暗示解决方案之后,我在实际测试中尝试了这个(这里的示例只是重现问题所需的最小代码)。实际测试包含嵌套的promise,否则我不需要async
和detectChanges
方法。
虽然破坏建议很好并且有助于简单测试中的问题,但我的实际测试包含以下语句以确保正确解析嵌套的promise:
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()
承诺永远不会被解析,因此我的断言代码永远不会被执行,并且测试仍会以相同的超时失败。
因此,即使销毁建议适用于给定的简化测试,也无法修复实际测试。
由于
本
答案 0 :(得分:3)
供参考: here is the problem pipe in question
我认为问题在于,当有待处理的异步任务时,组件永远不会在async
区域中被破坏,在这种情况下是管道。因此管道的ngOnDestroy
(删除超时)永远不会被调用,超时会挂起,这会使区域等待。
有几件事可以使它发挥作用:
我不知道你的组件中还有什么,但是根据你所展示的内容,测试并不需要使用{{1 }}。这样做的唯一原因是因为您从async
方法返回承诺。如果您忘记了承诺(或只是调用方法而不使用),那么测试将是同步的,不需要createComponent
。测试完成后,组件会被破坏。测试通过。
这是更好的解决方案:只需自行销毁组件!
async
每个人都快乐!
我测试了这两种解决方案,它们都有效。
因此,对于这个特殊情况的商定解决方案就是模拟管道。管道不会影响组件的任何行为,因此我们不应该关心它的作用,因为它只是用于显示。管道本身已经由库的作者进行测试,因此我们无需在组件内测试其行为。
fixture.destroy();
然后从@Pipe({
name: 'amTimeAgo'
})
class MockTimeAgoPipe implements PipeTransform {
transform(date: Date) {
return date.toString();
}
}
配置中取出MomentModule
,并将TestBed
添加到MockTimeAgoPipe