Ways to verify DOM changes in Vue.js using Mocha testing framework

I am having difficulty grasping some fundamental concepts of unit testing in Vue.js using Karma, Mocha, and Chai.

Here is the component I am working on:

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 my current testing approach:

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 am utilizing Karma for test execution and Chai for assertions. The setup in karma.conf.js is correct. However, when running this test, it fails as the content within the <p> tag does not update. The console.log command displays Bruce Lee.

The tests are being carried out using Firefox.

Answer №1

v-model Relies on the input event, which is not triggered by simply changing the input's value in JavaScript. This behavior holds true even outside of Vue, as demonstrated below:

function logInput(e) {
  console.log('input', e.target.value)
}

function update() {
  const input = document.querySelector('#input1')
  input.value = "bar"
}
<input oninput="logInput(event)" id="input1">
<button onclick="update()">Update textbox</button>
<div>Clicking the button changes text but does not trigger the <code>input</code> event. Check the console for details.</div>

Manually dispatching the input event in your test should solve this issue. In your scenario, use

input.dispatchEvent(new Event('input'))
after setting the input.value:

const input = vm.$el.querySelector('input');
input.value = 'John Doe';
input.dispatchEvent(new Event('input')); // Trigger input event to update v-model

Answer №2

To change the value of an input without triggering Vue to update the model (because input's properties aren't reactive), you can experiment in your browser. For example, running the following command in the console:

document.getElementsByTagName('input')[0].value = 'Chuck Norris'
. Despite changing the input value, nothing will happen as the text of the p element will still remain as "Bruce Lee".

The only way to trigger Vue is through an input event. Therefore, you need to dispatch an input event. This can be achieved using the following method:

let event = document.createEvent('HTMLEvents')
event.initEvent('input', true, true)
vm.$el.querySelector('input').dispatchEvent(event)

Answer №3

After a recommendation from @Anatoly, I decided to give the Vue Test Utils a try. Experimenting with it led me to a solution that I want to share:

yarn add -D @vue/test-utils

Alternatively:

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

This is how the test file appears after incorporating Vue Test Utils:

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();
    });
  });
});

While there is only one test showcased here, I've utilized the beforeEach function for potential expansion in the future. The Vue component VueExample is mounted for testing purposes. Within the test, we locate the <input> element, set its value to Chuck Norris, and trigger the input event. Initially, the text within the <p> tag remains unchanged at Bruce Lee due to Vue's asynchronous DOM updates.

By employing nextTick(), we confirm that the anticipated change has been implemented, resulting in the <p> text matching the newly assigned value of Chuck Norris.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having an issue with HTML and JavaScript where the button won't open when pressed. Any help is appreciated

https://jsbin.com/haluhifuqe/edit?html,js,output I'm facing an issue with my HTML & JavaScript code - when I click the button, it doesn't open. Can anyone help me out? <!DOCTYPE html> <html> <head> <meta charset="utf-8 ...

Upon mounting, Vue.js 3 composable data is not available

Currently, I am utilizing Vue.js 3 along with a basic test composable: TEST COMPOSABLES Load post id: {{ i }} <div v-if="error"> <p>Uh oh! An error has occurred: {{ error.message }}</p> <button @click="r ...

The function '$.fn.<new_function>' is not a valid function in jQuery

UPDATE: code link with enhanced formatting: UPDATE: code upgraded with enhancements from JSHint http://pastebin.com/hkDQfZy1 I am attempting to utilize $.fn to establish a new function on jQuery objects by this method: $.fn.animateAuto = function(x,y) { ...

ASP.Net & Ajax Fusion Login Interface

I am encountering an issue while creating a login page with HTML, AJAX, and ASP.NET. The data is being passed to the AJAX function successfully, but when I debug the ASP page, the username and password are showing up as NULL. The purpose of the code is to ...

I am having trouble displaying SASS styles in the browser after running webpack with node

In my current project for an online course, I am utilizing sass to style everything. The compilation process completes successfully without any errors, but unfortunately, the browser does not display any of the styles. The styles folder contains five file ...

Retrieve the data attribute from a select box that was created dynamically

Following an AJAX request, I have successfully generated two select boxes: $("#job_id").change(function() { var id = $(this).val(); $.ajax({ url: '', type: 'POST', dataType: 'json', dat ...

Use jQuery's change method to initiate a hidden file input

Want to create a fake file input using an anchor tag and trigger the hidden file input with jQuery? Looking for some advice on how to make this happen. Check out my current attempt here. I'm not sure if I'm on the right track with this, so any g ...

What is the best way to give stacked bar charts a rounded top and bottom edge?

Looking for recommendations on integrating c3.js chart library into an Angular 6 project. Any advice or suggestions would be greatly appreciated! https://i.sstatic.net/iiT9e.png ...

Maximizing the efficiency of a personalized hook that facilitates data sharing in React

I have developed a unique Custom Hook that looks like the following: import { useEffect, useState } from 'react'; import axios from 'axios'; const myCustomHook = () => { const [countries, setCountries] = useState([]); const [i ...

JavaScript Form for computing Daily Rate from JSON

I am looking to retrieve pricing information from a JSON file based on the Room, Season, and number of nights specified. Currently, the HTML code triggers an alert each time one of the three form inputs is selected. <!DOCTYPE html> <html> < ...

Changing the main directory name in a Three.JS project triggers an unexpected aliasing glitch

Creating a new stackoverflow account just to ask a question is not my usual style, but I am completely baffled by this issue. For months, I have been struggling with a strange bug that causes a glitch in my three.js VR projects on Android. My usual method ...

Guide to using AES-256-CBC encryption in Node.js and decrypting with OpenSSL on a Linux system

Question: Hello there, I am currently facing an issue with decrypting my encoded base64 using a specific command. Here is the command that I am trying to use: echo "base64key" | (openssl enc -AES-256-cbc -d -a -pass "pass:test" -pbkdf2 ...

Vue instance with non-reactive data

I am looking to store an object in Vue that will be accessible throughout the entire instance but does not need to be reactive. Typically, if I wanted it to be reactive, I would use 'data' like this: new Vue({ data: myObject }) However, since ...

The content in Vue Ckeditor does not display as WYSIWYG

While attempting to integrate CKEditor with Vue.js by following the guide in this article, I encountered an issue where the editor was not displaying content correctly (not WYSIWYG) and text was not formatting as expected. The same problem arose when try ...

Error with an Array of Objects in an Array when using Angular and Typescript

Our system has an array called "food/essen" with a total of 10 items. The food plan is made up of 8 objects from the "Food" array and includes an ID for the week number. An issue we are facing in our web application is that although it recognizes the 8 o ...

The unhandled type error rises with each scroll I make

Having been diligently working on my current website project, I encountered a puzzling issue. Upon writing code to implement smooth scrolling throughout the site, I found myself facing a persistent error that continues to escalate with each scroll up or do ...

"Within the node.js framework, the search/query section of the URL appears

I am currently working on a website (client + server) that both operate from the same machine. Despite not encountering any issues in Chrome's developer tools, I am struggling to identify the source of a problem. My dilemma is with trying to POST a s ...

Having trouble displaying the image in my administrative tool

I am currently developing an admin application that will showcase uploaded product images stored in a database. The images are saved as object IDs in MongoDB. However, the image container in the admin app shows the count of images stored in the database bu ...

Retrieve the date one week prior to today's date in Node.js and format it in Mysql style

I need to find the exact date from one week ago in SQL format using Node.js. I attempted a similar solution as described here - How to get yesterday date in node.js backend? but unfortunately it's not working for my specific case. ...

An issue arises when trying to group and sum an array of objects due to difficulty converting strings to arrays in TypeScript

Below is the provided code snippet: Definition of Interface - interface IWEXInterface { readonly Date?: string; "Exec Qty"?: string; readonly Expiry?: string; } Data Collection - let data: IWEXInterface[] = [ { Date: &qu ...