pet*_*176 2 javascript ecmascript-6 reactjs jestjs enzyme
我有一个等待多个承诺的函数
const function = async () => {
await function1()
await function2()
await function3()
}
Run Code Online (Sandbox Code Playgroud)
我想测试 function3 被调用:
it(('calls function3', async () => {
jest.spyOn(api, 'function1').mockResolvedValue({})
jest.spyOn(api, 'function2').mockResolvedValue({})
spy = jest.spyOn(api, 'function3')
await function()
expect(spy).toBeCalledTimes(1)
})
Run Code Online (Sandbox Code Playgroud)
这个测试失败了,但是当我多次调用 await 时:
it(('calls function3', async () => {
jest.spyOn(api, 'function1').mockResolvedValue({})
jest.spyOn(api, 'function2').mockResolvedValue({})
spy = jest.spyOn(api, 'function3')
await await await await await function()
expect(spy).toBeCalledTimes(1)
})
Run Code Online (Sandbox Code Playgroud)
测试将通过。为什么是这样?await function()在进入下一个期望行之前不应该解决所有的承诺吗?
编辑:等待的函数越深,即函数 4,我需要的等待语句越多,但它不是 1 比 1。
await function()在进入下一个期望行之前不应该解决所有的承诺吗?
是的,在继续之前await将等待返回Promise。
这是一个简单的工作示例:
const function1 = jest.fn().mockResolvedValue();
const function2 = jest.fn().mockResolvedValue();
const function3 = jest.fn().mockResolvedValue();
const func = async () => {
await function1();
await function2();
await function3();
}
it('calls function3', async () => {
await func();
expect(function3).toHaveBeenCalled(); // Success!
})
Run Code Online (Sandbox Code Playgroud)
如果await没有像预期的那样等待,那么Promise链条很可能在某个时候被破坏了。
下面是一个Promise断链的例子:
const function1 = jest.fn().mockResolvedValue();
const function2 = jest.fn().mockResolvedValue();
const function3 = jest.fn().mockResolvedValue();
const func = async () => {
await function1();
await function2();
await function3();
}
const func2 = async () => {
func(); // <= breaks the Promise chain
}
it('calls function3', async () => {
await func2();
expect(function3).toHaveBeenCalled(); // <= FAILS
})
Run Code Online (Sandbox Code Playgroud)
await多次调用会将其余的测试函数排在PromiseJobs队列的后面多次,这可以让挂起的Promise回调有机会运行......
...因此,如果将其更改为以下内容,则上面的损坏测试将通过:
it('calls function3', async () => {
await await await await func2(); // <= multiple await calls
expect(function3).toHaveBeenCalled(); // Success...only because of multiple await calls
})
Run Code Online (Sandbox Code Playgroud)
...但真正的解决方案是找到并修复Promise链条断裂的地方:
const func2 = async () => {
await func(); // <= calling await on func fixes the Promise chain
}
it('calls function3', async () => {
await func2();
expect(function3).toHaveBeenCalled(); // Success!
})
Run Code Online (Sandbox Code Playgroud)
这是承诺在微任务队列中排队的顺序问题,我用它flush-promises来解决同样的问题。
它使用节点setImmediate将回调推送到队列,当微任务队列为空时将调用该回调。
const flushPromises = require('flush-promises');
test('flushPromises', async () => {
let a;
let b;
Promise.resolve().then(() => {
a = 1;
}).then(() => {
b = 2;
})
await flushPromises();
expect(a).toBe(1);
expect(b).toBe(2);
});
Run Code Online (Sandbox Code Playgroud)