Unit Test Vue Apps with Vue Test Utils — Mocking Items

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.

Mocking Injections

We can mock injected reactive properties by passing them all in the mocks property when we mount our component.

For example, we can write:

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

const Foo = {
  template: `
    <div>
      <p>{{$route.path}}</p>
    </div>
  `,
}

const $route = {
  path: '/foo',
}

test('should render the path', () => {
  const wrapper = mount(Foo, {
    mocks: {
      $route
    }
  })
  expect(wrapper.text()).toContain('/foo')
})
Enter fullscreen mode Exit fullscreen mode

We just set the $route property to the $route object in the mocks object then we should see it rendered.

Stubbing Components

We can stub global components by writing using the stubs property:

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

const Foo = {
  template: `
    <div>
      <child-component></child-component>
    </div>
  `,
}

test('should render child-component', () => {
  const wrapper = mount(Foo, {
    stubs: ['child-component']
  })
  expect(wrapper.find('child-component')).toBeTruthy()
})
Enter fullscreen mode Exit fullscreen mode

We have the child-component in Foo which we didn’t register, so we can stub it by using the stubs property to stub it with an empty component.

Testing Key, Mouse, and Other DOM Events

We can trigger events on component with the trigger method.

For example, we can write:

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

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

test('shows latest count when button is clicked', async () => {
  const wrapper = mount(MyButton)
  await wrapper.trigger('click')
  expect(wrapper.text()).toContain('1');
})
Enter fullscreen mode Exit fullscreen mode

We mount the MyButton component and call trigger on the returned component wrapper.

Then we can check the latest value of count with the text method.

For example, we can write:

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

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

test('shows latest count when button is clicked', async () => {
  const wrapper = mount(MyButton)
  await wrapper.find('button').trigger('click')
  expect(wrapper.find('p').text()).toContain('1');
})
Enter fullscreen mode Exit fullscreen mode

to create the MyButton component with the add button.

It updated the count when we click it.

To test it, we call find to find the button. Then we call trigger to trigger the click event.

Then we call find with the 'p' selector to check the content of the p element.

We can check if a method is called when we trigger an event on an element.

For example, we can write:

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

const Foo = {
  template: `
    <div>
      <button class="yes" @click="callYes">Yes</button>
      <button class="no" @click="callNo">No</button>
    </div>
  `,
  props: {
    callMe: {
      type: Function
    }
  },
  methods: {
    callYes() {
      this.callMe('yes')
    },
    callNo() {
      this.callMe('no')
    }
  }
}

test('should call callMe with the right arguments when buttons are clicked', async () => {
  const spy = jest.fn();
  const wrapper = mount(Foo, {
    propsData: {
      callMe: spy
    }
  })
  await wrapper.find('button.yes').trigger('click')
  expect(spy).toHaveBeenCalledWith('yes');
  await wrapper.find('button.no').trigger('click')
  expect(spy).toHaveBeenCalledWith('no');
})
Enter fullscreen mode Exit fullscreen mode

We have the Foo component that takes a callMe function as a prop.

Then to write our test, we create a spy of the callMe function by calling jest.fn() .

Next, we pass that in as a prop with we mount Foo .

Finally, we call trigger to trigger clicks on the buttons and check the rendered results.

toHaveBeenCalledWith takes the arguments of the function we’re expecting.

Conclusion

We can mock various items in our components with Jest and Vue Test Utils.

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