在我的测试中,我想阻塞我的主线程,直到我的一个组件通过componentDidUpdate()
结束了其生命周期方法的生命周期,之后我触发了一个事件,该事件使它向自己添加了子组件。我该怎么办?
像这样的东西:
describe('my <Component />', () => {
it('should do what I want when its button is clicked twice', () => {
const wrapper = mount(<Component />);
const button = wrapper.find('button');
// This next line has some side effects that cause <Component /> to add
// some children components to itself...
button.simulate('click', mockEvent);
// ... so I want to wait for those children to completely go through
// their lifecycle methods ...
wrapper.instance().askReactToBlockUntilTheComponentIsFinishedUpdating();
// ... so that I can be sure React is in the state I want it to be in
// when I further manipulate the <Component />
button.simulate('click', mockEvent);
expect(whatIWant()).to.be.true;
});
});
(我想这样做是因为,现在,我收到以下警告:
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.
我相信我得到它是因为我的测试导致我的组件改变其内部状态的速度超过了React内部的多线程魔术所能跟上的速度,所以当我第二次运行
button.simulate('click')
时,React实例化了新的子组件,但是尚未完成安装。我认为等待React完成更新我的Component及其子元素是解决该问题的最佳方法。) 最佳答案
尝试将expect()
块包装在setImmediate()
块中:
describe('my <Component />', () => {
it('should do what I want when its button is clicked twice', (done) => {
const wrapper = mount(<Component />);
const button = wrapper.find('button');
button.simulate('click', mockEvent);
button.simulate('click', mockEvent);
setImmediate(() => {
expect(whatIWant()).to.be.true;
done();
});
});
});
这是怎么回事:为了处理异步性,Node和大多数浏览器在后台都有一个事件队列。每当需要异步运行诸如Promise或IO事件之类的内容时,JS环境就会将其添加到队列的末尾。然后,每当同步代码完成运行时,环境就会检查队列,选择队列前面的内容,然后运行它。
setImmediate()
将一个函数添加到队列的后面。一旦当前队列中的所有内容完成运行,传递给setImmediate()
的函数中的任何内容都将运行。因此,无论React在异步执行什么操作,都将expect()
包裹在setImmediate()
中将使您的测试等待,直到React在后台完成其异步工作为止。这是一个有关
setImmediate()
的更多信息的好问题:setImmediate vs. nextTick这是Node中
setImmediate()
的文档:https://nodejs.org/api/timers.html#timers_setimmediate_callback_args