Jest is a popular JavaScript testing framework that comes packed with a lot of goodies for developers. If you’re completely unfamiliar with how Jest works in general, I recommend you start with this introduction. Once you understand the basics of Jest, you’re ready to jump right in and see how it can be used to test your Vue apps.
If you don’t have the Vue CLI installed on your machine already, start by running either:
- npm install -g @vue/cli
or, if you prefer Yarn:
- yarn global add @vue/cli
Now you will be able to run the vue
command from the command line. Let’s create a Vue app called alligator-test
.
- vue create alligator-test
Choose the default preset at the prompt (hit the enter key). After that, run the following command to add our testing dependencies (@vue/cli-plugin-unit-jest
and @vue/test-utils
):
- npm install @vue/cli-plugin-unit-jest @vue/test-utils
Next, modify your project’s package.json file to have an entry in scripts
which says "test": "jest"
.
Then, create a file jest.config.js
with the following content:
module.exports = {
preset: '@vue/cli-plugin-unit-jest'
}
Now, open the alligator-test
directory in your code editor of choice.
Let’s make some changes to the default files that the vue-cli
creates for us.
Delete the src/components
directory and modify App.vue
as such:
<template>
<div id="app">
<div>
<h3>Let us test your arithmetic.</h3>
<p>What is the sum of the two numbers?</p>
<div class="inline">
<p>{{ x1 }} + {{ x2 }} =</p> <input v-model="guess"> <button v-on:click="check">Check Answer</button>
</div>
<button v-on:click="refresh">Refresh</button>
<p>{{message}}</p>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
x1: Math.ceil(Math.random() * 100),
x2: Math.ceil(Math.random() * 100),
guess: "",
message: ""
}
},
methods: {
check() {
if (this.x1 + this.x2 === parseInt(this.guess)) {
this.message = "SUCCESS!"
} else {
this.message = "TRY AGAIN"
}
},
refresh() {
this.x1 = Math.ceil(Math.random() * 100);
this.x2 = Math.ceil(Math.random() * 100);
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.inline * {
display: inline-block;
}
img {
height: 350px;
}
</style>
Take a look through the code and see if you can figure out what the app does.
Then go ahead and run npm run serve
from the root directory of your project.
Now you head over to localhost:8080
in your browser and see the working app.
Try making a few guesses! Hopefully, you can pass the test before we get to writing our tests.
Create a folder called __tests__
in the root directory of your project, which is standard jest
convention.
Inside __tests__
, create a file called app.spec.js
. By default jest
will catch any test files (searching recursively through folders) in your project that are named *.spec.js
or *.test.js
.
At the top of app.spec.js
we’re going to import the following from @vue/test-utils
as well as our App
component itself:
import { mount } from '@vue/test-utils'
import App from './../src/App.vue'
Let’s write our first test.
describe('App', () => {
// Inspect the raw component options
it('has data', () => {
expect(typeof App.data).toBe('function')
})
})
Run npm test
in your Terminal – the test should pass! This is a pretty basic test which checks if the data
for our component is a function. The way we wrote it back in the coding phase of this tutorial, we indeed defined it as a function.
Let’s add another describe
block to our test file.
describe('Mounted App', () => {
const wrapper = mount(App);
test('does a wrapper exist', () => {
expect(wrapper.exists()).toBe(true)
})
})
This time we are mounting the component, which gives us back a wrapper
. A wrapper is a mock Vue instance.
Warning: Since publication isVueInstance
has been deprecated. The test for “is a Vue instance” has been rewritten to “does a wrapper exist”.
We can use it to validate whether certain values are present using Jest’s expect
function. We can write tests like this:
it('renders the correct markup', () => {
expect(wrapper.html()).toContain('What is the sum of the two numbers?')
})
And this:
// it's also easy to check for the existence of elements
it('has a button', () => {
expect(wrapper.find('button').exists()).toBe(true)
})
Warning: Since publication contains
has been deprecated. wrapper.contains()
has been replaced with wrapper.find()
.
These tests all pass! Let’s write some tests for the app’s more Vue-specific functionality.
it('renders correctly with different data', async () => {
wrapper.setData({ x1: 5, x2: 10 })
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('10')
})
setData
allows you to set the component’s data. Since those variables were initialized in data
, they are reactive. When we are mocking our component however, we must call $nextTick()
on wrapper.vm
, which is the component underlying the wrapper. Then, we can find that our reactive properties are updated.
Finally, we’re going to test whether our app gives the correct output according to what we intend it to do – test addition!
it('button click without correct sum', () => {
expect(wrapper.vm.message).toBe("")
const button = wrapper.find('button')
button.trigger('click')
expect(wrapper.vm.message).toBe('TRY AGAIN')
})
wrapper.find
returns a wrapper for the button element (though there are 2 buttons on our page, the one that we want is the first button on the page so it gets grabbed). x1
and x2
are set from our previous test. But guess
, the variable that is connected to the input element via v-model
, is not. So, when the button for submission is clicked, the correct sum has not been entered. Hence we expect the message
to be TRY AGAIN
. When you run npm test
the test should pass.
it('button click with correct sum', () => {
wrapper.setData({ guess: "15" })
const button = wrapper.find('button')
button.trigger('click')
expect(wrapper.vm.message).toBe('SUCCESS!')
})
On the other hand, when we set the sum to be correct, wrapper.vm.message
will say ‘SUCCESS!’
I hope this tutorial was useful to you in seeing how to get started with testing Vue.js with Jest! Good luck out there. Test your app!
From this point, if you’re interested in diving deeper into what Jest can do, I’d recommend reading up on Snapshot testing.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
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!
I’m new to Jest and trying to get it working with Vue was proving to be a nightmare. This tutorial is the first one I’ve found that actually works with Jest and ES6+ modules. Very much appreciated.
So awesome you updated this to accomodate
isVueIntance()
deprecation REALLY FAST!Thank you for this tutorial.