Монтирование экземпляра vue с помощью avoriaz, но не может шпионить за импортированной функцией
У меня есть следующий компонентный скрипт (некоторые ненужные биты удалены):
import api from '@/lib/api';
export default {
methods: {
upload (formData) {
api.uploadFile(formData).then(response => {
this.$emit('input', response.data);
});
}
}
};
И у меня есть следующий тест, который использует avoriaz для монтирования экземпляра Vue:
import { mount } from 'avoriaz';
import { expect } from 'chai';
import sinon from 'sinon';
import UploadForm from '@/components/UploadForm';
describe('upload', () => {
it('passes form data to api.uploadFile', () => {
const testFormData = { test: 'test' };
const api = {
uploadFile: sinon.spy()
};
const wrapper = mount(UploadForm);
wrapper.vm.api = api;
wrapper.vm.upload(testFormData);
expect(api.uploadFile.called).to.equal(true);
});
});
Моему синонийному шпиону никогда не звонили, и я попробовал несколько разных вариантов выше. Каков наилучший способ шпионить за импортированной функцией, как это? Или я концептуально подхожу к этому неправильному пути?
2 ответа
проблема
Вы должны заглушить зависимость API, которая является зависимостью файла. Это невозможно сделать с помощью экземпляра vue, поскольку api не является частью компонента vue.
Вы должны заглушить зависимость от файла.
Решение
Один из способов сделать это - использовать inject-loader
,
меры
Установить Inject-загрузчик
npm install --save-dev inject-loader
Вверху вашего файла импортируйте UploadForm
с inject-loader
а также vue-loader
:
import UploadFormFactory from '!!vue-loader?inject!@/components/UploadForm';
Это фабричная функция, которая возвращает UploadForm
с зависимостями заглушки.
Теперь в вашем тесте нужно позвонить UploadFormFactory
с зависимостью вы хотите заглушить:
const api = {
uploadFile: sinon.spy()
};
const UploadForm = UploadFormFactory({
'@/lib/api': api
})
Итак, ваш тестовый файл будет выглядеть так:
import { mount } from 'avoriaz';
import { expect } from 'chai';
import sinon from 'sinon';
import UploadFormFactory from '!!vue-loader?inject!@/components/UploadForm';
describe('upload', () => {
it('passes form data to api.uploadFile', () => {
const api = {
uploadFile: sinon.spy()
};
const UploadForm = UploadFormFactory({
'@/lib/api': api
})
const testFormData = { test: 'test' };
const api = {
uploadFile: sinon.spy()
};
const wrapper = mount(UploadForm);
wrapper.vm.upload(testFormData);
expect(api.uploadFile.called).to.equal(true);
});
});
Больше информации
Я написал учебник с более подробной информацией здесь - https://www.coding123.org/stub-dependencies-vue-unit-tests/
Я думаю, что ответ Эдда является наиболее всеобъемлющим для большинства сценариев, поэтому я отмечаю его как принятый ответ. Тем не менее, я нашел обходной путь - сделать библиотеку API глобальной службой (Vue.prototype.$api = api
) в моем файле main.js, а затем перезаписывать глобальные заглушки перед каждым тестом.
describe('UploadForm.vue', () => {
let wrapper;
const uploadFile = sinon.stub().returns(Promise.resolve({ data: 0 }));
beforeEach(() => {
wrapper = mount(UploadForm, {
globals: {
$api: { uploadFile }
}
});
});
// ...