Unit Test Vue Apps with Vue Test Utils — Keyboard and Mouse Events

John Au-Yeung - Jan 23 '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 the Vue Test Utils library, we can write and run unit tests for Vue apps easily.

In this article, we’ll look at how to write unit tests with the Vue Test Utils library.

Keyboard Event Tests

We can test keyboard events in our code.

For example, we can write:

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

const KEY_DOWN = 40
const KEY_UP = 38
const ESCAPE = 27

const QuantityComponent = {
  template: `
    <div>
      <input type="text" [@keydown](http://twitter.com/keydown "Twitter profile for @keydown").prevent="onKeydown" v-model="quantity" />
    </div>
  `,
  data() {
    return {
      quantity: 0
    }
  },
  methods: {
    increment() {
      this.quantity += 1
    },
    decrement() {
      this.quantity -= 1
    },
    clear() {
      this.quantity = 0
    },
    onKeydown(e) {
      if (e.keyCode === ESCAPE) {
        this.clear()
      }
      if (e.keyCode === KEY_DOWN) {
        this.decrement()
      }
      if (e.keyCode === KEY_UP) {
        this.increment()
      }
      if (e.key === 'a') {
        this.quantity = 10
      }
    }
  },
  watch: {
    quantity(newValue) {
      this.$emit('input', newValue)
    }
  }
}

describe('Key event tests', () => {
  it('Quantity is zero by default', () => {
    const wrapper = mount(QuantityComponent)
    expect(wrapper.vm.quantity).toBe(0)
  })

  it('Up arrow key increments quantity by 1', async () => {
    const wrapper = mount(QuantityComponent)
    await wrapper.find('input').trigger('keydown.up')
    expect(wrapper.vm.quantity).toBe(1)
  })

  it('Down arrow key decrements quantity by 1', async () => {
    const wrapper = mount(QuantityComponent)
    wrapper.vm.quantity = 2
    await wrapper.find('input').trigger('keydown.down')
    expect(wrapper.vm.quantity).toBe(1)
  })

  it('Escape sets quantity to 0', async () => {
    const wrapper = mount(QuantityComponent)
    wrapper.vm.quantity = 3
    await wrapper.find('input').trigger('keydown.esc')
    expect(wrapper.vm.quantity).toBe(0)
  })

  it('Magic character "a" sets quantity to 10', async () => {
    const wrapper = mount(QuantityComponent)
    await wrapper.find('input').trigger('keydown', {
      key: 'a'
    })
    expect(wrapper.vm.quantity).toBe(10)
  })
})
Enter fullscreen mode Exit fullscreen mode

to trigger the keyboard events on each test.

The QuantityComponent has an input element that listens to the keydown event and updates the quantity accordingly.

The onKeydown method updates the quantity reactive property to set the value according to the key that’s pressed.

In our tests, we get the input element with the find method.

Then we call trigger to trigger various kinds of keydown events.

keydown.up simulates pressing the up arrow.

keydown.up simulates pressing the down arrow.

keydown.up simulates pressing the esc key.

The last test simulates pressing the 'a' key.

Once we did that, we can check the quantity reactive property to get the final result.

Testing Async Behavior

We can test async behavior by using the same principles as the previous example.

For example, we can write:

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

const Counter = {
  template: `
    <div>
      <button @click='count++'>add</button>
      <p>{{count}}</p>
    </div>
  `,
  data() {
    return {
      count: 0
    }
  },
}

describe('Counter tests', () => {
  it('count is set to 1 after click', async () => {
    const wrapper = mount(Counter)
    expect(wrapper.text()).toContain('0')
    const button = wrapper.find('button')
    await button.trigger('click')
    expect(wrapper.text()).toContain('1')
  })

})
Enter fullscreen mode Exit fullscreen mode

We have the Counter component that updates the count reactive property when we click on the add button.

Then in our test, we check the rendered content with the text method.

And then we click the button and do the check again.

Conclusion

We can simulate clicks and keyboard events in our tests and test the rendered content.

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