vue.jsvue-test-utilsvue-formulate

Unit test of Vue Formulate not seeing errors


I am getting started with unit testing components in Vue using Jest and Vue-Test-Utils. I am using Vue Formulate to manage form fields, which works as expected in the browser. I am importing the plugin in a 'local Vue' testing instance as per the documentation.

However, the following assertion fails as text not found in testing, whilst it works in the browser. What am I doing wrong? I have tried a variety of selectors including wrapper.text() without success

Component:

<template>
<div class="card">
    <FormulateForm v-model="formValues">
        <FormulateInput type="text" label="Full Name" name="name" validation="required"/>
    </FormulateForm>
</div>
</template>

<script>
export default {
name: "RegistrationFormComponent",

data: function(){
    return {
        'formValues' : {},
    }
}
</script>

Test

import { mount, createLocalVue } from '@vue/test-utils';
import VueFormulate from '@braid/vue-formulate';
import registrationForm from '../../resources/js/components/RegistrationFormComponent'

test('name field is required', async () => {
    const localVue = createLocalVue();
    localVue.use(VueFormulate);
    let wrapper = mount(registrationForm,{localVue});

    let form = wrapper.find('form');
    let field = form.find('input[name=name]');

    await field.setValue('');
    expect(wrapper.find('.formulate-input-error').text()).toContain('Name is required');
})

Jest Output:

 FAIL  tests/Vue/registrationForm.test.js
  ● email must be a valid email address

    [vue-test-utils]: find did not return .formulate-input-error, cannot call text() on empty Wrapper

      12 | 
      13 |     await field.setValue('Dog');
    > 14 |     expect(wrapper.find('.formulate-input-error').text()).toContain('a valid email');
         |                                                   ^
      15 | })

Solution

    1. If you’re checking for errors, you’ll need your error-visibility on the input to be “live”, or you need to simulate a blur event (in this case this is almost certainly the issue).
    2. Because watchers are involved in Vue Formulate’s internals you often need to “flush” all the promises before the state “settles”. You can do this by installing the flush-promises module.
    npm install -D flush-promises
    

    Then import this in your test file, and await flushPromises() before checking for your final states.

    import flushPromises from 'flush-promises'
    import { mount, createLocalVue } from '@vue/test-utils';
    import VueFormulate from '@braid/vue-formulate';
    import registrationForm from '../../resources/js/components/RegistrationFormComponent'
    
    test('name field is required', async () => {
        const localVue = createLocalVue();
        localVue.use(VueFormulate);
        let wrapper = mount(registrationForm,{localVue});
    
        let form = wrapper.find('form');
        let field = form.find('input[name=name]');
    
        field.setValue('');
        field.trigger('blur');
        await flushPromises()
        expect(wrapper.find('.formulate-input-error').text()).toContain('Name is required');
    })
    

    Full Disclosure: I’m the author of VueFormulate