【问题标题】:React async await function blocks useDispatch in execution orderReact async await 功能块 useDispatch 按执行顺序
【发布时间】:2020-08-16 11:20:13
【问题描述】:

我有一个 React 钩子组件,onChange 事件将执行 aync-await 函数和一些调度,在我的模型测试中,如果我将 await function 放在任何调度之前,则未检测到 store.dispatch 被调用,如果我将调度放在等待函数之前,它只会检测到被调用,例如

const onChange = async (userId) => {
    await someAsyncFn(userId);
    dispatch(selectUser(userId));    //not detected
    dispatch(selectGroup(userId);    //not detected
};
--Test.js
expect(store.dispatch).toHaveBeenCalledTimes(2) ---failed, only receive 0 times

但如果我在调度后放置了等待,则测试用例通过了

const onChange = async (userId) => {
    dispatch(selectUser(userId));     //detected
    dispatch(selectGroup(userId);     //detected
    await someAsyncFn(userId);
};
--Test.js
expect(store.dispatch).toHaveBeenCalledTimes(2) ---passed receive 2 times

但是,如果我在调度之间放置了等待,则只会检测到上面的调度

const onChange = async (userId) => {
    dispatch(selectUser(userId));     //detected
    await someAsyncFn(userId);
    dispatch(selectGroup(userId);     //not detected
};
--Test.js
expect(store.dispatch).toHaveBeenCalledTimes(2) ---failed, only detect selectUser being called

当我运行我的应用程序时,上述 3 种情况之间的 UI 行为没有真正的区别,调度和我的等待功能都发生了,但我有点困惑,为什么我的测试用例无法检测到我的派遣?有没有办法绕过或强制从测试用例中解决我的 await 方法?

【问题讨论】:

  • 并且您确定承诺正在解决或拒绝...?可能是承诺没有被拒绝或解决。 (可能是超时并破坏了代码?)
  • 在实际应用中它已解决,但您指的是在 Jest 测试中执行时?有没有办法绕过异步等待?
  • 我已经模拟了要使用mockResolvedValue 解决的异步函数,并且我可以测试以验证正在调用的异步函数,但是调度似乎仍然没有触发
  • 请发布所有相关代码。见stackoverflow.com/help/mcve。不知道发生了什么事。它在一种情况下有效而在另一种情况下无效,这表明某处存在竞争条件,并且可以通过 await 延迟来避免。

标签: javascript async-await jestjs react-hooks enzyme


【解决方案1】:

您必须考虑到await 用于等待异步任务。因此,当您在 async 方法中调用 await 时,在异步任务解决之前,后面的代码不会执行。

很可能,您没有在测试代码中等待异步代码解析。这会导致在您的测试中不会考虑 await 之后的所有内容。

要等待异步代码解析,您必须将您的测试定义为async 和await 用于您的测试方法:

test('testing on change', async () => {

    // Perform the call to the onChange method. Await for it to resolve.
    await onChange();

    // At this point, the calls to dispatch will have been done independently of their order in the onChange method.
    expect(store.dispatch).toHaveBeenCalledTimes(2)
});

【讨论】:

  • 谢谢!但似乎我不能直接调用我的 onChange,我的 onChange 绑定到我的选择下拉列表,我正在通过 mount DOM 执行模拟“更改”来测试我的 onChange 中调用的所有内部方法,有没有办法在这里模拟 await?顺便说一句,如果我在这里等待,那么后面执行的代码是否真的会在运行测试时执行我的 someAsyncFn 中的任何内容?我实际的 someAsyncFn 是通过 http 调用加载一些图像文件
  • 或者有什么办法可以强制我的 someAsyncFn 被解析,我不在乎它在测试时是否能完成真正的工作,只是想确保它与我的两个调度方法一起被调用while 执行更改事件?
  • 另外,从性能的角度来看,我不太确定哪一个是通过调度订购我的 someAsyncFn 的最佳方式,我了解到 JavaScript 始终是同步的,没有哪个业务逻辑会先执行,如果我执行 await->dispatch 1->dispatch 2 与 dispatch 1->dispatch 2->await 会有性能差异吗?
猜你喜欢
  • 2022-08-14
  • 2019-07-01
  • 2018-12-15
  • 2021-09-30
  • 2020-04-13
  • 1970-01-01
  • 2018-06-25
  • 2017-09-11
  • 1970-01-01
相关资源
最近更新 更多