javascriptvue.jsmocha.jskarma-mocha

How to test DOM update in Vue.js with Mocha?


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.


Solution

  • 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