This tutorial is out of date and no longer maintained.
Vue.js is a JavaScript framework that is useful for building the front-end of web applications, particularly when creating complex features. For every project, it’s necessary to go through everything in our applications and check that it all works as expected. However, for large projects, it quickly becomes tedious to check every feature after every new update. For this reason, we can create automated tests which can run all the time and give us reassurance that our code works. In this tutorial, we will create a few simple unit tests for VueJS which show how to get started.
To have something to test, we will be making a basic to-do list component. We’ll test that the list gets displayed correctly and also that the user can add new items to the to-do list. Hopefully, by the end of this tutorial, you’ll be able to write tests that check what your component outputs to the user and which simulate user actions by interacting with the HTML (for example by clicking a button).
Here is my GitHub repo with all the code in this post.
Setting up a JavaScript project can be a complicated process. There are so many libraries that need to be chosen, all of them serving a slightly different purpose. Fortunately, for VueJS, we have vue-cli
, which sets everything up for us! You’ll need to have npm installed first and then you can run the following commands:
- npm install -g vue-cli
- vue init webpack project-name
At this stage, you’ll be prompted with a few questions. Most of them are straightforward and you can choose the default option. The only requirement is that you:
vue-router
Then install the dependencies:
- cd project-name
- npm install
This final command will start up your browser and take you to localhost where your application will be running:
- npm run dev
Here is a (very) brief overview of some of the key dependencies that vue-cli
has set up for us, including the version which was installed for my own project.
In your project, you should find the following folders: build
, config
, node_modules
, src
, static
, and test
. The only ones which are important for this tutorial are src
, which will hold our application code, and test
.
It is always good to start off with something fairly basic to get going. We’ll start off with creating our simple list component. Create a new file called List.vue
in the src/components
folder and put the following code inside:
<template>
<div>
<h1>My To Do List</h1>
<!--displays list -->
<ul>
<li v-for="item in listItems">{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'list',
data () {
return {
listItems: ['buy food', 'play games', 'sleep'],
}
}
}
</script>
In the component, the list items are stored in an array (listItems
) in the component data. This data is then accessible to the template where it is looped over in a foreach
loop (v-for
) and displayed on the page.
Since it’s more fun if we can see our list, we can create a new route to display our component. Go into src/router/index.js
and add a route, and your code should look something like this:
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import List from '@/components/List'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: Hello
},
{
path: '/to-do',
name: 'ToDo',
component: List
},
]
})
Now if you navigate to localhost:8080/#/to-do
, you will see your list!
First, we want to test if the data is displayed correctly. Inside test/unit/specs
, create a new file List.spec.js
and put the following code:
import List from '@/components/List';
import Vue from 'vue';
describe('List.vue', () => {
it('displays items from the list', () => {
// our test goes here
})
})
In this file, we are describing the List.vue
component and we have a single empty test that will check that it (the component) displays items from the list. This is the basic file structure for Mocha tests.
Inside our test, we first need to set up the Vue component. Copy the code below and put it under the comment our test goes here
:
// build component
const Constructor = Vue.extend(List);
const ListComponent = new Constructor().$mount();
We extend Vue and then mount our component. It is important to mount the component as this is the bit that renders the HTML in our template. This essentially means that the HTML gets built and the variables in our template (e.g., {{ item }}
) get filled with data, enabling us to later have access to the HTML (via $el)
.
With our component ready, we can write our first assertion. In this example, we are using the ‘expect’ style, which is provided by Chai assertion library, along with ‘should’ and ‘assert’. Put the following code after mounting the component:
// assert that component text contains items from the list
expect(ListComponent.$el.textContent).to.contain('play games');
As I mentioned before, we can get the component’s HTML using ListComponent.$el
, and to access only the inner HTML (i.e., the text), we have ListComponent.$el.textContent
. The assertion is checking that the text contains one of the list items which is set in the component’s data.
To check that everything is working as it should be, we can run the tests! With the vue-cli
project, we can simply type npm run unit
, which is an alias for cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run
(much more memorable!)
- npm run unit
If all the tests have passed, it will be showing green with a list of the successful tests and a code coverage report, letting you know what percentage of your application code was executed during the tests.
That’s a good start, but it is rare indeed that your app will only be displaying data. The next feature we’re going to add is for the user to be able to add new items to their list. For this we want an input box where the user can type the new item and a button which adds the item to the list on click. This is an updated version of List.vue
:
<template>
<div>
<h1>My To Do List</h1>
<input v-model="newItem" >
<button @click="addItemToList">Add</button>
<!-- displays list -->
<ul>
<li v-for="item in listItems">{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'test',
data () {
return {
listItems: ['buy food', 'play games', 'sleep'],
newItem: ''
}
},
methods: {
addItemToList() {
this.listItems.push(this.newItem);
this.newItem = '';
}
}
}
</script>
Using v-model
, the value of the input box is bound to newItem
variable stored in the component’s data. When the button is clicked, the function addItemToList
gets executed which adds the newItem
to the list array and clears the newItem
so that more can be added to the list.
To start testing this feature, create a new empty test in List.spec.js
and add the test code as we go along:
it('adds a new item to list on click', () => {
// our test goes here
})
First, we’ll want to build our component and mimic a user typing in the input box. Since VueJS binds the value of the input box to the newItem
variable, we can simply set our value to newItem
.
// build component
const Constructor = Vue.extend(List);
const ListComponent = new Constructor().$mount();
// set value of new item
ListComponent.newItem = 'brush my teeth';
Next, we need to click the button. We have to find the button in the HTML, which is available with $el
. Only this time we can use querySelector
so as to find the actual element. It is possible to find an element using its class (.buttonClass
), its id (#buttonId
), or the element’s name (button
).
// find button
const button = ListComponent.$el.querySelector('button');
To simulate a click, we need to pass the button a new event object to dispatch. In the testing environment, the List component won’t be listening for any events and so we need to manually run the watcher.
// simulate click event
const clickEvent = new window.Event('click');
button.dispatchEvent(clickEvent);
ListComponent._watcher.run();
Finally, we need to check that the newItem gets displayed, which we already know how to do from the first test! We might also want to check that the newItem
gets stored in the list array.
//assert list contains new item
expect(ListComponent.$el.textContent).to.contain('brush my teeth');
expect(ListComponent.listItems).to.contain('brush my teeth');
Here is the test file in full:
import List from '@/components/List';
import Vue from 'vue';
describe('List.vue', () => {
it('displays items from the list', () => {
const Constructor = Vue.extend(List);
const ListComponent = new Constructor().$mount();
expect(ListComponent.$el.textContent).to.contain('play games');
})
it('adds a new item to list on click', () => {
// build component
const Constructor = Vue.extend(List);
const ListComponent = new Constructor().$mount();
// set input value
ListComponent.newItem = 'brush my teeth';
// simulate click event
const button = ListComponent.$el.querySelector('button');
const clickEvent = new window.Event('click');
button.dispatchEvent(clickEvent);
ListComponent._watcher.run();
// assert list contains new item
expect(ListComponent.$el.textContent).to.contain('brush my teeth');
expect(ListComponent.listItems).to.contain('brush my teeth');
})
})
Now we can run our tests again, and they should show green!
Hopefully, this code will be clear to you now, but it is not particularly readable, especially for someone making VueJS tests for the first time. There is a VueJS utility library that tucks away some of the more complicated-looking code. To use it, we can go to our project root and run the following:
- npm install avoriaz
This test works exactly the same way as the one before except now we can hide the setup of the Vue component behind mount()
and, for clicking the button, all we need is two lines of code: find()
the button and dispatch()
the click event.
import { mount } from 'avoriaz';
import List from '@/components/List';
import Vue from 'vue';
describe('List.vue', () => {
// previous tests ..
it('adds new item to list on click with avoriaz', () => {
// build component
const ListComponent = mount(List);
// set input value
ListComponent.setData({
newItem: 'brush my teeth',
});
// simulate click event
const button = ListComponent.find('button')[0];
button.dispatch('click');
// assert list contains new item
expect(ListComponent.text()).to.contain('brush my teeth');
expect(ListComponent.data().listItems).to.contain('brush my teeth');
})
})
I personally find writing tests so essential to my normal workflow and yet with JavaScript, and VueJS in particular, I had some trouble getting started. Hopefully, this tutorial will help out anyone in the same position as me!
Here is my GitHub repo with the code from this tutorial.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!