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
Here what features i selected:
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
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
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
src/
├─ components/
├─ __tests__/
│ │ └─ navbar.test.js
│ └─ navbar.js
Tests/specs syntax
Let's try to next command:
npm run test:unit
As you can see below, it's showing the result of your test.
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)
})
})
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'
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'
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', () => {
})
Without ES6:
describe('HelloWorld.vue', function() {
})
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)
})
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)
})
})
Launch the test
The test will fail, the import doesn't exist so you will get this error.
Create the component
The last error told us the problem, we have to create the component!
touch src/components/Navbar.vue
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>
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>
Launch the test
npm run test:unit
It works ! Some other kind of test will be added in another post ;)
Top comments (0)