Angular Material提供component harnesses进行测试,通过await
兑现承诺,您可以与它们的组件进行交互,如下所示:
it('should click button', async () => {
const matButton = await loader.getHarness(MatButtonHarness);
await matButton.click();
expect(...);
});
但是,如果单击按钮会触发延迟操作怎么办?通常,我会使用fakeAsync()
/ tick()
来处理它:
it('should click button', fakeAsync(() => {
mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
// click button
tick(1000);
fixture.detectChanges();
expect(...);
}));
但是我有什么办法可以在同一测试中做到这两者?
在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(...);
})();
});
答案 0 :(得分:2)
您async
内不需要fakeAsync
(真实),至少可以控制模拟的时间流。 fakeAsync
的重点是允许您将await
替换为tick
/ flush
。现在,当您真正需要该值时,我认为您陷入了then
的困境,就像这样:
it('should click button', fakeAsync(() => {
mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
const resultThing = fixture.debugElement.query(By.css("div.result"));
loader.getHarness(MatButtonHarness).then(matButton => {
matButton.click();
expect(resultThing.textContent).toBeFalsy(); // `Service#load` observable has not emitted yet
tick(1000); // cause observable to emit
expect(resultThing.textContent).toBe(mockResults); // Expect element content to be updated
});
}));
现在,由于您的测试主体函数位于对fakeAsync
的调用中,因此它应该1)在解决所有创建的Promises(包括getHarness
返回的Promises)之前,不允许测试完成,和2)如果有任何待处理任务,则测试失败。
(顺便说一句,如果您将fixture.detectChanges()
管道与服务返回的Observable一起使用,我认为在第二个expect
之前不需要async
,因为async
管道在内部订阅触发时会显式地调用所有者的更改检测器。不过,我很想知道我是否错了。
答案 1 :(得分:1)
我刚刚发布了一个测试助手,可让您完全按照自己的要求进行操作。除其他功能外,它还允许您在 fakeAsync
测试中使用材料线束,并按照您的描述控制时间的流逝。
帮助程序会自动运行您在伪异步区域中传递给其 .run()
方法的内容,并且它可以处理 async/await
。它看起来像这样,您可以在其中创建 ctx
助手来代替 TestBed.createComponent()
(无论您在哪里这样做):
it('should click button', () => {
mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
ctx.run(async () => {
const matButton = await ctx.getHarness(MatButtonHarness);
await matButton.click();
ctx.tick(1000);
expect(...);
});
});
该库名为 @s-libs/ng-dev
。查看此特定助手 here 的文档,并通过 github here 让我知道任何问题。