web-dev-qa-db-fra.com

Comment puis-je tester une entrée personnalisée Vue component

Dans la documentation Vue.js, il existe un exemple de composant d'entrée personnalisé. J'essaie de comprendre comment je peux écrire un test unitaire pour un composant comme ça. L'utilisation du composant ressemblerait à ceci

<currency-input v-model="price"></currency-input>

L'implémentation complète peut être trouvée à https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events

La documentation dit

Donc, pour qu'un composant fonctionne avec v-model, il devrait (ceux-ci peuvent être configurés dans 2.2.0+):

  • accepter un accessoire de valeur
  • émettre un événement d'entrée avec la nouvelle valeur

Comment écrire un test unitaire qui garantit que j'ai écrit ce composant de manière à ce qu'il fonctionne avec v-model? Idéalement, je ne veux pas tester spécifiquement ces deux conditions, je veux tester le comportement selon lequel lorsque la valeur change dans le composant, elle change également dans le modèle.

11
Jason Desrosiers

Tu peux le faire:

  • Utiliser Vue Test Utils , et
  • Montage d'un élément parent que utilise <currency-input>
  • Faux un événement d'entrée dans le champ de texte interne de <currency-input> avec une valeur qu'il transforme (13.467 est transformé par <currency-input> à 12.46)
  • Vérifiez si, dans le parent, la propriété price (liée à v-model) a changé.

Exemple de code (en utilisant 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);
  });
});

Démo exécutable dans le navigateur utilisant 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/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/browser.js"></script>
<script src="https://rawgit.com/vuejs/vue-test-utils/2b078c68293a41d68a0a98393f497d0b0031f41a/dist/vue-test-utils.iife.js"></script>

Remarque: Le code ci-dessus fonctionne correctement (comme vous pouvez le voir), mais il peut y avoir des améliorations aux tests impliquant v-model bientôt. Suivez ce problème pour des informations à jour.

20
acdcjunior