测试包装的 vuetify 自动完成组件 v 菜单在 html 中无法打开

Testing a wrapped vuetify autocomplete component v menu does not open in html

在这种情况下,我想通过 vue-test-utils. I use vuetify autocomplete 组件测试我的自定义组件。我只是用 div 包装并提取为自定义组件。到目前为止没有什么特别的。

这个组件真的很适合开发。我没问题.

我使用了这个组件,如下所示。

<my-component
  id="brand-dropdown"
  ref="brand-dropdown"
  :items="brands"
  labelKey="product.brand"
  item-text="name"
  item-value="name"
  v-model="product.brandName"/>

我的自定义组件如下所示:

<template>
  <div class="comboContainer">
    <v-autocomplete
      class="product-combobox"
      ref="complete"
      :items="localItems"
      append-icon="$dropdownArrow"
      outlined
      dense
      hide-details
      color="#999999"
      :item-text="itemText"
      :item-value="itemValue"
      :filter="autoCompleteFilter"
      v-model="selected"
      @change="onListItemSelected">
      <template slot="label">
        <span>{{$t(labelKey)}}</span>
      </template>
      <template slot="prepend-inner" v-if="showSearchIcon">
        <div class="d-flex align-center justify-center"
             style="height: 25px;">
          <img src="~/assets/icons/search/search.png"/>
        </div>
      </template>
      <template v-slot:no-data>
        <v-list-item id="noMatchText">
          <v-list-item-title>
            <div :no-data-item="dataTestId">
              {{ $t('selection.noMatchFound') }}
            </div>
          </v-list-item-title>
        </v-list-item>
      </template>
      <template v-slot:item="{ item }">
        <v-tooltip top color="transparent">
          <template v-slot:activator="{ on, attrs }">
            <div
              v-on="item[itemText].length >36?on:null"
              class="combobox-item comboboxOverFlow"
              :data-testid="itemDataTestIdPrefix+item.id"
              :parent-list="dataTestId">
              <span>{{ item[itemText] }}</span>
            </div>
          </template>
          <div class="popup-rectangle">
            <span>{{ item[itemText] }}</span>
          </div>
        </v-tooltip>
      </template>
    </v-autocomplete>
  </div>
</template>

<script>
export default {
  props: {
    items: {
      type: Array,
      default: [],
    },
    labelKey: {
      type: String,
      default: '',
    },
    itemText: {
      type: String,
      default: '',
    },
    itemValue: {
      type: String,
      default: '',
    },
    value: {
      type: [Number, String, Array],
    },
    disabled: {
      type: Boolean,
      default: false,
    }
    shouldTriggerWatch: {
      type: Boolean,
      default: false,
    }
  },
  data() {
    return {
      selected: this.value,
      showSearchIcon: false,
    };
  },
  watch: {
    value: {
      immediate: true,
      handler(val) {
        if (this.shouldTriggerWatch) {
          this.selected = val;
          this.$emit('input', this.selected);
        }
      },
    },
  },
  computed: {
    localItems() {
      if (this.items && this.items.length) {
        return this.items.map(x => ({
          ...x,
          displayName: x.lang_key ? this.$t(x.lang_key) : x.name,
        }));
      }
      return [];
    },
  },
  methods: {
    onListItemSelected() {
      this.$emit('input', this.selected);
    },
    autoCompleteFilter(item, queryText, itemText) {
      const re = new RegExp(`(\s+|^)(${queryText.toLocaleLowerCase()})(.*|$)`);
      return re.test(itemText.toLocaleLowerCase());
    },
  },
};

我要测试三个测试用例

  1. 当我传递空列表时,应该呈现为空下拉列表并呈现无数据槽。
      <template v-slot:no-data>
        <v-list-item id="noMatchText">
          <v-list-item-title>
            <div :no-data-item="dataTestId">
              {{ $t('selection.noMatchFound') }}
            </div>
          </v-list-item-title>
        </v-list-item>
      </template>
  1. 当我通过包含测试数据的填充列表时,我想测试正确呈现的所有项目
     <template v-slot:item="{ item }">
        <v-tooltip top color="transparent">
          <template v-slot:activator="{ on, attrs }">
            <div
              v-on="item[itemText].length >36?on:null"
              class="combobox-item comboboxOverFlow"
              :data-testid="itemDataTestIdPrefix+item.id"
              :parent-list="dataTestId">
              <span>{{ item[itemText] }}</span>
            </div>
          </template>
          <div class="popup-rectangle">
            <span>{{ item[itemText] }}</span>
          </div>
        </v-tooltip>
      </template>
  1. 当我搜索时,我想提供我的过滤器功能按预期工作。自动完成根据过滤值呈现项目。

这是我的测试文件。

function mountComponent(options) {
  return mount(ComboBox, {
    vuetify: new Vuetify(),
    sync: false,
    mocks: {
      $t: key => key,
      $i18n: { locale: 'en' },
    },
    ...options,
  });
}

describe('Combobox unit tests', () => {
  beforeEach(() => {
    document.body.setAttribute('data-app', 'true');
  });

  test('should create component successfully', () => {
    const wrapper = mountComponent({ items: [] });
    expect(wrapper.exists()).toBeTruthy();
  });
  test('should list zero items if the item list is empty', async () => {
    const wrapper = mountComponent({
      propsData: {
        items: [],
        labelKey: 'labelKey',
        dataTestId: 'test-dropdown',
        itemText: 'name',
        itemValue: 'id',
      },
    });

    const autocomplete = wrapper.find('.product-combobox');
    const autocompleteControls = autocomplete.find('.v-input__slot');
    autocompleteControls.trigger('click');

    await wrapper.vm.$nextTick();
    await flushPromises();

    **// v menu cant opened !!!!**
  });
  test('should list third items correctly', async () => {
    const testItems = [{ name: 'item1', id: 1 }, { name: 'item2', id: 2 }, { name: 'item3', id: 3 }];
    const wrapper = mountComponent({
      attachToDocument: true,
      propsData: {
        eagerProp: true,
        items: testItems,
        dataTestId: 'test-dropdown',
        itemDataTestIdPrefix: 'test-dropdown-item-',
        itemText: 'name',
        itemValue: 'id',
        value: null,
      },
    });

    const slot = wrapper.find('.v-input__slot');
    const input = wrapper.find('input');

    // Focus input should only focus
    input.trigger('focus');

    expect(wrapper.vm.$children[0].isFocused).toBe(true);
    expect(wrapper.vm.$children[0].menuCanShow).toBe(true);
    expect(wrapper.vm.$children[0].isMenuActive).toBe(false);

    slot.trigger('click');

    expect(wrapper.vm.$children[0].isMenuActive).toBe(true);
    expect(wrapper.vm.$children[0].menuCanShow).toBe(true);

    wrapper.setProps({ searchInput: 'foo' });

    expect(wrapper.vm.$children[0].isMenuActive).toBe(true);
    expect(wrapper.vm.$children[0].menuCanShow).toBe(true);

    // v menu cant opened !!!!
    // you think these expects is unnecesary. you are right I just explore this component 
    // if I success I'll delete all of them
  });
  test('should filter autocomplete search results', async () => {
    
  });
});

我无法在测试环境中打开 v-menu。

我试过发出事件和触发器('click')

当我控制日志 wrapper.html() 时,我看不到 v 菜单已打开并且所有项目都呈现在 html 中。输出如下所示。

<div class="comboContainer">
   <div class="v-input product-combobox v-input--hide-details v-input--dense theme--light v-text-field v-text-field--enclosed v-text-field--outlined v-select v-autocomplete">
      <div class="v-input__control">
         <div role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-owns="list-2" class="v-input__slot" style="height: 44px;">
            <fieldset aria-hidden="true">
               <legend style="width: 0px;"><span>​</span></legend>
            </fieldset>
            <div class="v-select__slot">
               <label for="input-2" class="v-label theme--light" style="left: 0px; position: absolute;"><span></span></label><input data-testid="test-dropdown" id="input-2" type="text" autocomplete="off">
               <div class="v-input__append-inner">
                  <div class="v-input__icon v-input__icon--append"><i aria-hidden="true" class="v-icon notranslate material-icons theme--light">$dropdownArrow</i></div>
               </div>
               <input type="hidden">
            </div>
            <div class="v-menu"></div>
         </div>
      </div>
   </div>
</div>

我的问题是物品在哪里? <div class="v-menu"></div> 为什么我在 wrapper.html 中看不到。我不使用 shallowMount,我使用 mount。因此,我无法编写涵盖的测试用例。

如何模拟打开的菜单并呈现所有项目并提供一些断言?

我错过了什么?

版本

"@nuxtjs/vuetify": "1.12.1",
"@vue/test-utils": "1.0.0-beta.29",
"vue-jest": "3.0.7"

好吧,可能更好的方法是模拟 v-autocomplete 并将其替换为测试组件(只需控制传递给它的值并从中发出假事件)。您不是在开发 Vuetify,因此无需测试组件内部发生的情况。