Cutting corners during testing can lead to false confidence and, ultimately, a faulty app. Learn how to test Vue components using Vue Testing Library.
Testing is crucial in the development of any application. Cutting corners during the testing phase can lead to false confidence and, ultimately, a faulty app.
In this tutorial, we’ll demonstrate how to test Vue components using Vue Testing Library. While there are countless other testing libraries we could use, I’m a proponent of testing your application the way your users would use it, and that’s precisely what Vue Testing Library aims to do.
Vue Testing Library a member of the Testing Library family, which includes React Testing Library, DOM Testing Library, and more. It builds upon Vue Test Utils, the official testing library for Vue, and DOM Testing Library, which enables it to use features from the Testing Library family.
To follow along with this tutorial, you should have:
Since we’ll be creating and testing single-file components, you’ll need to create a new Vue project using the Vue CLI.
Run the command below to set up a new Vue project.
vue create testing-vue-components.
We can stick to the default Vue configurations since we’ll be installing any additional dependencies by ourselves.
Vue Testing Library can be used with a lot of testing frameworks, but we’ll use Jest for this tutorial.
Install jest and Vue Testing Library.
npm i --save-dev jest @testing-library/vue
Since we’ll be writing ES6, we need to use Babel to handle the compilation for us. Vue already ships with a Babel configuration, so we just need to install babel-jest
and configure Jest to transform .js
files using Babel.
npm i --save-dev babel-jest
Again, because we’re writing single-file components, we need to configure Jest to load .vue
files. The vue-jest
package helps with that.
npm install --save-dev vue-jest@4.0.0-beta.3
Finally, update the package.json
to contain the necessary configuration.
"jest": {
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"transform": {
"^.+\\.js$": "babel-jest",
".*\\.(vue)$": "vue-jest"
}
},
When a user loads a page, they should be able to see the component, so the first thing to test should be that the component renders.
Consider this simple Counter
component, which provides two buttons for counting and shows the number of counts:
// Counter.vue
<template>
<div>
<h3>Count: {{ counter }}</h3>
<div class="button-container">
<button @click="increment">Add</button>
<button @click="decrement">Subtract</button>
</div>
</div>
</template>
<script>
export default {
name: 'Counter',
data() {
return {
counter: 0,
};
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter--;
},
},
};
</script>
To test the component, create a Counter.js
file in the tests
directory.
import Counter from '../Counter.vue';
import { render } from '@testing-library/vue';
test('It renders correctly', () => {
const { getByText } = render(Counter);
getByText('Count: 0');
});
The getByText
helper checks that there is a text with the specified argument in the document. In our counter component, the initial state of counter
is set to 0
, so without clicking any button, we should have Count: 0
rendered to the document.
Other actions that a user might perform include clicking on both buttons, so we need to test those as well.
import Counter from '../Counter.vue';
import { render, fireEvent } from '@testing-library/vue';
test('It correctly responds to button clicks', async () => {
const { getByText } = render(Counter);
// Check initial state
getByText('Count: 0');
// Get buttons.
const addButton = getByText('Add');
const subtractButton = getByText('Subtract');
// Click the Add button.
await fireEvent.click(addButton);
// Counter should be updated.
getByText('Count: 1');
// Click the subtract button.
await fireEvent.click(subtractButton);
// Counter should be updated.
getByText('Count: 0');
// Further clicks
await fireEvent.click(addButton);
await fireEvent.click(addButton);
await fireEvent.click(addButton);
await fireEvent.click(addButton);
getByText('Count: 4');
await fireEvent.click(subtractButton);
await fireEvent.click(subtractButton);
getByText('Count: 2');
});
Using getByText
, we can get the buttons and click them just as a normal user would.
As the name implies, fireEvent
is used to dispatch different events on elements. We’re awaiting events here because Vue updates the DOM asynchronously, hence all the events dispatched from fireEvent
returns a promise which will get resolved on the next tick.
#vue #testing #developer