В этой статье объясняется, как использовать глобальную шину событий в VueJS. Он описывает альтернативный метод обычному подходу, использующему шину событий, определенную в отдельном файле:
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;
. Он должен быть импортирован в каждый SF C, где это необходимо. Альтернативный подход присоединяет шину глобальных событий к основному экземпляру Vue:
// main.js
import Vue from 'vue';
Vue.prototype.$eventBus = new Vue(); // I call it here $eventBus instead of $eventHub
new Vue({
el: '#app',
template: '<App/>',
});
// or alternatively
import Vue from 'vue';
import App from './App.vue';
Vue.prototype.$eventBus = new Vue();
new Vue({
render: (h): h(App),
}).$mount('#app');
Теперь у меня проблема в том, что я не знаю, как использовать шину глобальных событий, созданную таким образом в модуле tests.
Уже существует вопрос о тестировании шины глобальных событий с использованием первого упомянутого подхода, но ответ не принимается.
Я попытался, как предложено в одном из отвечает на использование createLocalVue
, но это не помогло:
it('should listen to the emitted event', () => {
const wrapper = shallowMount(TestingComponent, { localVue });
sinon.spy(wrapper.vm, 'handleEvent');
wrapper.vm.$eventBus.$emit('emit-event');
expect(wrapper.vm.handleEvent.callCount).to.equal(1);
});
Это говорит о ожидаемом 0, фактическом 1. Я пробовал с async
функцией и $nextTick()
, но без успеха.
Для предыдущего примера я использую mocha
, chai
и sinon
. Это только для иллюстрации. Ответы с использованием jest
или любой другой инфраструктуры тестирования / библиотеки утверждений приветствуются.
РЕДАКТИРОВАТЬ 25 февраля 2020 года
Чтение книги "Тестирование Vue. js Приложения " от Эдда Йербурга, автора @vue/test-utils
, я выдвинул некоторые идеи, но я все еще пытаюсь понять, как выполнить sh тестирование шины глобального события, добавленной как свойство экземпляра. В книге свойства экземпляра проверяются в модульных тестах.
Я создал git хранилище с примером кода, следующим за статьей от medium.com . Для этого примера я использовал jest
для модульного тестирования.
Это код:
src/main.js
import Vue from 'vue';
import App from './App.vue';
<strong>// create global event bus as instance property
Vue.prototype.$eventBus = new Vue();</strong>
Vue.config.productionTip = false;
new Vue({
render: (h) => h(App),
}).$mount('#app');
src/App.vue
<template>
<div id="app">
<hello-world></hello-world>
<change-name></change-name>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
import ChangeName from './components/ChangeName.vue';
export default {
name: 'App',
components: {
HelloWorld,
ChangeName,
},
};
</script>
src/components/HelloWorld.vue
<template>
<div>
<h1>Hello World, I'm {{ name }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
name: 'Foo',
};
},
created() {
this.$eventBus.$on('change-name', this.changeName);
},
beforeDestroy() {
this.$eventBus.$off('change-name');
},
methods: {
changeName(name) {
this.name = name;
},
},
};
</script>
src/components/ChangeName.vue
Изменить имя
<script>
export default {
name: 'ChangeName',
data() {
return {
newName: '',
};
},
methods: {
changeName() {
this.$eventBus.$emit('change-name', this.newName);
},
},
};
</script>
Это очень простое приложение с двумя компонентами. Компонент ChangeName.vue
имеет элемент ввода, и пользователь может вызвать метод, нажав кнопку. Метод генерирует событие change-name
с использованием глобальной шины событий. Компонент HelloWorld.vue
прослушивает событие change-name
и обновляет свойство модели name
.
. Вот как я пытался его протестировать:
tests\unit\HelloWorld.spec.js
import { shallowMount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';
describe('HelloWorld.vue', () => {
const mocks = {
$eventBus: {
$on: jest.fn(),
$off: jest.fn(),
$emit: jest.fn(),
},
};
it('listens to event change-name', () => {
<strong>// this test passes</strong>
const wrapper = shallowMount(HelloWorld, {
mocks,
});
expect(wrapper.vm.$eventBus.$on).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$eventBus.$on).toHaveBeenCalledWith('change-name', wrapper.vm.changeName);
});
it('removes event listener for change-name', () => {
<strong>// this test does not pass</strong>
const wrapper = shallowMount(HelloWorld, {
mocks,
});
expect(wrapper.vm.$eventBus.$off).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$eventBus.$off).toHaveBeenCalledWith('change-name');
});
it('calls method changeName on event change-name', () => {
<strong>// this test does not pass</strong>
const wrapper = shallowMount(HelloWorld, {
mocks,
});
jest.spyOn(wrapper.vm, 'changeName');
wrapper.vm.$eventBus.$emit('change-name', 'name');
expect(wrapper.vm.changeName).toHaveBeenCalled();
expect(wrapper.vm.changeName).toHaveBeenCalledWith('name');
});
});
tests\unit\ChangeName.spec.js
import { shallowMount } from '@vue/test-utils';
import ChangeName from '@/components/ChangeName.vue';
describe('ChangeName.vue', () => {
const mocks = {
$eventBus: {
$on: jest.fn(),
$off: jest.fn(),
$emit: jest.fn(),
},
};
it('emits an event change-name', () => {
<strong>// this test passes</strong>
const wrapper = shallowMount(ChangeName, {
mocks,
});
const input = wrapper.find('input');
input.setValue('name');
const button = wrapper.find('button');
button.trigger('click');
expect(wrapper.vm.$eventBus.$emit).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$eventBus.$emit).toHaveBeenCalledWith('change-name', 'name');
});
});
TL; DR
Это очень длинный вопрос , но в большинстве случаев это примеры кода. Вопрос в том, как выполнить модульное тестирование глобальной шины событий, созданной как Vue свойство экземпляра?
В частности, у меня возникла проблема с пониманием третьего теста в tests/unit/HelloWorld.spec.js
. Как проверить, что метод вызывается при отправке события? Должны ли мы вообще проверять это поведение в модульных тестах?