·
2 min read

Vue Tip: Test Vue Components Using Vue Testing Library

Vue Tip: Test Vue Components Using Vue Testing Library Image

Vue Testing Library is my preferred Vue.js testing library. It is built on top of @vue/test-utils, the official testing library for Vue.

If we write tests for our Vue components, we want them to be maintainable. Therefore, our tests should not include implementation details of our components.

The primary guiding principle of Vue Testing Library is:

The more your tests resemble the way your software is used, the more confidence they can give you.

So rather than dealing with instances of rendered Vue components, the tests will work with actual DOM nodes. The library provides methods to query the DOM the same way the user would. Users are looking for specific text or a button to click. They don't look for the nth child of a div with the class .button-container.

Let's take a look at a simple example:

Button.vue
<template> <p>Times clicked: {{ count }}</p> <button @click="increment">Increment</button> </template> <script setup> const count = ref(0) const increment = () => (count.value = count.value + 1) </script>
button.spec.js
import { render, screen, fireEvent } from '@testing-library/vue' import Button from './Button' test('increments value on click', async () => { // The `render` method renders the component into the document. // It also binds to `screen` all the available queries to interact with // the component. render(Button) // queryByText returns the first matching node for the provided text // or returns null. expect(screen.queryByText('Times clicked: 0')).toBeTruthy() // getByText returns the first matching node for the provided text // or throws an error. const button = screen.getByText('increment') // Click a couple of times. await fireEvent.click(button) await fireEvent.click(button) expect(screen.queryByText('Times clicked: 2')).toBeTruthy() })

Info

The byText query could be replaced by a more suitable query like getByRole, see Which query should I use?.

Info

Installing jest-dom adds some useful assertions like .toBeInTheDocument(). In our example, we could then change the assertion to expect(screen.queryByText('Times clicked: 0')).toBeInTheDocument().

This test does not contain any implementation details of our Button component, so it's unlikely to break even under heavy refactoring.

If you liked this Vue tip, follow me on X to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter:

I will never share any of your personal data. You can unsubscribe at any time.