Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 583
cezar Avatar asked Jan 24 '20 12:01

cezar


2 Answers

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
like image 72
tony19 Avatar answered Oct 01 '22 14:10

tony19


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)
like image 36
Shalom Peles Avatar answered Oct 01 '22 14:10

Shalom Peles