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

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


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)


In one of the comments @Anatoly suggested to use the Vue Test Utils. I was playing around and came up with a solution I'd like to share:

yarn add -D @vue/test-utils

or:

npm install --save-dev @vue/test-utils

Then the test file looks like this:

import Vue from 'vue';import { shallowMount } from '@vue/test-utils';import VueExample from "../../../components/VueExample";describe('VueExample.vue', () => {  let wrapper;  beforeEach(() => {    wrapper = shallowMount(VueExample);  });  it('should change the name', done => {    const textInput = wrapper.find('input');    textInput.setValue('Chuck Norris');    textInput.trigger('input');    expect(wrapper.find('p').text()).to.equal('Bruce Lee');    Vue.nextTick(() => {      expect(wrapper.find('p').text()).to.equal('Chuck Norris');      done();    });  });});

There is only one test in this example, but I still use beforeEach to make it easier expandable with further tests. Here we mount the Vue component VueExample. In the test we find the <input> tag, set its value to Chuck Norris and trigger the input event. We can see that the text node of the <p> tag is unchanged and still says Bruce Lee. This is due to asynchronous nature of the DOM updates in Vue.

Using nextTick() we can check that the chane has taken effect and the text node of the <p> tag equals to the previous set value, which is Chuck Norris.