我的示例组件显示了一个计数器(最初为"0"(和一个"0";增加";按钮它看起来像这样:
<div ref="label">{{ counter }}</div>
<div
ref="button"
@click="counter++"
>
Click me
</div>
如果我用Jest测试点击行为,下面的测试将无法通过
it('increases the counter when the button is clicked', async () => {
const button = testComponent.findComponent({ ref: 'button' })
button.vm.$emit('click');
const label = testComponent.findComponent({ ref: 'label' })
expect(label.text()).toBe('1'); // fails
});
正如我正确理解的那样,事件处理程序是同步调用的,但DOM更新仍在Vue的异步更新队列中等待。因此,为了使测试工作正常,我必须等待Vue.$nextTick()
来更新DOM:
it('increases the counter when the button is clicked', async () => {
const button = testComponent.findComponent({ ref: 'button' })
button.vm.$emit('click');
await Vue.$nextTick();
const label = testComponent.findComponent({ ref: 'label' })
expect(label.text()).toBe('1'); // succeeds
});
但是我可以等待任何来更新DOM。我可以等待一个空物体,测试就会成功:
it('increases the counter when the button is clicked', async () => {
const button = testComponent.findComponent({ ref: 'button' })
button.vm.$emit('click');
await {};
const label = testComponent.findComponent({ ref: 'label' })
expect(label.text()).toBe('1'); // succeeds
});
我不明白为什么会这样。这是耶稣的一种特殊行为吗?为什么这样有效?
await null
是等待一段时间直到另一个在结算之前创建的承诺的通用方法,只有当另一个承诺立即结算时,它才能正常工作:
Promise.resolve().then(() => console.log('foo'));
await null;
console.log('bar'); // output is foo bar
文档建议将等待承诺的flush-promises
与setTimeout
或setImmediate
一起使用,这是一种等待更多的方式。
nextTick
返回一个立即解析的promise,因此await Vue.nextTick()
可以替换为await null
。这在未来的Vue版本中不太可能改变,但如果改变了,这将破坏使用await null
的代码。如果一个可以等待的承诺是可访问的,就像nextTick
的情况一样,那么将其链接在语义上是正确的,至少这明确地指定了我们等待的内容。