Testing Vue 3 Apps — Reactive Properties and Form Handling

John Au-Yeung - Jan 19 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.

In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.

Passing Data to Components

We can pass data to components.

For example, we can write:

import { mount } from '@vue/test-utils'

const Name = {
  template: `
    <div>
      <input v-model="name">
      <div v-if="error">{{ error }}</div>
    </div>
  `,
  props: {
    minLength: {
      type: Number
    }
  },
  computed: {
    error() {
      if (this.name.length < this.minLength) {
        return `Name must be at least ${this.minLength} characters.`
      }
      return
    }
  }
}

test('renders an error if length is too short', () => {
  const wrapper = mount(Name, {
    props: {
      minLength: 10
    },
    data() {
      return {
        name: 'short'
      }
    }
  })
  expect(wrapper.html()).toContain('Name must be at least 10 characters')
})
Enter fullscreen mode Exit fullscreen mode

We have the Name component with an input field and an error display.

The error computed property checks if the name is too short and show an error message if it is.

In the test, we pass in the minLength prop to the component.

And the data method has the name reactive property set.

Then we show the error message since the name value’s length is shorter than 10.

Using setProps

We can also use the setProps method to set the props.

For example, we can write:

import { mount } from '@vue/test-utils'

const Show = {
  template: `
    <div>
      <div v-if="show">{{ greeting }}</div>
    </div>
  `,
  props: {
    show: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      greeting: 'Hello'
    }
  }
}

test('renders a greeting when show is true', async () => {
  const wrapper = mount(Show)
  expect(wrapper.html()).toContain('Hello')
  await wrapper.setProps({ show: false })
  expect(wrapper.html()).not.toContain('Hello')
})
Enter fullscreen mode Exit fullscreen mode

We test the Show component and check if the 'Hello' is rendered in the component.

Then we call setProps to set the show prop to false .

Then we check that 'Hello' isn’t rendered.

Test Form Handling

We can test form handling by interacting with form elements.

For example, we can write:

import { mount } from '@vue/test-utils'

const EmailInput = {
  template: `
    <div>
      <input type="email" v-model="email">
      <button @click="submit">Submit</button>
    </div>
  `,
  data() {
    return {
      email: ''
    }
  },
  methods: {
    submit() {
      this.$emit('submit', this.email)
    }
  }
}

test('sets the value', async () => {
  const wrapper = mount(EmailInput)
  const input = wrapper.find('input')
  await input.setValue('abc@mail.com')
  expect(input.element.value).toBe('abc@mail.com')
})
Enter fullscreen mode Exit fullscreen mode

We have an EmailInput component with an input component.

Then we add a test to mount the EmailInput component.

Then we get the input with find .

And then we call input.setValue to set its value.

Then we get the value from the input with input.element.value .

Conclusion

We can pass in the data for the props and test the rendered Vue 3 components with Vue Test Utils.

Also, we can test form inputs with this.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .