#vue.js #events #async-await #jestjs
#vue.js #Мероприятия #асинхронное ожидание #jestjs
Вопрос:
В моем примере компонента отображается счетчик (изначально «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
});
Я не могу понять, почему это так. Это специфическое поведение Jest? Почему это работает?
Комментарии:
1. Потому что ожидание чего- либо дает контроль и позволяет среде выполнения оценивать содержимое в очереди микрозадач.
Ответ №1:
await null
это общий способ немного подождать, пока не будет выполнено другое обещание, созданное до того, как оно будет выполнено, оно работает по назначению, только если другое обещание выполняется мгновенно:
Promise.resolve().then(() => console.log('foo'));
await null;
console.log('bar'); // output is foo bar
В документации предлагается использовать flush-promises
это ожидание обещания вместе с setTimeout
or setImmediate
и это способ подождать еще немного.
nextTick
возвращает обещание, которое мгновенно разрешается, поэтому await Vue.nextTick()
его можно заменить await null
. Маловероятно, что это будет изменено в будущих версиях Vue, но если это произойдет, это нарушит код, который использует await null
. Если доступно ожидаемое обещание, как в случае nextTick
, семантически правильно связать его, по крайней мере, это явно указывает, чего мы ждем.