Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simulate select with element-ui and vue-test-utils

I'm doing unit tests with Jest and Element-ui in Vue on a component which contains a select with 2 options. I am selecting an option from a dropdown and then checking that an action has been called.

1) With normal select and option HTML tags this works perfectly.

// Fruit.vue

<template lang="pug">
  select(
    v-model="fruit"
  )
    option(
      v-for="item in fruits"
      :label="item.label"
      :value="item.value"
    )
</template>
<script>
export default {
  data () {
    return {
      fruits: [
        {
          label: 'Banana',
          value: false
        },
        {
          label: 'Apple',
          value: false
        }
      ]
    }
  },
  computed: {
    fruit: {
      get () {
        return this.$store.state.fruit
      },
      set (fruit) {
        this.$store.dispatch('setSelectedFruit', { fruit })
      }
    }
  }
</script>

// DOM

<select>
  <option label="Banana" value="false"></option>
  <option label="Apple" value="false"></option>
</select>

// Fruit.spec.js

it('calls the "setSelectedFruit" action when a value is selected', () => {
  const wrapper = mount(Fruit, { store, localVue })
  const options = wrapper.find('select').findAll('option')


  options.at(1).setSelected()
  expect(actions.setSelectedFruit).toHaveBeenCalled()
})

However I use element-ui's el-select and el-option, which have their own interaction with the DOM.

2) With el-select and el-option

// Fruit.vue

Stays the same, except that select is replaced by el-select and option by el-option.

// DOM

<div class="el-select-dropdown">
  <div class="el-select-dropdown__wrap">
    <ul class="el-select-dropdown__list">
      <li class="el-select-dropdown__item">
        <span>Banana</span>
      </li>
      <li class="el-select-dropdown__item">
        <span>Apple</span>
      </li>
    </ul>
  </div>
</div>

// Fruit.spec.js

a)

it('calls the "setSelectedFruit" action', () => {
  const wrapper = mount(Fruit, { store, localVue })
  const options = wrapper.find('.el-select-dropdown__list').findAll('el-select-dropdown__items')

  options.at(1).setSelected()
  expect(actions.setSelectedFruit).toHaveBeenCalled()
})

b) Given that setSelected is actually an alias according to the vue-test-utils documentation, I tried it this way:

it('calls the "setSelectedFruit" action', () => {
  const wrapper = mount(Fruit, { store, localVue })
  const options = wrapper.findAll('.el-select-dropdown__item')
  const select = wrapper.find('.el-select-dropdown__list')

  options.at(1).element.selected = false
  select.trigger('change')
  expect(actions.setSelectedFruit).toHaveBeenCalled()
})

With the second method, the chosen option is set as selected, but the trigger on the select doesn't work and so the v-model isn't updated.

So I'd like to know if someone has a solution for this, or if there is another library (other than vue-test-utils) with which element-ui's el-select can be simulated.

like image 451
nicojonck Avatar asked Dec 12 '18 18:12

nicojonck


2 Answers

It's really difficult to trigger click in <el-dropdown> or <el-select> and make the dropdown item come out . And then I try to mock all this element. It works fine for me.

/mock/div.vue

<template>
  <div>
    <slot></slot>
    <slot name="dropdown"></slot>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({   
  inheritAttrs: true
})
</script>

jest.setup.js

import { config } from '@vue/test-utils'
import Div from './mock/div.vue'
config.global.components = {  
   ElDropdown: Div,
   ElDropdownItem: Div,
   ElDropdownMenu: Div
}
like image 70
J.Chen Avatar answered Oct 19 '22 08:10

J.Chen


I was able to get this working by triggering a click on the drop down item that you would like to simulate:

wrapper.findAll('.el-select-dropdown__item').at(1).trigger('click');
await Vue.nextTick();
expect(YourExpectStatement);

The Vue.nextTick() was needed for me, as it allows the DOM to update it's cycle, more info here. Also note you'll need to make your test function async, like:

it('Async test name', async () => {
like image 20
jimmytricks Avatar answered Oct 19 '22 09:10

jimmytricks