v-model в Vue представляет собой синтаксический сахар
для двусторонней привязки данных между родительским компонентом и
дочерним компонентом. В тестировании компонентов с использованием
Vue Test Utils важно понимать, как эта привязка
работает под капотом, чтобы корректно имитировать пользовательские
события и проверять обновления состояния.
В Vue 3 v-model работает через два ключевых
элемента:
По умолчанию:
modelValue.update:modelValue.// Дочерний компонент
export default {
props: {
modelValue: String
},
emits: ['update:modelValue'],
methods: {
updateValue(newValue) {
this.$emit('update:modelValue', newValue);
}
}
}
Использование v-model в родительском компоненте:
<ChildComponent v-model="text" />
Это эквивалентно:
<ChildComponent :modelValue="text" @update:modelValue="text = $event" />
Vue Test Utils предоставляет функцию mount для создания
экземпляра компонента в тестовой среде. Чтобы проверить
v-model, нужно передать значение через пропс и отследить
событие update:modelValue.
import { mount } from '@vue/test-utils';
import ChildComponent from '@/components/ChildComponent.vue';
test('должен корректно работать v-model', async () => {
const wrapper = mount(ChildComponent, {
props: {
modelValue: 'initial'
}
});
// Проверка начального значения
expect(wrapper.props('modelValue')).toBe('initial');
// Эмуляция изменения значения
await wrapper.vm.updateValue('updated');
// Проверка эмита события
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['updated']);
});
Ключевые моменты:
wrapper.props() возвращает текущие пропсы.wrapper.vm.$emit() позволяет вручную вызвать
событие.wrapper.emitted() хранит все события, которые были
вызваны компонентом.В реальном приложении v-model чаще всего обновляется
через элементы формы, такие как <input> или
<textarea>. Vue Test Utils позволяет симулировать эти
события:
const wrapper = mount(ChildComponent, {
props: { modelValue: '' }
});
const input = wrapper.find('input');
await input.setValue('новое значение');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['новое значение']);
Особенности:
setValue автоматически вызывает событие
input и обновляет привязку v-model.<input> в другой
метод, важно вызывать метод updateValue через
vm или симулировать кастомное событие.Vue 3 позволяет создавать кастомные модификаторы v-model
с собственными именами:
<ChildComponent v-model:title="pageTitle" />
В компоненте:
props: {
title: String
},
emits: ['update:title']
Тестирование аналогично стандартному v-model, только
нужно учитывать кастомное имя:
await wrapper.vm.$emit('update:title', 'Новый заголовок');
expect(wrapper.emitted()['update:title'][0]).toEqual(['Новый заголовок']);
Важно тестировать, как изменения пропсов родителя влияют на компонент
с v-model:
const wrapper = mount(ChildComponent, {
props: { modelValue: 'initial' }
});
await wrapper.setProps({ modelValue: 'changed' });
expect(wrapper.props('modelValue')).toBe('changed');
Особенности реактивности:
setProps обновляет пропсы и вызывает рендер компонента
заново.update:modelValue не вызывается при изменении
пропса извне — оно вызывается только внутри компонента.Прямое изменение пропса:
wrapper.props().modelValue = 'новое' не сработает, так как
props в Vue readonly. Использовать нужно setProps.
Игнорирование эмита события: Многие тесты
проверяют только внутреннее состояние, не учитывая, что родитель
получает изменения через update:modelValue.
Несоответствие имен: Кастомные
v-model требуют точного соответствия имен событий и
пропсов.
Асинхронность: Вызовы методов и симуляция
событий часто асинхронны, поэтому важно использовать await
для setValue, setProps и vm
методов.
В сложных компонентах v-model часто комбинируется с computed свойствами или watch. В этом случае тестирование включает:
const wrapper = mount(ParentComponent);
const input = wrapper.findComponent(ChildComponent).find('input');
await input.setValue('новое');
expect(wrapper.vm.parentValue).toBe('новое');
Такой подход позволяет проверять полную цепочку двусторонней привязки между родителем и дочерним компонентом.
Механизм v-model в Vue Test Utils становится прозрачным,
когда осознаются два ключевых аспекта: пропсы + эмит
события. Именно через правильное управление ими обеспечивается
корректная проверка двусторонней привязки в любых компонентах.