Монтирование экземпляра 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 }
      }
    });
  });
  // ...
Другие вопросы по тегам