刷新承诺队列?

问题描述 投票:0回答:1

[使用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);
});

并且在<Logs>组件中:

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个回答
0
投票

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

原因是您对异步任务没有引用,并且需要测试断言才能运行之后异步任务。如果拥有它,则只需在其上单击await,这将确保您的测试断言将在异步任务中运行。 (您的情况是ReactDOM.unmountComponentAtNode在您的示例中,异步任务位于componentDidMount中,它可以响应调用,因此您没有对异步任务的引用。

通常,flushPromises的简单实现是:

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

此实现基于以下事实:javascript中的异步操作基于

任务队列

(javascript有几种类型的异步任务队列)。具体来说,承诺会在微任务队列中排队。每次异步操作(例如http请求)完成异步任务的出队并执行。setImmediate是一种获取回调并将其存储在setImmediate上的方法,并将在事件循环的下一次迭代中调用。在微任务队列(包含承诺)中,Immediates Queue被选中。

让我们分析代码,我们正在创建一个新的Promise,它在Immediates Queueend

处排队,在事件循环的下一次迭代中将调用Micro-task queue,这意味着它将在所有已兑现的诺言之后解决。

希望这会有所帮助。

[注意]],如果在异步任务中加入新的诺言,它将在最后进入队列,这意味着resolve返回的诺言将不在其后运行。

很少有帖子/视频以获取更多信息:

flushPromises

    https://blog.insiderattack.net/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-9226cbe7a6aa
  • https://www.youtube.com/watch?v=8aGhZQkoFbQ
  • © www.soinside.com 2019 - 2024. All rights reserved.