Unit Test Vue Apps with Vue Test Utils — Transitions and Plugin Tests

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 Transitions

We can test components with transitions the same way we test other components.

All we have to do is to set the reactive properties to the value we want.

For example, we can write:

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

const Foo = {
  template: `
    <div>
      <transition>
        <p v-if="show">Foo</p>
      </transition>
    </div>
  `,
  data() {
    return {
      show: true
    }
  }
}

describe('Foo', () => {
  it('renders bar for foo prop', async () => {
    const wrapper = mount(Foo)
    expect(wrapper.text()).toMatch(/Foo/)
    await wrapper.setData({
      show: false
    })
    expect(wrapper.text()).not.toMatch(/Foo/)
  })
})
Enter fullscreen mode Exit fullscreen mode

We call mount to mount the Foo component.

Then we check what’s displayed before we set the show reactive property to false .

Then we call setData to set show to false .

Then we check the pattern of the content displayed with the text method to return the rendered text and the toMatch method to check whether the content matches the given regex pattern.

We can also stub the transitions with the transitionStub helper:

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

const Foo = {
  template: `
    <div>
      <transition>
        <p v-if="show">Foo</p>
      </transition>
    </div>
  `,
  data() {
    return {
      show: true
    }
  }
}

const transitionStub = () => ({
  render(h) {
    return this.$options._renderChildren
  }
})

describe('Foo', () => {
  it('renders bar for foo prop', async () => {
    const wrapper = mount(Foo, {
      stubs: {
        transition: transitionStub()
      }
    })
    expect(wrapper.text()).toMatch(/Foo/)
    await wrapper.setData({
      show: false
    })
    expect(wrapper.text()).not.toMatch(/Foo/)
  })
})
Enter fullscreen mode Exit fullscreen mode

transitionStub is just a function that returns an object with the render method to simulate rendering the transitions.

We can also avoid using setData if we mount our component and set the reactive properties’ values when we mount it:

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

const Foo = {
  template: `
    <div>
      <transition>
        <p v-if="show">Foo</p>
      </transition>
    </div>
  `,
  data() {
    return {
      show: true
    }
  }
}

test('should render Foo', async () => {
  const wrapper = mount(Foo, {
    data() {
      return {
        show: true
      }
    }
  })

  expect(wrapper.text()).toMatch(/Foo/)
})

test('should not render Foo', async () => {
  const wrapper = mount(Foo, {
    data() {
      return {
        show: false
      }
    }
  })

  expect(wrapper.text()).not.toMatch(/Foo/)
})
Enter fullscreen mode Exit fullscreen mode

Applying Global Plugins and Mixins

If we want to apply global plugins, then we have to use the createLocalVue to return a mocked version of the Vue constructor.

This way, we can control when the global plugin is applied.

For example, we can write:

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

const localVue = createLocalVue()

const MyPlugin = {};
MyPlugin.install = function (Vue, options) {
  Vue.prototype.fooMethod = function () {
    this.foo = 'bar';
  }
}

localVue.use(MyPlugin);
const Foo = {
  template: `
    <div>
      <p>{{foo}}</p>
    </div>
  `,
  data() {
    return {
      foo: ''
    }
  }
}

test('should render bar', async () => {
  const wrapper = mount(Foo, {
    localVue
  })
  await wrapper.vm.fooMethod();
  expect(wrapper.text()).toContain('bar')
})
Enter fullscreen mode Exit fullscreen mode

We call the createLocalVue function to create a mock version of the Vue constructor.

Then we create our plugin by defining the MyPlugin object and adding the fooMethod instance method to our plugin.

Next, we call localVue.use(MyPlugin) so we can add our plugin with we mount the Foo component.

Then in our test, we set the localVue property in the object in the 2nd argument of mount .

And we call our fooMethod to run the test.

Finally, we check if the text is rendered.

Conclusion

We can mock transitions and plugins so that we can do test with plugins.

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