DEV Community

Vorachith Phoubandith
Vorachith Phoubandith

Posted on

Vue 3 with Jest and Vue Tests Utils: Introduction

Never took the time to create a vue project with unit test?
Before to begin, we will see what are the advantages to use unit test.

  • It will increase your confidence ! Indeed, Tests also called Specs allow you to add new feature without breaking the existing code.
  • It will be use by any developers concerned by the project, you can consider Specs like a documentation of the application.
  • The quality of code you will produce only can improve

Let's start, we will begin with creating the project, it will take about 2 minutes.

vue create vue-3-test-unit && cd vue-3-test-unit
Enter fullscreen mode Exit fullscreen mode

Here what features i selected:
Capture d’écran 2021-08-20 à 11.25.07

Select a pattern for your Tests

You will find lot of pattern to organize your tests.

The pattern I recommend

I personally use the next pattern. The advantage is that all tests will be in the tests/unit folder.

tests/
├─ unit/
│  ├─ assets
│  ├─ components
│  ├─ js
│  ├─ router
│  ├─ store
│  ├─ views
│  ├─ App.test.js
Enter fullscreen mode Exit fullscreen mode

To get this pattern, just reproduce it in your terminal:

mkdir tests/unit/assets
mkdir tests/unit/components
mkdir tests/unit/router
mkdir tests/unit/store
mkdir tests/unit/views
mv tests/unit/example.spec.js tests/unit/App.spec.js
Enter fullscreen mode Exit fullscreen mode

Others kind of pattern

If you are interested, you will find below some others kind of pattern:

src/
├─ components/
│  ├─ navbar.js
│  ├─ navbar.style.js
│  └─ navbar.test.js
Enter fullscreen mode Exit fullscreen mode
src/
├─ components/
├─ __tests__/
│  │  └─ navbar.test.js
│  └─ navbar.js
Enter fullscreen mode Exit fullscreen mode

Tests/specs syntax

Let's try to next command:

npm run test:unit
Enter fullscreen mode Exit fullscreen mode

As you can see below, it's showing the result of your test.
Capture d’écran 2021-08-20 à 14.53.31
Explanations:

  • Test Suites is a kind of grouped test
  • Tests show the number of test
  • Snapshots is used to be sure an entire component runs like you want, it also used as an integration test You can see "PASS" in green. If a test fail, you will get "FAIL" in red.

Understand how a test works

Let's open the App.spec.js file so we can understand how it works. We got the below code that i will explain.

import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

describe('HelloWorld.vue', () => {
  it('renders props.msg when passed', () => {
    const msg = 'new message'
    const wrapper = shallowMount(HelloWorld, {
      props: { msg }
    })
    expect(wrapper.text()).toMatch(msg)
  })
})
Enter fullscreen mode Exit fullscreen mode

Why must we do imports?

Because an vue application have to be mounted into a DOM element, you will need to mount some vue.file to make tests.
For example, if we want to perform a test on the HelloWorld.vue page, we have to import. Two solutions to do this:

mount

import { mount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
Enter fullscreen mode Exit fullscreen mode

shallowMount

Like mount, it creates a Wrapper that contains the mounted and rendered Vue component, but it is possible to use it with stubbed child components.

import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
Enter fullscreen mode Exit fullscreen mode

Syntax of a test explained

To write a test, you only need to know how to do :

  • a test suite : use 'describe' to do it
  • a test : use 'test' or 'it'
  • a goal for your test : 'expect' allow you to define what are the expectation of the test

Describe

The description must be clear, we use the name of the component or the function name tested.
If you want to use ES6

describe('HelloWorld.vue', () => {

})
Enter fullscreen mode Exit fullscreen mode

Without ES6:

describe('HelloWorld.vue', function()  {

})
Enter fullscreen mode Exit fullscreen mode

Test with expect

After putting the description of this test, we prepare variable that will be used in the expect.

  it('renders props.msg when passed', () => {
    const msg = 'new message'
    const wrapper = shallowMount(HelloWorld, {
      props: { msg }
    })
    expect(wrapper.text()).toMatch(msg)
  })
Enter fullscreen mode Exit fullscreen mode

This test means that the DOM of the HelloWorld.vue page must have a text containing 'new message' by the props 'msg'.

Write our first test

At this point, you can manage your project in several ways.

  • Code first, test after : You can code the component first and add the test.
  • Test first, code after : You can add the test first, so you can begin the code with a clear idea of what you will do. To go further, check for the TDD (test driven development). I will use this approach.

Begin with the test

First, we must think about the feature we want to implement. In this case, why not to begin with adding a navbar to the App? The process will be :

  • create the test of navbar component's
  • create the navbar component's
  • add it in App.vue
Write the test

The test will be simple, we will erase the content of App.spec.js and add a test that will check if the navbar component's exist in App.vue

import { shallowMount } from '@vue/test-utils'
import Navbar from '../../src/components/Navbar.vue'
import App from '../../src/App.vue'
import router from '../../src/router/index.js'

describe('App.vue', () => {
  it('Navbar component\'s exist', async () => {
    router.push('/')
    await router.isReady()
    const wrapper = shallowMount(App, {
      global: {
        plugins: [router]
      }
    })
    expect(wrapper.findComponent(Navbar).exists()).toBe(true)
  })
})

Enter fullscreen mode Exit fullscreen mode
Launch the test

The test will fail, the import doesn't exist so you will get this error.
Capture d’écran 2021-08-20 à 19.08.17

Create the component

The last error told us the problem, we have to create the component!

touch src/components/Navbar.vue
Enter fullscreen mode Exit fullscreen mode

Just add the below code if you don't want to make a Navbar by yourself.

<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div>
</template>

<script>
export default {
  name: 'Navbar',
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

Enter fullscreen mode Exit fullscreen mode
Add the component to App.vue

We return in the App.vue page to add the Navbar. If you don't want to add the import part here, you can add it in your main.js

<template>
  <navbar />
  <router-view />
</template>

<script>
import Navbar from '@/components/Navbar.vue'

export default {
  name: 'App',
  components: {
    Navbar
  },
}
</script>
Enter fullscreen mode Exit fullscreen mode
Launch the test
npm run test:unit            
Enter fullscreen mode Exit fullscreen mode

Capture d’écran 2021-08-20 à 23.58.55
It works ! Some other kind of test will be added in another post ;)

Oldest comments (0)