Вычисляет ли Vue nextTick, когда вы ожидаете «что-нибудь» в тесте Jest?

#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 , семантически правильно связать его, по крайней мере, это явно указывает, чего мы ждем.