How can I test a custom input Vue component How can I test a custom input Vue component vue.js vue.js

How can I test a custom input Vue component


You can do it:

  • Using Vue Test Utils, and
  • Mounting a parent element that uses <currency-input>
  • Fake an input event to the inner text field of <currency-input> with a value that it transforms (13.467 is transformed by <currency-input> to 13.46)
  • Verify if, in the parent, the price property (bound to v-model) has changed.

Example code (using Mocha):

import { mount } from '@vue/test-utils'import CurrencyInput from '@/components/CurrencyInput.vue'describe('CurrencyInput.vue', () => {  it("changing the element's value, updates the v-model", () => {    var parent = mount({      data: { price: null },      template: '<div> <currency-input v-model="price"></currency-input> </div>',      components: { 'currency-input': CurrencyInput }    })    var currencyInputInnerTextField = parent.find('input');    currencyInputInnerTextField.element.value = 13.467;    currencyInputInnerTextField.trigger('input');    expect(parent.vm.price).toBe(13.46);  });});

In-browser runnable demo using Jasmine:

var CurrencyInput = Vue.component('currency-input', {  template: '\    <span>\      $\      <input\        ref="input"\        v-bind:value="value"\        v-on:input="updateValue($event.target.value)">\    </span>\  ',  props: ['value'],  methods: {    // Instead of updating the value directly, this    // method is used to format and place constraints    // on the input's value    updateValue: function(value) {      var formattedValue = value        // Remove whitespace on either side        .trim()        // Shorten to 2 decimal places        .slice(0, value.indexOf('.') === -1 ? value.length : value.indexOf('.') + 3)      // If the value was not already normalized,      // manually override it to conform      if (formattedValue !== value) {        this.$refs.input.value = formattedValue      }      // Emit the number value through the input event      this.$emit('input', Number(formattedValue))    }  }});// specs code ///////////////////////////////////////////////////////////var mount = vueTestUtils.mount;describe('CurrencyInput', () => {  it("changing the element's value, updates the v-model", () => {    var parent = mount({      data() { return { price: null } },      template: '<div> <currency-input v-model="price"></currency-input> </div>',      components: { 'currency-input': CurrencyInput }    });        var currencyInputInnerTextField = parent.find('input');    currencyInputInnerTextField.element.value = 13.467;    currencyInputInnerTextField.trigger('input');    expect(parent.vm.price).toBe(13.46);  });});// load jasmine htmlReporter(function() {  var env = jasmine.getEnv()  env.addReporter(new jasmine.HtmlReporter())  env.execute()}())
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css"><script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script><script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script><script src="https://npmcdn.com/vue@2.5.15/dist/vue.js"></script><script src="https://cdn.jsdelivr.net/npm/vue-template-compiler@2.5.15/browser.js"></script><script src="https://rawgit.com/vuejs/vue-test-utils/2b078c68293a41d68a0a98393f497d0b0031f41a/dist/vue-test-utils.iife.js"></script>