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.
Tu peux le faire:
<currency-input>
<currency-input>
avec une valeur qu'il transforme (13.467
est transformé par <currency-input>
à 12.46
)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);
});
});
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.