Unit Test Vue Apps with Vue Test Utils — Lifecycle and Async Tests
Tags: vue, javascript, testing, webdev
Published: 2021-01-23 02:09:51

**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.

### Lifecycle Hooks

When we call `mount` or `shallowMount` to mount our components, the lifecycle methods will be run.

However, the `beforeDestroy` or `destroyed` methods won’t be triggered unless the component is manually destroyed with `wrapper.destroy()` .

The component won’t be automatically destroyed at the end of each test, so we have to clean up any dependencies manually.

### Writing Asynchronous Tests

When we write tests, we have to be aware that any changes to reactive properties are done asynchronously.

This means that we have to the test as an async function or use `then` and run our test code that runs after the reactive property is updated in the `then` callback.

For example, 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')
  })
})
```

to `await` the `trigger` method so that we can check the updated value of the `count` reactive property after the update is done.

We can also 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', () => {
    const wrapper = shallowMount(Counter)
    const button = wrapper.find('button')
    const text = wrapper.find('p')
    button.trigger('click')
      .then(() => {
        expect(text.text()).toBe('clicks: 1')
      })
  })
})
```

which is the same code without async and await.

### Asserting Emitted Events

We can check which events are emitted when we do something with the component.

To do this, we can call the `emitted` method to check which events are emitted.

For instance, we can write:

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

const Foo = {
  template: `
    <div>
      <button @click="$emit('foo')">emit foo</button>
    </div>
  `,
}

describe('Foo', () => {
  it('emits foo event when the emit foo button is clicked', async () => {
    const wrapper = shallowMount(Foo)
    const button = wrapper.find('button');
    await button.trigger('click')
    expect(wrapper.emitted().foo).toBeTruthy()
  })
})
```

We have the `Foo` component that calls `$emit` to emit the `'foo'` event when we click it.

Then in the last line of the test, we call `wrapper.emitted()` to check if the `foo` event is emitted.

If it’s emitted, then the `foo` property should be truthy.

We can also check which payload is emitted. For example, we can write:

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

const Foo = {
  template: `
    <div>
      <button @click="$emit('foo', 123)">emit foo</button>
    </div>
  `,
}

describe('Foo', () => {
  it('emits foo event with payload 123 when the emit foo button is clicked', async () => {
    const wrapper = shallowMount(Foo)
    const button = wrapper.find('button');
    await button.trigger('click')
    expect(wrapper.emitted().foo.length).toBe(1)
    expect(wrapper.emitted().foo[0]).toEqual([123])
  })
})
```

We check the `foo` property’s `length` to see how many times it’s emitted.

And the payload is checked by accessing `foo` ‘s array value and checking the content.

### Conclusion

We can check if events are emitted and be aware that lifecycle hooks like `destroy` aren’t run automatically.