Tutorial

How to Test Your Vue Components Using the Jest Testing Framework

Vue.js

While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

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.

Setup and Installing Dependencies

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:

jest.config.js
module.exports = {
  preset: '@vue/cli-plugin-unit-jest'
}

Go ahead and open up the alligator-test directory in your code editor of choice.

Coding Up a Simple App

Let’s make some changes to the default files that the vue-cli create for us.

Delete the src/components directory and modify App.vue as such:

App.vue
<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. 😉

Testing the App with Jest

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('is a Vue instance', () => {
    expect(wrapper.isVueInstance()).toBeTruthy()
  })
}

This time we are mounting the component, which gives us back a wrapper.

A wrapper is a mock Vue instance.

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.contains('button')).toBe(true)
})

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!’

Conclusion

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.

0 Comments

Creative Commons License