In vue test utils $refs is set to an empty object

Viewed 530

I'm mounting a component EditUser in tests using the mount function from vue-test-utils. EditUser has one child component ChangePassword. mount should mount all child components as is and not stub them. I'm accessing the ChangePassword components submit method using a ref like this this.$refs.changePassword.submit(). It works fine in browser but in test $refs is getting set to an empty object and can not access the submit method. I'm using jest to test my vue components.

In EditUSer.vue component

updatePassword() {
  this.$refs.changePassword.submit()
    .then(data => {
       this.successMessage = data.message
       this.$bvModal.hide('change-password-modal')
     })
     .catch(data => {
       console.error(data.message)
      })
}

In template

<b-modal id="change-password-modal" title="Change Password" size="lg" @ok="updatePassword">
    <change-password ref="changePassword" :id="id"></change-password>
</b-modal>

And in ChangePassword.vue component I have a submit method

submit() {
  return this.form.patch('/api/users/' + this.id + '/password')
}

In test

it ('updates password', async () => {
    moxios.stubRequest('/api/users/1/password', {
      status: 200,
      response: {
        message: 'Password updated successfully!'
      }
    })

    const wrapper = mount(EditUser, { propsData: { id: 1 } })
    const testUtils = new TestUtils(wrapper)

    wrapper.vm.updatePassword()

    await flushPromises()

    testUtils.see('Password updated successfully!')
  })

It works fine in browser but in test (jest) I'm getting this error

TypeError: Cannot read property 'submit' of undefined

      262 |       },
      263 |       updatePassword() {
    > 264 |         this.$refs.changePassword.submit()
          | ^
      265 |             .then(data => {
      266 |               this.successMessage = data.message
      267 |               this.$bvModal.hide('change-password-modal')

      at VueComponent.updatePassword (src/Users/EditUser.vue:264:1)
      at Object.<anonymous> (tests/unit/users/editUser.spec.js:64:16)
1 Answers

I had a similar problem using Vuetify's v-dialog. I'm not familiar with BootstrapVue, but I think the issue stems from how Vue itself sets up the $refs.

$refs won't be updated until the bound component is created, and Vue will wait to create the component until it needs to be rendered.

To get around this, just make sure your change-password component has been rendered at least once in your test before trying to access $refs.

In your test, try something like

wrapper.vm.$bvModal.show('change-password-modal'); // should render the content, binding $refs.
await wrapper.vm.$nextTick(); // make sure Vue has time to update
wrapper.vm.updatePassword();
Related