Independent consultant
Web / Mobile / VR / AR / IoT
GDE, author, engineer
import sum from './sum'
test('returns sum of input', () => {
})
import sum from './sum'
test('returns sum of input', () => {
expect(sum(1,3)).toBe(4)
})
vue add unit-jest
npm run test:unit
Component
Output
Input
user action, props, store
assert
rendered output, vue events, function calls
<template>
<div></div>
</template>
<script>
export default {
props: ['visible']
}
</script>
module.exports = {
render: function () {
var _vm=this;
var _h=_vm.$createElement;
var _c=_vm._self._c||_h;
return _c('div')
}
staticRenderFns: [],
props: ['visible']
}
mount(Component, {
propsData: {
prop: 'some value'
},
mocks: {
$store: { state: { count: 1 } }
}
})
Mount will mount component and it's children as well.
https://vue-test-utils.vuejs.org/api/options.html
shallowMount(Component, {
propsData: {
prop: 'some value'
},
mocks: {
$store: { state: { count: 1 } }
}
})
to mount only shallow use shallowMount
Find elements and assert their existance
wrapper.find('a').text()
wrapper.findAll('a').at(0).text()
wrapper.find('[data-test="text"]')
Find elements and assert their existance
test('renders when clicked', () => {
// Arrange
const wrapper = mount(TestComponent)
// Act
wrapper.trigger('click')
// Assert
expect(wrapper.text()).toBe()
})
Test callbacks by mocking them
test('calls onClose when button is clicked', () => {
const callbackFn = jest.fn()
const wrapper = mount(Component, {
propsData: {
callbackFn
}
})
wrapper.find('button').trigger('click')
expect(callbackFn).toHaveBeenCalled()
})
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'Vladimir Default footer'
const wrapper = mount(HelloWorld, {
propsData: { msg }
})
expect(wrapper).toMatchSnapshot()
})
})
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`HelloWorld.vue renders props.msg when passed 1`] = `
<div class="hello" msg="Vladimir Default footer">
<header>Vladimir</header>
<section></section>
<footer>Default footer</footer>
</div>
`;
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'Vladimir Default footer'
const wrapper = mount(HelloWorld, {
propsData: { msg },
slots: {
default: '<p>some content</p>',
header: '<h1>Header</h1>',
footer: '<h2>Footer</h2>'
},
})
expect(wrapper).toMatchSnapshot()
})
})
it('updates text', async () => {
const wrapper = mount(Component)
wrapper.trigger('click')
await Vue.nextTick()
expect(wrapper.text()).toContain('updated')
})
Make sure to use nextTick before asserting updates of reactive properties
wrapper.vm.$emit('update')
wrapper.vm.$emit('updateTodo', "test todo")
Now you can test that event was emitted
expect(wrapper.emitted().updateTodo).toBeTruthy()
const wrapper = mount(TodoList)
wrapper.find(TodoItem).vm.$emit('remove-todo')
The first approach - unit test getters, mutations, and actions
import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import Getters from '../../../src/components/Getters'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('Getters.vue', () => {
let getters
let store
beforeEach(() => {
getters = {
clicks: () => 2,
inputValue: () => 'input'
}
store = new Vuex.Store({
getters
})
})
it('Renders "store.getters.inputValue" in first p tag', () => {
const wrapper = shallowMount(Getters, { store, localVue })
const p = wrapper.find('p')
expect(p.text()).toBe(getters.inputValue())
})
it('Renders "store.getters.clicks" in second p tag', () => {
const wrapper = shallowMount(Getters, { store, localVue })
const p = wrapper.findAll('p').at(1)
expect(p.text()).toBe(getters.clicks().toString())
})
})
Second approach - creating a local store
import { createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import storeConfig from './store-config'
import { cloneDeep } from 'lodash'
test('increments "count" value when "increment" is commited', () => {
const localVue = createLocalVue()
localVue.use(Vuex)
const store = new Vuex.Store(cloneDeep(storeConfig))
expect(store.state.count).toBe(0)
store.commit('increment')
expect(store.state.count).toBe(1)
})
import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
const localVue = createLocalVue()
localVue.use(VueRouter)
const router = new VueRouter()
shallowMount(Component, {
localVue,
router
})
import { shallowMount } from '@vue/test-utils'
const $route = {
path: '/some/path'
}
const wrapper = shallowMount(Component, {
mocks: {
$route
}
})
wrapper.vm.$route.path // /some/path
import { mount, RouterLinkStub } from '@vue/test-utils'
const wrapper = mount(Component, {
stubs: {
RouterLink: RouterLinkStub
}
})
expect(wrapper.find(RouterLinkStub).props().to).toBe('/some/path')
npx -p @storybook/cli sb init --type vue
yarn storybook
stories/HelloWorld.stories.js
yarn add @storybook/addon-storyshots --dev
import initStoryshots from '@storybook/addon-storyshots';
initStoryshots();
@VladimirNovick