【问题标题】:Flushing a Promise queue?刷新 Promise 队列?
【发布时间】:2020-08-24 15:57:27
【问题描述】:

在使用 Jest 编写测试时,异步模拟 Axios 请求导致在安装组件后调用 setState()。这导致在测试运行期间出现控制台输出。

it('renders without crashing', () => {
  const mockAxios = new MockAdapter(axios);

  mockAxios.onGet(logsURL).reply(200, [...axios_logs_simple]);

  const div = document.createElement('div');
  ReactDOM.render(<Logs />, div);
  ReactDOM.unmountComponentAtNode(div);
});

在&lt;Logs&gt; 组件中:

componentDidMount() {
  axios.get(apiURL).then(response => {
    this.setState({data: response.data});
  });
}

我发现 blog post 显示了一个解决方案,但我不明白它是如何发挥作用的:

it('renders without crashing', async () => { //<-- async added here
  const mockAxios = new MockAdapter(axios);

  mockAxios.onGet(logsURL).reply(200, [...axios_logs_simple]);

  const div = document.createElement('div');
  ReactDOM.render(<Logs />, div);
  await flushPromises(); //<-- and this line here.
  ReactDOM.unmountComponentAtNode(div);
});

const flushPromises = () => new Promise(resolve => setImmediate(resolve));

据我了解,它创建了一个立即解决的新承诺。那如何保证其他异步代码也能解决?

现在,它解决了这个问题。测试运行期间没有更多控制台消息。测试仍然通过(这不是一个很好的测试)。但这看起来就像我只是落在了竞争条件的另一边,而不是一开始就阻止了竞争条件。

【问题讨论】:

    标签: reactjs mocking jestjs axios es6-promise


    【解决方案1】:

    我将从您需要此解决方案的原因开始。

    原因是您没有对 异步任务 的引用,并且您需要测试断言在 异步之后运行任务。 如果你有它,你可以在上面await,这将确保你的测试断言将在异步任务之后运行。 (在你的情况下是ReactDOM.unmountComponentAtNode)

    在您的示例中,异步任务位于 componentDidMount 内,它会响应调用,因此您没有对异步任务的引用。

    flushPromises 的简单实现通常是:

    const flushPromises = () => new Promise(resolve => setImmediate(resolve));
    

    此实现基于 javascript 中的异步操作基于 任务队列(javascript 有多种类型的异步任务队列)。 具体来说,承诺在微任务队列中排队。每次异步操作(如 http 请求)完成时,异步任务就会出列并执行。

    setImmediate 是一种获取回调并将其存储在Immediates Queue 中的方法,并将在事件循环的下一次迭代中调用。 这个Immediates Queue 是在微任务队列(包含承诺)之后检查的。

    让我们分析一下代码,我们正在创建一个新的 Promise,它在 Micro-task queue 的 end 排队,它的 resolve 将在事件循环的下一次迭代中被调用,即意味着它将在所有已经入队的承诺之后解决。

    希望这个解释有所帮助。

    注意如果在异步任务中你将一个新的promise加入队列,它会在最后进入队列,这意味着flushPromises返回的promise不会在它之后运行.

    很少有帖子/视频了解更多信息:

    1. https://blog.insiderattack.net/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-9226cbe7a6aa
    2. https://www.youtube.com/watch?v=8aGhZQkoFbQ
    3. https://www.youtube.com/watch?v=cCOL7MC4Pl0

    【讨论】:

    • 非常感谢兄弟!!
    • 值得注意的是,setImmediate 在 Jest 27 github.com/facebook/jest/pull/11222 中已从 jsdom 中删除,因此这在 Jest 测试中将不再起作用。相反,您可以使用setTimeout。所以例子变成了:const flushPromises = () =&gt; new Promise(resolve =&gt; setTimeout(resolve, 0));
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2017-10-14
    • 2014-08-26
    相关资源
    最近更新 更多