Unit testing Vue components
Edd Yerburgh
twitter @eddyerburgh
github.com/eddyerburgh
Why write unit tests?
My first React job...
Fixing bugs!
Unit tests to the rescue
Unit test benefits
- Check components work correctly
- Provide documentation
- Easier debugging
- Less bugs
How?
// sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
// sum.spec.js
const sum = require('./sum');
test('returns the sum of its input', () => {
expect(sum(1, 3)).toBe(4);
});
A unit test
Passing tests
A failing test
Vue components
Vue single file component (SFCs)
<template>
<div>
<p>Counter: {{counter}}</p>
<button @click="counter++">Add 1</button>
</div>
</template>
<script>
export default {
name: 'counter',
data: () => ({
counter: 0
})
}
</script>
What to test?
Component contract
defines the expected behavior of your component and what assumptions are reasonable to make about its usage
Trigger an input
Expect an output
Input
- User action
- Props
Output
- Rendered output
- Vue events
- Function calls (Vuex dispatch)
⚠️
Avoid testing implementation detail
Counter spec
- increments counter when button is clicked
How?
Vue SFC
<template>
<div>
<p>Counter: {{counter}}</p>
<button @click="counter++">Add 1</button>
</div>
</template>
<script>
export default {
name: 'counter',
data: () => ({
counter: 0
})
}
</script>
compiled SFC
module.exports = {
render:function (){
var _vm=this;
var _h=_vm.$createElement;
var _c=_vm._self._c||_h;
return _c('div', [_c('p', [_vm._v("Counter: " + _vm._s(_vm.counter))]), _vm._v(" "), _c('button', {
on: {
"click": _vm.counter++
}
}, [_vm._v("Add 1")])])
},
staticRenderFns: [],
name: 'counter',
props: ['title'],
data: () => {
counter: 0
}
}
Compilation process
Compilers
- Webpack (vue-loader)
- Jest (vue-jest)
- Browserify (vueify)
github.com/eddyerburgh/vue-unit-test-perf-comparison
Test runner | 10 | 100 | 1000 | 5000 |
---|---|---|---|---|
tape | 2.32s | 3.49s | 9.28s | 38s |
jest | 2.44s | 4.50s | 21.84s | 91s |
mocha-webpack | 2.32s | 3.07s | 10.79s | 38s |
karma-mocha | 7.93s | 11.01s | 33.30s | 119s |
ava | 19.05s | 73.44s | 625.15s | 7161s |
Test runner comparison
Use Jest or mocha-webpack
https://vue-test-utils.vuejs.org/en/guides/testing-SFCs-with-jest.html
https://vue-test-utils.vuejs.org/en/guides/testing-SFCs-with-mocha-webpack.html
vue-test-utils
Vue testing library
mount
returns a running instance of component inside a wrapper
Needs to run in a browser environment
(JSDOM 👌)
import Counter from '@/components/Counter'
import { mount } from 'vue-test-utils'
describe('Counter.vue', () => {
it('increments counter on click', () => {
const wrapper = mount(Counter)
expect(wrapper.find('span').text()).toBe('0')
wrapper.find('button').trigger('click')
expect(wrapper.find('span').text()).toBe('1')
})
})
Testing a component
mount
shallow
shallow
import { shallow } from 'vue-test-utils'
import Counter from '~/components/Counter'
test('increments counter when button is clicked', () => {
const wrapper = shallow(Counter)
expect(wrapper.text()).toContain('0')
wrapper.find('button').trigger('click')
expect(wrapper.text()).toContain('1')
})
Using shallow
We've written some tests!
Testing Vue.js applications out now
manning.com/books/testing-vuejs-applications
Unit Testing Vue Components
By Edd Yerburgh
Unit Testing Vue Components
The how, why, and what of unit testing components
- 1,733