我正在为React应用程序编写集成测试,即一起测试多个组件的测试,并且我希望模拟对外部服务的任何调用。
问题是测试似乎在异步回调执行之前执行,导致我的测试失败。
这周围有什么办法吗?我可以等待调用异步代码完成吗?
下面是一些糟糕的伪代码来说明我的观点。
我想测试一下,当我挂载Parent时,它的Child组件呈现从外部服务返回的内容,我将模拟它。
class Parent extends component {
render() {
<div>
<Child />
</div>;
}
}
class Child extends component {
DoStuff() {
aThingThatReturnsAPromise().then((result) => {
Store.Result = result;
});
}
render() {
DoStuff();
return <div>{Store.Result}</div>;
}
}
function aThingThatReturnsAPromise() {
return new Promise((resolve) => {
eternalService.doSomething(function callback(result) {
resolve(result);
});
});
}
当我在测试中这样做时,它失败了,因为它在回调被触发之前被执行。
jest.mock('eternalService', () => {
return jest.fn(() => {
return { doSomething: jest.fn((cb) => cb('fakeReturnValue');
});
});
describe('When rendering Parent', () => {
var parent;
beforeAll(() => {
parent = mount(<Parent />)
});
it('should display Child with response of the service', () => {
expect(parent.html()).toMatch('fakeReturnValue')
});
});
我该如何测试这个呢?我理解Angular 解析,这与zonejs有关,在React中是否有等效的方法?
7条答案
按热度按时间lx0bsm1f1#
针对Jest 27+更新
对于jest 27+,您还可以使用process.nextTick:
(感谢评论中的Adrian Godong)
原始答案
下面是一个等待未决承诺得到解决的代码段:
请注意,setImmediate是一个非标准特性(也不希望成为标准特性),但如果它对您的测试环境足够的话,应该是一个不错的解决方案。
此方法用于中断长时间运行的操作,并在浏览器完成其他操作(如事件和显示更新)后立即运行回调函数。
下面是使用async/await的大致方法:
如果您需要一些实际的示例,我经常使用in this project。
pkbketx92#
flushPromises
方法在某些情况下是失败。只需使用
await Promise.resolve()
即可:50few1ms3#
我建议您将
aThingThatReturnsAPromise()
从其模块或文件中导出,然后将其导入到测试用例中。由于
aThingThatReturnsAPromise()
返回一个承诺,因此可以利用Jest的异步测试特性,Jest将等待您的承诺得到解决,然后您可以进行Assert。要了解更多信息,请阅读Jest文档中Jest如何处理带有Promises的测试用例
v8wbuo2f4#
作为其他答案中列出的一些技术的替代方法,您也可以使用npm模块flush-promises。下面显示了一个包含两个测试的示例测试套件(参考的url中也显示了该测试套件):
xtupzzrd5#
我不知道任何原生的React,以完成你正在寻找的。
不过,我可以在安装完成后调用beforeAll()的@done,用类似的代码来完成这一点。
我从来没有使用过它们,但可能感兴趣的是Jest的runAllTicks和runAllImmediates。
w8rqjzmb6#
虽然伪代码可以被重构以遵循React生命周期(使用
componentWillMount()
componentDidMount()
,测试起来会容易得多。但是,下面是我对您的测试代码所做更改的未经测试的伪代码,请随时测试并更新它。希望它会对您有所帮助!uidvcgyl7#
其他的答案基本上可以归结为:“创造一个新的承诺并等待它解决”是不好的。他们只是等待当前悬而未决的承诺解决,但如果解决当前悬而未决的承诺创造了新的悬而未决的承诺!?你只能涵盖一轮的承诺使用类似
一个更通用的解决方案是用测试库中的
await act
Package 您的render
函数,如下所示:在此之后,在任何
useEffect
链中创建的所有承诺,甚至改变状态(响应于fetch
等等)的useEffect
,其导致更多的useEffect
运行,从而执行更多的fetch
等等--所有承诺将被解析并准备好Assert,而无需像测试库的waitFor
、findBy*
等等的异步机制。