'How can I test the correct rendering of items in a Vuetify v-select dropdown using jest?

I have been trying to check if the correct values get displayed in a v-select and v-menu dropdown box, but they don't appear in my isolated testing component after I trigger a click event.

        <template #append>
          <v-menu>
            <template #activator="{ on }">
              <div v-on="on">
                <span
                  data-testid="type-filter-selector-value"
                >{{ type }}</span>
                <v-icon class="d-inline-block">
                  mdi-menu-down
                </v-icon>
              </div>
            </template>
            <v-list>
              <v-list-item
                v-for="t in searchTypes"
                :key="t"
                @click="type = t"
              >
                <v-list-item-title class="text-capitalize">
                  {{ t }}
                </v-list-item-title>
              </v-list-item>
            </v-list>
          </v-menu>
        </template>

Test:

  test('rendered select filter contains items labels', () => {
    component = localMount(SelectFilterComponent, {
      propsData: {
        filter: {
          label: 'icecream',
          items: [
            { text: 'Pistaccio' },
          ],
        },
      },
    });
    componentHtml = component.html();
    console.log('before click', component.html());
    component.find('.v-select').trigger('click');
    console.log('after click', component.html());
    expect(componentHtml).toContain('Pistaccio');
  });

When you look at the html structure of the component in the actual page, you see that the rendered items are actually appended not to the v-select element, but to the outer div with data-app="true". Also Jest through some vuetify error if this element did not exist. After some hacking I was succesful in wrapping my component in such a div with the following jest-helper method:

const localVue = createLocalVue();
const vuetify = new Vuetify();

const inject = {
  localVue,
  vuetify,
};

export const localMount = (component, options = {}) => {
  const child = mount(component, {
    ...inject,
    ...options,
  });
  const app = mount({
    template: '<div data-app="true" id="app"></div>',
  });
  app.element.appendChild(child.element);
  return app;
};

And finally here is the selectFilter component, (stripped of unrelevant styles etc):

<template>
  <v-select
    class="v-select"
    :items="filter.items"
    :label="filter.label"
    :value="filter.value"
    :chips="filter.multiple"
    :multiple="filter.multiple"
  />
</template>

<script>
export default {
  props: {
    filter: {
      type: Object,
      required: true,
    },
  },
};
</script>

Now the output of the console logs in the test is here:

  console.log tests/unit/components/SelectFilter.spec.js:40
    before click <div data-app="true" id="app" class="v-application">
      <div class="v-input v-select v-input--dense theme--light v-text-field v-select">
        <div class="v-input__control">
          <div role="button" aria-haspopup="listbox" aria-expanded="false" aria-owns="list-14" class="v-input__slot" style="height: 38px;">
            <div class="v-select__slot"><label for="input-14" class="v-label theme--light" style="left: 0px; position: absolute;">icecream</label>
              <div class="v-select__selections"><input id="input-14" readonly="readonly" type="text" aria-readonly="false" autocomplete="off"></div>
              <div class="v-input__append-inner">
                <div class="v-input__icon v-input__icon--append"><i aria-hidden="true" class="v-icon notranslate mdi mdi-menu-down theme--light"></i></div>
              </div><input type="hidden">
            </div>
            <div class="v-menu">
              <!---->
            </div>
          </div>
          <div class="v-text-field__details">
            <div class="v-messages theme--light">
              <transition-group-stub tag="div" name="message-transition" class="v-messages__wrapper"></transition-group-stub>
            </div>
          </div>
        </div>
      </div>
    </div>

  console.log tests/unit/components/SelectFilter.spec.js:42
    after click <div data-app="true" id="app" class="v-application">
      <div class="v-input v-select v-input--dense theme--light v-text-field v-select">
        <div class="v-input__control">
          <div role="button" aria-haspopup="listbox" aria-expanded="false" aria-owns="list-14" class="v-input__slot" style="height: 38px;">
            <div class="v-select__slot"><label for="input-14" class="v-label theme--light" style="left: 0px; position: absolute;">icecream</label>
              <div class="v-select__selections"><input id="input-14" readonly="readonly" type="text" aria-readonly="false" autocomplete="off"></div>
              <div class="v-input__append-inner">
                <div class="v-input__icon v-input__icon--append"><i aria-hidden="true" class="v-icon notranslate mdi mdi-menu-down theme--light"></i></div>
              </div><input type="hidden">
            </div>
            <div class="v-menu">
              <!---->
            </div>
          </div>
          <div class="v-text-field__details">
            <div class="v-messages theme--light">
              <transition-group-stub tag="div" name="message-transition" class="v-messages__wrapper"></transition-group-stub>
            </div>
          </div>
        </div>
      </div>
    </div>

In other words, no change after the click. What am I missing? How do I make the component in jest expose the v-select items, so I can probe if they are rendered correctly?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source