如何使用vue测试工具触发v-自动完成“输入”事件?

时间:2019-03-06 15:02:06

标签: jestjs vuetify.js vue-test-utils

我正在尝试在单元测试中触发Vuetify v-autocomplete组件的“ input”事件。据我所知,单元测试与Vuetify guys are using十分相似,但是由于某种原因,从未调用过模拟方法。

factory方法仅返回通过mount创建的组件实例,并添加本地存储,vue和vueLoading实例。

在这里我会很想见识,已经为此失去了几个小时,我开始有点生气...

Vuetify版本:1.4.3

组件

<template>
  <v-autocomplete
    :items="options"
    :value="selectedId"
    :label="label || $t('user.filter')"
    :dark="dark"
    :class="fieldClass"
    :menu-props="{ contentClass }"
    :loading="$loading.isLoading('fetch users')"
    item-text="email"
    item-value="id"
    name="search_by_user"
    hide-details
    single-line
    clearable
    @input="updateValue($event)"
    @click.native="fetchUsers"
  />
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  props: {
    value: {
      type: String,
      required: false,
      default: null
    },
    label: {
      type: String,
      required: false,
      default: null
    },
    dark: {
      type: Boolean,
      required: false,
      default: true
    },
    fieldClass: {
      type: String,
      required: false,
      default: 'select-user-search'
    },
    contentClass: {
      type: String,
      required: false,
      default: 'user-search'
    },
    blankItem: {
      type: Object,
      required: false,
      default: null
    }
  },
  data () {
    return {
      selectedId: this.value
    }
  },
  computed: {
    ...mapGetters(['users']),
    options () { return this.blankItem ? [this.blankItem].concat(this.users) : this.users }
  },
  created () {
    if (this.value) this.fetchUsers()
  },
  methods: {
    fetchUsers () {
      if (this.users.length) return

      this.$store.dispatch('FETCH_USERS', {
        fields: ['id', 'email'],
        filter: { active: 'true' }
      })
    },
    updateValue (value) {
      this.selectedId = value
      this.$emit('input', value)
    }
  }
}
</script>

<style>
  .select-user-search {
    overflow: hidden;
    padding-bottom: 1px;
  }

  .select-user-search .v-select__selections {
    overflow: hidden;
  }

  .select-user-search .v-select__selection {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
</style>

单元测试

import { mount, shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import VueLoading from 'vuex-loading'
import Vuetify from 'vuetify'
import UserSearch from 'manager/components/user/search.vue'

const factory = (values, shallow = true) => {
  if (!shallow) {
    return mount(UserSearch, { ...values })
  }
  return shallowMount(UserSearch, { ...values })
}

const localVue = createLocalVue()

localVue.use(Vuex)
localVue.use(VueLoading)
localVue.use(Vuetify)

describe('UserSearch', () => {
  let actions, getters, store, vueLoading

  beforeEach(() => {
    actions = {
      FETCH_USERS: jest.fn()
    }

    getters = {
      users: () => []
    }

    vueLoading = new VueLoading({ useVuex: true })

    store = new Vuex.Store({
      actions,
      getters
    })
  })

  it('calls "updateValue" method when input triggered', async () => {
    const methods = {
      updateValue: jest.fn()
    }

    const wrapper = factory({ methods, store, localVue, vueLoading }, false)
    const input = wrapper.find('input')

    input.element.value = 'value'
    input.trigger('input')

    await wrapper.vm.$nextTick()

    expect(methods['updateValue']).toBeCalledWith('value')
  })
})

1 个答案:

答案 0 :(得分:0)

我使用以下变体

组件

<template>
    <span> <!-- span (or the other HTML element) around <v-autocomplete> is important -->
        <v-autocomplete
            :items="options"
            :value="selectedId"
            :label="$t('user.filter')"
            :menu-props="{ contentClass }"
            :loading="false"
            item-text="email"
            item-value="id"
            name="search_by_user"
            hide-details
            single-line
            clearable
            @input="updateValue($event)"
            @click.native="fetchUsers"
        />
    </span>
</template>


<script lang="ts">
    import { Component } from 'vue-property-decorator';
    import Vue from 'vue';

    @Component
    export default class AppAutocomplete extends Vue {
        private options: any[] = [{email: 'box1@gmail.com', id: 1}];
        private selectedId: string|undefined = undefined;
        private contentClass = 'user-search';

        private fetchUsers() {
        }

        public updateValue(event: any) {
        }
    }
</script>

单元测试

import { Wrapper, createLocalVue, mount } from '@vue/test-utils';
import Vue from 'vue';
import Vuetify from 'vuetify';

// @ts-ignore
import AppAutocomplete from '@/components/AppAutocomplete.vue';


describe('AppAutocomplete', () => {
    Vue.use(Vuetify);

    let wrapper: Wrapper<Vue>;
    let vm: any;

    beforeEach(() => {

        wrapper = mount(AppAutocomplete, {
            localVue: createLocalVue(),
            vuetify: new Vuetify({
                mocks: { $vuetify: { lang: { t: (val: string) => val } } },
            }),
            mocks: { $t: () => { /** */ } },
        });

        vm = wrapper.vm;
    });


    afterEach(() => wrapper.destroy());


    it(`calls "updateValue" method when input triggered`, ()  => {

        jest.spyOn(vm, 'updateValue');

        const autocompleteElem = wrapper.find('.v-autocomplete');

        autocompleteElem.vm.$emit('input', 'box1');

        expect(vm.updateValue).toBeCalledTimes(1);
        expect(vm.updateValue).toHaveBeenCalledWith('box1');

    });

});

用其他HTML元素包围v-autocomplete很重要。没有它,测试将失败。

Vuetify版本:2.1.12