vue-test-utils v2: testing v-model value updates on keydown event

38 views Asked by At

I'm brand new to Vue Test Utils and struggling a bit with the documentation on testing v-model updates. I'm using vite and so I've decided to use vitest

I have an AutoComplete component with two slots input and results. The input slot is monitored for @keydown events. If the user has pressed a "special" key then this is captured and triggers a different action, but if they press a "normal" key then the input (and therefore the modelValue) should update accordingly.

A simplified version of my AutoComplete component:

<script setup>

import { ref, watchEffect, computed} from 'vue';

    // Props
    const props = defineProps({
        modelValue : {
            type: [String, null],
            required: true
        },
        autoCompleteConfigs : {
            type: Array,
            required: true,
        }
    });

    const emit = defineEmits(['selected','chosen','updated','update:modelValue']);

    ///

    const methods = {
        //when the user makes a selection
        onChosen :  (result) =>{
            ///
        },

        moveSelection: (x) =>{
            ///
        },

        // Event handler for keydown
        onKeydown : (event) => {

            //check if form select is active before passing through events
            if (query.value === null){
                return;
            }

            //check for special keys
            const passThruKeys = ['ArrowUp','ArrowDown','Tab','Enter','Delete'];

            if (passThruKeys.includes(event.key)) {
                event.preventDefault();

                //if user chooses current selection
                if (event.key === 'Enter' || event.key === 'Tab'){
                    methods.onChosen(searchResults.value[currentSelection.value])
                }

                //move selection up or down
                if (event.key === 'ArrowUp'){
                    methods.moveSelection(-1);
                }
                else if (event.key === 'ArrowDown'){
                    methods.moveSelection(1);
                }
            }
        }

    };

</script>

<template>


    <!-- input field for this slot-->
    <div>
        <slot name="input" @keydown="methods.onKeydown" ></slot>
    </div>

    <!-- Define how results will be displayed-->
    <div>
        <slot v-if="searchResults.length > 0" name="results" :results="searchResults" :indexSearched="currentSearchIndex" @chosen="methods.onChosen"></slot>
        
    </div>

</template>

My attempt at a first test:

import { mount} from "@vue/test-utils";
import AutoComplete from '@/Components/AutoComplete.vue'
import { describe, it, expect, vi} from "vitest";

//const useRemoteSearch = vi.fn(() => [])

describe("AutoComplete", () => {

    let wrapper;

    beforeEach(() => {
        wrapper = mount(AutoComplete, {
            props: {
                modelValue: 'Some text ',
                'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
                autoCompleteConfigs : [
                    {
                        trigger : '#',
                        index : 'tag',
                        autoComplete : 'tag'
                    },
                    {
                        trigger : '@',
                        index : 'user',
                        autoComplete : 'username'
                    }
                ],
            },
            slots: {
                input: `<input :value="modelValue" 
                         @keydown="onKeydown" 
                         id="message" 
                         @input="$emit(
                               'update:modelValue', 
                                $event.target.value
                         )"/>`,
            },
        });
    });

    it("should update model value", async() => {

        const input = wrapper.find('#message');

        input.setValue(wrapper.props().modelValue + "#h");

        await wrapper.vm.$nextTick();

        expect (wrapper.vm.query).toBe("h");

    });

});

///

The error message:

    TypeError: _ctx.$emit is not a function
1

There are 1 answers

0
Ben On

Not really answer, but if I stop trying to update modelValue by updating the input field and juts update the modelValue directly then it works:

    it("should update query when there is a match with autoconfig", async () => {

        wrapper.setProps({ modelValue: wrapper.props().modelValue + "#h" })

        await wrapper.vm.$nextTick();

        expect (wrapper.vm.query).toBe("h");
    });