During my unit tests using Jest and Element-ui in Vue, I encountered an issue with a component containing a select element with 2 options. After selecting an option from the dropdown, I needed to verify that a specific action was called.
1) Everything worked perfectly with standard select
and option
HTML tags.
// 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('verifies the call to the "setSelectedFruit" action after selection', () => {
const wrapper = mount(Fruit, { store, localVue })
const options = wrapper.find('select').findAll('option')
options.at(1).setSelected()
expect(actions.setSelectedFruit).toHaveBeenCalled()
})
The challenge arose when using element-ui's el-select
and el-option
, which have different interaction patterns with the DOM.
2) Using el-select
and el-option
// Fruit.vue
The code remains unchanged, except for replacing select
with el-select
and option
with 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('verifies the call to 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) Since setSelected
is just an alias as per the vue-test-utils documentation, I attempted a workaround:
it('verifies the call to 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()
})
While the second method successfully sets the chosen option
as selected
, the trigger on the select
does not update the v-model
.
Hence, if anyone has a solution to this problem or knows of another library (besides vue-test-utils) capable of simulating the functionality of element-ui's el-select
, your insights would be highly appreciated.