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.
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
}
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 () => {
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With