В настоящих приложениях наши компоненты скорее всего будут иметь внешние зависимости. Было бы прекрасно, если бы мы могли полностью контролировать эти зависимости в наших тестах, чтобы они опирались только на поведение тестируемого компонента.
Для этого в модульных тестах используется понятие "мок" ("mock") – это объект, за вызовами методов которого мы можем следить и даже управлять их результатами. Чтобы не тестировать и компонент, и его зависимость в связке, нам достаточно внедрить вместо зависимости созданный мок-объект.
vue-loader
предоставляет возможность внедрять произвольные зависимости в *.vue
компоненты, используя inject-loader. Основная идея состоит в том, что вместо прямой подгрузки модуля компонента мы используем inject-loader
, чтобы создать "фабричную функцию" для этого модуля. Когда мы вызовем эту функцию с мок-объектом, она вернет нам экземпляр модуля с внедренными мок-объектами.
Допустим, у нас есть следующий компонент:
<!-- example.vue -->
<template>
<div class="msg">{{ msg }}</div>
</template>
<script>
// эту зависимость нужно подменить мок-объектом
import SomeService from '../service'
export default {
data () {
return {
msg: SomeService.msg
}
}
}
</script>
Вот как получить его с мок-объектами:
Заметка: [email protected] еще не в стабильной версии
npm install inject-loader@^2.0.0 --save-dev
// example.spec.js
const ExampleInjector = require('!!vue-loader?inject!./example.vue')
Обратите внимание на эту безумную строку импорта – мы используем запросы к webpack загрузчику. Краткое пояснение:
!!
в начале строки означает "отключи все загрузчики из глобальной конфигурации"vue-loader?inject!
значит "используй загрузчикvue-loader
и передай запрос?inject
". Это заставляетvue-loader
скомпилировать компонент в режиме внедрения зависимостей.
Полученный ExampleInjector
– это фабричная функция, которую можно вызвать, чтобы создать экземпляр модуля example.vue
:
const ExampleWithMocks = ExampleInjector({
// mock it
'../service': {
msg: 'Привет от мок-сервиса!'
}
})
Наконец, мы можем тестировать компонент как обычно:
it('should render', () => {
const vm = new Vue({
template: '<div><test></test></div>',
components: {
'test': ExampleWithMocks
}
}).$mount()
expect(vm.$el.querySelector('.msg').textContent).toBe('Привет от мок-сервиса!')
})