В тестировании Vue-компонентов директивы представляют особую сложность. Пользовательские директивы часто работают напрямую с DOM, используют сторонние библиотеки, подписываются на события, управляют фокусом, анимациями или размерами элементов. В модульных тестах подобное поведение избыточно и мешает изоляции компонента. Стабирование директив позволяет:
Vue Test Utils предоставляет встроенные механизмы для подмены директив упрощёнными версиями или заглушками.
При монтировании компонента Vue Test Utils использует обычный механизм Vue. Это означает:
directives компонента
подключаются автоматически;beforeMount, mounted,
updated, unmounted) реально выполняются.Без стабирования директива будет вести себя так же, как в браузере, что нежелательно для unit-тестов.
global.directivesОсновной способ стабирования — передача заглушек в параметре
global.directives при mount или
shallowMount.
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'
const wrapper = mount(MyComponent, {
global: {
directives: {
focus: {
mounted() {}
}
}
}
})
В данном примере директива v-focus заменяется пустой
реализацией. Все её хуки могут быть описаны явно или опущены.
Ключевые особенности:
v-;Часто нет необходимости объявлять хуки вовсе. Vue Test Utils допускает использование пустого объекта:
directives: {
tooltip: {}
}
Такой стаб отключает директиву целиком. Vue не будет вызывать никаких хуков, но шаблон успешно скомпилируется.
Подобный подход подходит для директив, которые:
Иногда требуется проверить, что директива применяется к элементу. Для этого стаб может содержать шпионов.
const mountedSpy = vi.fn()
mount(MyComponent, {
global: {
directives: {
intersect: {
mounted: mountedSpy
}
}
}
})
Это позволяет:
el,
binding, vnode).Хуки директив получают объект binding, содержащий:
valueargmodifiersinstanceСтаб может анализировать эти данные:
directives: {
permission: {
mounted(el, binding) {
if (binding.value !== 'admin') {
el.remove()
}
}
}
}
Такой стаб имитирует упрощённую бизнес-логику директивы без зависимости от реальной реализации.
shallowMountshallowMount не стабирует директивы автоматически. Они
продолжают выполняться, если не подменены явно.
shallowMount(MyComponent, {
global: {
directives: {
resize: {}
}
}
})
Важно учитывать:
shallowMount стабирует дочерние компоненты, но не
директивы;Если директива используется во многих тестах, её стабирование удобно вынести в глобальную конфигурацию.
config.global.directives = {
clickOutside: {}
}
Преимущества:
Недостаток — потеря гибкости, если в отдельных тестах требуется особое поведение директивы.
Иногда требуется сохранить часть логики директивы, но отключить побочные эффекты.
import realDirective from '@/directives/scroll'
directives: {
scroll: {
mounted(el, binding) {
// пропущена подписка на window
realDirective.mounted(el, binding)
}
}
}
Подобный подход полезен, когда:
Директивы, которые:
лучше стабировать максимально примитивно. В противном случае тесты начинают проверять детали реализации директивы вместо логики компонента.
directives: {
autoHeight: {
mounted(el) {
el.style.height = '100px'
}
}
}
Это позволяет сохранить предсказуемое состояние DOM.
Неправильное имя директивы
directives: {
vFocus: {} // ошибка
}
Используется имя без v- и без camelCase-преобразований
шаблона.
Ожидание автоматического стабирования
Vue Test Utils не стабирует директивы автоматически ни при каких режимах монтирования.
Смешивание стабов и реальных глобальных директив
Если директива зарегистрирована глобально в приложении, но не стабирована в тесте, будет использована реальная версия.
Стабирование не всегда оправдано. Реальную директиву имеет смысл оставить, если:
В таких случаях директива должна иметь собственные unit-тесты, а компонент — интеграционные тесты с реальной директивой.
Стабирование директив в Vue Test Utils — инструмент управления сложностью тестов. Оно позволяет строго изолировать компонент, контролировать побочные эффекты и сфокусироваться на проверке реактивности, событий и вычисляемых состояний. Грамотное использование стабов делает тесты стабильными, быстрыми и легко поддерживаемыми.