Unit Test Vue Apps with Vue Test Utils

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.

Installation

We can add it when we run Vue CLI to scaffold our app.

We select Unit Tests from the list and then select Jest to add the test framework with the production code.

Usage

Once we added the test files, we can write our unit tests.

In our unit tests, we can interact with our components like we do when using them.

To do that, we mount the component and interact with the elements by triggering events on them.

Also, we can mock any data and external resources that need to be set to let us do the tests.

This way, we can run our tests independently without relying on anything external that makes the tests unreliable.

To write our first test, we can add the test in the tests/unit folder by writing:

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

const MessageComponent = {
  template: '<p>{{ msg }}</p>',
  props: ['msg']
}

describe('MessageComponent', () => {
  it('renders props.msg when passed', () => {
    const msg = 'new message'
    const wrapper = shallowMount(MessageComponent, {
      propsData: { msg }
    })
    expect(wrapper.text()).toMatch(msg)
  })
})
Enter fullscreen mode Exit fullscreen mode

We have the MessageComponent that renders the value of the msg prop onto the screen.

In our test, which is in the callback we pass into it , we call shallowMount to mount the component without its children.

propsData lets us pass the prop data we need for the test.

Then the wrapper.text() method returns the rendered text.

And we use toMatch to check the results.

To run the test, we run npm run test:unit to run the unit test and then we should see some green text to indicate that the test passed.

Simulating User Interaction

We can also simulate user interaction easily.

To do that, we can write:

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

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

describe('Counter', () => {
  it('renders new number when Add up button is clicked', async () => {
    const wrapper = shallowMount(Counter)
    const button = wrapper.find('button')
    const text = wrapper.find('p')
    await button.trigger('click')
    expect(text.text()).toBe('clicks: 1')
  })
})
Enter fullscreen mode Exit fullscreen mode

We have the Counter component that we want to test.

It has a button that increases count by 1 when we click it.

Then in the test, we call shallowMount to mount the component.

Then we call wrapper.find to get the button and the p element.

To simulate a click on the button, we call trigger to trigger the click event.

trigger is async is returns a promise, so our test callback has to be an async function and we have to await the trigger method.

Then we check the text displayed in the p element with the text method and see if the text has been updated.

Conclusion

We can write unit tests easily to test Vue apps by using Jest and simulating user actions.

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