9

In my Vue 2.7.14 app I'm using Vuelidate 2.0.0. I'm trying to migrate a test from Jest to Vitest, but the v$ object is not initialised correctly in the latter case. The component has a checkbox bound to formData.accepted

  validations () {
    return {
      formData: {
        accepted: {
          required,
          sameAs: sameAs(true)
        }
      }
    }
  }

Vuelidate is initialised within the component as per the docs

  setup () {
    return {
      v$: useVuelidate({ $autoDirty: true })
    }
  },

When I run the following test under Jest, it passes

  it('click save button', async () => {
    const wrapper = mount(MyComponent)

    expect(wrapper.vm.v$.formData.accepted.$invalid).toBeTruthy()
    await wrapper.find('[data-cy="accept-checkbox"]').trigger('click')
    expect(wrapper.vm.v$.formData.accepted.$invalid).toBeFalsy()
  })

However, if I run the same test using Vitest it fails because wrapper.vm.v$.formData is undefined because v$ is initialised to:

v$ {
  "$dirty": false,
  "$path": "__root",
  "$model": null,
  "$error": false,
  "$errors": [],
  "$invalid": false,
  "$anyDirty": false,
  "$pending": false,
  "$silentErrors": [],
  "$validationGroups": {}
}

By contrast, when the Jest test is run, $silentErrors is not empty, and the following property path is (obviously) valid

v$.formData.accepted.$invalid 

What should I do to ensure that v$ is initialised correctly when the test is run with Vitest?

Dónal
  • 185,044
  • 174
  • 569
  • 824
  • Were you able to find a solution here? I'm seeing the same issue with no clear work-around. – Stephen Dec 31 '22 at 00:05
  • @Stephen yes, I'm not sure which version of Vitest I was using when I ran into this issue, but I tried again with a later version and the problem just magically disappeared. – Dónal Jul 04 '23 at 10:50

2 Answers2

0

First try:

You need to assign a const to the wrapper:

  it('click save button', async () => {
    const wrapper = mount(MyComponent)
    const { $v } = wrapper.vm;

    expect(wrapper.vm.v$.formData.accepted.$invalid).toBeTruthy()
    await wrapper.find('[data-cy="accept-checkbox"]').trigger('click')
    expect(wrapper.vm.v$.formData.accepted.$invalid).toBeFalsy()
  })

Further try:

I think you are also missing the import of validationMixin in your test file to use the $v object:

import { validationMixin } from 'vuelidate';

After that change your component to this:

export default {
  mixins: [validationMixin],
  setup () {
    return {
      v$: useVuelidate()
    }
}

Glad about feedback if it worked and if not we'll get there. :)

Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
  • 1
    Alright, I just read your new answer. I'll take a look after work again if it's fine for you – Ole Pannier Dec 13 '22 at 10:15
  • The code in your "First try" suggestion is functionally identical to the code I'm already using (which doesn't work). The only difference is the addition of an unused `$v` variable – Dónal Dec 13 '22 at 10:15
  • 1
    I appreciate your effort, but your answer assumes I'm using Vuelidate 0.X, but I'm actually using 2.0, which has a very different API e.g. the validationMixin you mention no longer exists https://vuelidate-next.netlify.app/migration_guide.html#removal-of-validationmixin – Dónal Dec 13 '22 at 10:15
  • 2
    I already know that `v$` is not initialised correctly, the very point of my question is to find out how to fix this problem. By the way, in Vuelidate 2.0, it's recommended you use `v$` rather than `$v` https://vuelidate-next.netlify.app/migration_guide.html#v-instead-of-v – Dónal Dec 13 '22 at 10:17
-1

To initialise Vuelidate when testing a Vue component with Vitest you can use the following approach:

1. Add the following line to your test file:

import Vuelidate from 'vuelidate';

2. Use Vuelidate in your test like so:

it('click save button', async () => {

const wrapper = mount(MyComponent)

const v = Vuelidate.instance()

expect(v.formData.accepted.$invalid).toBeTruthy()

await wrapper.find('[data-cy="accept-checkbox"]').trigger('click')

expect(v.formData.accepted.$invalid).toBeFalsy()

})

3. Make sure that Vuelidate is initialised correctly within your Vue component like so:

v$: useVuelidate({

$autoDirty: true

})