Reactjs 如何使Jest在等待断言之前等待所有异步代码完成执行

Reactjs 如何使Jest在等待断言之前等待所有异步代码完成执行,reactjs,mocking,jestjs,enzyme,Reactjs,Mocking,Jestjs,Enzyme,我正在为React应用程序编写一个集成测试,即一个将多个组件一起测试的测试,我想模拟对外部服务的任何调用 问题是,测试似乎在异步回调执行之前执行,导致测试失败 这有什么关系吗?我是否可以等待调用异步代码完成 下面是一些糟糕的伪代码来说明我的观点 我想测试一下,当我挂载Parent时,它的子组件呈现从外部服务返回的内容,我将对其进行模拟 类父级扩展组件 { 渲染() { } } 类子扩展组件 { 多斯塔夫() { AthingAtReturnsPromise()。然后((结果)=>{ Store.

我正在为React应用程序编写一个集成测试,即一个将多个组件一起测试的测试,我想模拟对外部服务的任何调用

问题是,测试似乎在异步回调执行之前执行,导致测试失败

这有什么关系吗?我是否可以等待调用异步代码完成

下面是一些糟糕的代码来说明我的观点

我想测试一下,当我挂载Parent时,它的子组件呈现从外部服务返回的内容,我将对其进行模拟

类父级扩展组件
{
渲染()
{
}
}
类子扩展组件
{
多斯塔夫()
{
AthingAtReturnsPromise()。然后((结果)=>{
Store.Result=Result
})
}
render()
{
多斯塔夫()
返回({Store.Result})
}
}
ATReturnasPromise()的函数
{
返回新承诺(解决=>{
eternalService.doSomething(函数回调(结果){
解决(结果)
}
}
}
当我在测试中这样做时,它失败了,因为它在启动回调之前被执行

jest.mock('ternalservice',()=>{
return jest.fn(()=>{
返回{doSomething:jest.fn((cb)=>cb('fakeReturnValue');
});
});
描述('呈现父对象时',()=>{
var父代;
以前(()=>{
parent=mount()
});
它('应该显示带有服务响应的子项',()=>{
expect(parent.html()).toMatch('fakeReturnValue')
});
});

我如何测试它?我知道angular可以用zonejs解决这个问题,React中有没有等效的方法?

我不知道有什么本地方法可以通过React来完成您想要的任务

但是,在安装完成后,通过调用beforeAll()的@done,我可以在类似的代码中实现这一点。请参阅下面对代码的更改:

让设置完成;
jest.mock('ternalservice',()=>{
return jest.fn(()=>{
返回{doSomething:jest.fn((cb)=>{cb('fakeReturnValue');setupComplete();});
});
.
.
.
之前(完成=>{
parent=mount()
设置完成=完成;
});

});
虽然可以重构伪代码以遵循React生命周期(使用
componentWillMount()
componentDidMount()
),但测试起来要容易得多。不过,下面是我未测试的伪代码,请随时测试并更新。希望它能帮助您

describe('When rendering Parent', () => {
    it('should display Child with the response of the service', function(done) => {
        const parent = mount(<Parent />);
        expect(parent.html()).toMatch('fakeReturnValue');
        done();
    });
});
descripe('呈现父对象时',()=>{
它('应该显示带有服务响应的子项',函数(完成)=>{
const parent=mount();
expect(parent.html()).toMatch('fakeReturnValue');
完成();
});
});

下面是一个等待未决承诺得到解决的片段:

constflushpromises=()=>newpromise(setImmediate);
请注意,这是一个非标准功能(预计不会成为标准功能)。但如果它足以满足您的测试环境,则应该是一个很好的解决方案。其说明:

此方法用于中断长时间运行的操作,并在浏览器完成其他操作(如事件和显示更新)后立即运行回调函数

下面大致介绍了如何使用async/await使用它:

it('是使用flushPromises的示例',异步()=>{

const wrapper=mount(如果您想要一些实际工作的示例。

我建议您从其模块或文件导出
AtReturnsPromise()
,然后将其导入测试用例

由于
atreturnsapromise()
返回承诺,因此您可以利用Jest的异步测试功能。Jest将等待您的承诺得到解决,然后您可以做出断言

describe('When rendering Parent', () => {
    var parent;

    beforeAll(() => {
        parent = mount(<Parent />)
    });

    it('should display Child with response of the service', () => {
        expect.assertions(1);

        return aThingThatReturnsAPromise().then( () => {
            expect(parent.html()).toMatch('fakeReturnValue');
        });
    });
});
descripe('呈现父对象时',()=>{
var父代;
以前(()=>{
parent=mount()
});
它('应该显示带有服务响应的子项',()=>{
期望.断言(1);
返回ATHENTATURNSAPROMISE()。然后(()=>{
expect(parent.html()).toMatch('fakeReturnValue');
});
});
});

有关更多信息,请阅读Jest如何在Jest文档中处理带有承诺的测试用例作为其他答案中列出的一些技术的替代方法,您也可以使用npm模块。下面显示了一个包含两个测试的示例测试套件(如参考url所示):

const flushPromises=require('flush-promises');
描述('异步承诺测试套件',()=>{
它('涉及flushPromises的测试',异步()=>{
const wrapper=mount();
等待flushPromises();
//更多代码
});
它('没有刷新承诺将无法正常工作',异步()=>{
让我们一起来;
让b;
Promise.resolve()然后(()=>{
a=1;
}).然后(()=>{
b=2;
})
等待flushPromises();
期望(a)为(1);
期望(b)为(2);
});
});

@Gegenwind没有关系?它只是
expect.assertions()
的东西。我不会在回答中从doc中转储一个例子…非常好!如果你想让它更简洁一点,你可以进一步简化该函数:
const flushPromises=()=>新承诺(setImmediate);
flushPromises和
Wait Promise.resolve()之间有什么区别
?他们如何以不同的方式等待微任务队列?询问,因为我可以使用
承诺。当只有一个承诺需要满足,但
flushPromises
是必需的时,解决问题。此函数确实有帮助,但我很快就明白了为什么它不等待。处理承诺的行没有
awai