I've written a standalone reusable component in VueJS that is essentially just a wrapper for an input field, but that does smart real-time processing of the keyboard input based on props passed to it.
It's working like a charm, and I'm able to successfully test most of its functionality via the Vue Test Utils (Mocha flavor) but I'm also trying to test that it correctly responds to special keys (arrows, backspace, tab, etc.) and getting stumped.
Here's an edited down version of the component itself:
<template>
<input type="text" v-model="internalValue" :placeholder="placeholder"
@keydown="keyDownHandler"/>
</template>
<script>
export default {
name: "LimitedTextArea",
props: {
fieldname: '',
value: { type: String, default: ""},
placeholder: 'placeholder',
...
},
data: function() {
return {
internalValue: ''
}
},
watch: {
internalValue(newVal /*, oldVal*/ ) {
this.$emit("input", this.fieldname, newVal);
}
},
mounted: function() {
...
},
methods: {
keyDownHandler(evt) {
this.internalValue = this.value;
if (!evt.metaKey && evt.keyCode >= 45) {
evt.preventDefault();
const inputChar = evt.key;
let newChar = '';
/* filtering logic here */
this.internalValue += newChar;
} else {
// just for tracing this path during dev
console.log('will execute default action');
}
}
}
}
</script>
… and here's the test:
it('embedded: delete key functions normally', () => {
const initialValue = '';
const inputValue = 'omega';
const outputValue = 'omeg';
const deleteKeyEvent = {key: 'Backspace', keyCode: 8};
const parent = mount({
data: function() { return {
textValue: initialValue
}},
template: \`<div>
<limited-text-area :fieldname="'textValue'" :value="textValue"
@input="input"></limited-text-area>
</div>`,
components: { 'limited-text-area': LimitedTextArea },
methods: {
input(fieldname, value) {
this[fieldname] = value;
}
}
});
const input = parent.find('input');
typeStringIntoField(inputValue, input);
// I've tried with and without this before sending the key event…
input.element.focus();
input.element.setSelectionRange(inputValue.length, inputValue.length);
// I've tried doing it this way
input.trigger('keydown', deleteKeyEvent);
// And I've tried doing it this way, based on the Vue Test Utils guide
// for keyboard events
input.trigger('keydown.up.backspace');
expect(parent.vm.textValue).to.equal(outputValue);
});
Neither of the two approaches quoted above work. At this point I suspect that it may not be a simple question of calling the wrong method, and that I'm either:
Any help would be greatly appreciated! Thanks.
Simulating BACKSPACE
on <input>
natively (outside Vue in a browser) doesn't actually delete text, so I don't see it working with Vue. The solutions I found simply check the keydown event for backspace, and programmatically delete a character from the input's text [1] [2]. So, I'd say this isn't something that could be effectively unit-tested.
Note that vue-test-utils
uses JSDom (not PhantomJS).