I'm struggling to understand some basic concepts of unit testing in Vue.js using Karma, Mocha and Chai.
This is my component:
VueExample.vue
<template>
<div>
<p>{{ name }}</p>
<input v-model="name">
</div>
</template>
<script>
export default {
name: 'VueExample',
data () {
return {
name: 'Bruce Lee'
};
}
}
</script>
This is how I'm trying to test it:
VueExample.spec.js
import Vue from 'vue';
import VueExample from "../../../components/VueExample";
describe('VueExample.vue', () => {
let vm;
beforeEach(() => {
const Constructor = Vue.extend(VueExample);
vm = new Constructor().$mount();
});
it('should change the name', done => {
const input = vm.$el.querySelector('input');
input.value = 'Chuck Norris';
expect(vm.$el.querySelector('p').textContent).to.equal('Bruce Lee');
Vue.nextTick(() =>{
expect(vm.$el.querySelector('p').textContent).to.equal('Chuck Norris');
console.log(vm.$el.querySelector('p').textContent);
done();
});
});
});
I use Karma to run the tests and Chai as assertion library. Everything is properly configured in karma.conf.js
. When I run this test, it fails. The text inside the tag <p>
doesn't change. The console.log
command outputs Bruce Lee.
The tests are run with Firefox.
v-model
relies on the input event, which does not occur simply by editing the input's value in JavaScript. This is true outside of Vue, as seen below:
function logInput(e) {
console.log('input', e.target.value)
}
function update() {
const input = document.querySelector('#input1')
input.value = "foo"
}
<input oninput="logInput(event)" id="input1">
<button onclick="update()">Update textbox</button>
<div>Clicking button changes text but does not emit <code>input</code> event. See console.</div>
Dispatching the input event manually in your test should work. In your example, do input.dispatchEvent(new Event('input'))
after setting input.value
:
const input = vm.$el.querySelector('input');
input.value = 'Chuck Norris';
input.dispatchEvent(new Event('input')); // input event required to update v-model
Change the value of input don't trigger Vue to update the model (Because input's properties aren't reactive).'
You can try it in your browser. Run in the console document.getElementsByTagName('input')[0].value = 'Chuck Norris'
And nothing happens, the text of the p
element is still "Bruce Lee".
The way to trigger Vue is by input
event. so you should dispatch an input
event. this can be someting like this:
let event = document.createEvent('HTMLEvents')
event.initEvent('input', true, true)
vm.$el.querySelector('input').dispatchEvent(event)
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