Unit testing a Vuex store
GitHubレポジトリ—https://github.com/eddyerburgh/reddit-aww-example-app
Edd Yerburgh
@eddyerburgh
export const sum = (a, b) => a + b
Unit test
import sum from './sum'
test('returns sum of input', () => {
})
import sum from './sum'
test('returns sum of input', () => {
expect(sum(1,3)).toBe(4)
})
Why?
-
Check code works
-
Document code
-
Enable workflows
Components
Actions
State
Vuex
Actions
Mutations
State
Getters
Vuex store
A web app
Actions
Mutations
State
Getters
fetchItems
setItems
items
displayItems
Three approaches..
1. Don't
[Shocked in Spanish]
2. Test store parts seperately
Actions
Mutations
State
Getters
export default {
setItems (state, { items }) {
state.items = items
}
}
Mutation
export default {
// ..
setItems (state, { items }) {
state.items = items
},
// ..
}
import mutations from './mutations'
test('setItems mutates state.items', () => {
})
import mutations from './mutations'
test('setItems mutates state.items', () => {
const state = {
items: []
}
const items = [{}, {}]
mutations.setItems(state, { items })
expect(state.items).toBe(items)
})
import mutations from './mutations'
test('setItems mutates state.items', () => {
const state = {
items: []
}
})
import mutations from './mutations'
test('setItems mutates state.items', () => {
const state = {
items: []
}
const items = [{}, {}]
})
import mutations from './mutations'
test('setItems mutates state.items', () => {
const state = {
items: []
}
const items = [{}, {}]
mutations.setItems(state, { items })
})
displayItems ({ page, items }) {
const perPage = 20
const index = perPage * page
return items.slice(index - perPage, index)
},
Getter
displayItems ({ page, items }) {
const perPage = 20
const index = perPage * page
return items.slice(index - perPage, index)
},
test('returns items 21-40 if state.page value is 2', () => {
})
test('returns items 21-40 if state.page value is 2', () => {
const items = Array(42)
.fill()
.map((v, i) => i)
const state = {
items,
page: 2
}
})
test('returns items 21-40 if state.page value is 2', () => {
const items = Array(42)
.fill()
.map((v, i) => i)
const state = {
items,
page: 2
}
const result = getters.displayItems(state)
})
test('returns items 21-40 if state.page value is 2', () => {
const items = Array(42)
.fill()
.map((v, i) => i)
const state = {
items,
page: 2
}
const result = getters.displayItems(state)
expect(result).toHaveLength(20)
expect(result).toEqual(items.slice(20, 40))
})
import { fetchData } from '../api'
export default {
fetchItems ({ commit }) {
return fetchData()
.then(items => commit('setItems', { items }))
}
}
Action
import actions from './actions'
import { fetchData } from '../api'
jest.mock('../api')
test('commits items returned by api method', async () => {
})
import actions from './actions'
import { fetchData } from '../api'
jest.mock('../api')
test('commits items returned by api method', async () => {
const items = [1, 2, 3]
fetchData.mockResolvedValue(items)
const commit = jest.fn()
await actions.fetchItems({ commit })
expect(commit).toHaveBeenCalledWith(
'setItems', { items }
)
})
import actions from './actions'
import { fetchData } from '../api'
jest.mock('../api')
test('commits items returned by api method', async () => {
const items = [1, 2, 3]
fetchData.mockResolvedValue(items)
})
import actions from './actions'
import { fetchData } from '../api'
jest.mock('../api')
test('commits items returned by api method', async () => {
const items = [1, 2, 3]
fetchData.mockResolvedValue(items)
const commit = jest.fn()
})
import actions from './actions'
import { fetchData } from '../api'
jest.mock('../api')
test('commits items returned by api method', async () => {
const items = [1, 2, 3]
fetchData.mockResolvedValue(items)
const commit = jest.fn()
await actions.fetchItems({ commit })
})
Testing store parts seperately
- Fine-grained
- Brittle
3. Test a store instance
Actions
Mutations
State
Getters
store
fetchItems
state.items
1. Install Vuex
2. Create a store instance
3. Test instance
Steps
Step 1
Install Vuex
Vue.use(Vuex)
Vue
new Vue({})
new Vue({})
Vue.use
Vue
new Vue({})
new Vue({})
localVue.use
localVue
Step 1
Install Vuex
import { createLocalVue } from '@vue/test-utils'
const localVue = createLocalVue()
(on localVue constructor)
import { createLocalVue } from '@vue/test-utils'
const localVue = createLocalVue()
localVue.use(Vuex)
const store = new Vuex.Store({
state: {
items: []
},
actions,
mutations
})
const storeConfig = createStoreConfig()
const store = new Vuex.Store(storeConfig)
Step 2
Create instance
import mutations from './mutations'
import actions from './actions'
export default function createStoreConfig() {
const state = {
items: [],
}
return {
state,
actions,
mutations
}
}
Step 3
Test instance
await store.dispatch('fetchItems')
expect(store.state.items).toBe(items)
import Vuex from 'vuex'
import { createLocalVue } from '@vue/test-utils'
import { fetchItems } from '../api'
import createStoreConfig from './create-store-config'
const localVue = createLocalVue()
localVue.use(Vuex)
jest.mock('../api')
test('returns items', async () => {
})
import Vuex from 'vuex'
import { createLocalVue } from '@vue/test-utils'
import { fetchItems } from '../api'
import createStoreConfig from './create-store-config'
const localVue = createLocalVue()
localVue.use(Vuex)
jest.mock('../api')
test('returns items', async () => {
const items = [{},{},{}]
fetchItems.mockResolvedValue(items)
})
import Vuex from 'vuex'
import { createLocalVue } from '@vue/test-utils'
import { fetchItems } from '../api'
import createStoreConfig from './create-store-config'
const localVue = createLocalVue()
localVue.use(Vuex)
jest.mock('../api')
test('returns items', async () => {
const items = [{},{},{}]
fetchItems.mockResolvedValue(items)
const storeConfig = createStoreConfig()
const store = new Vuex.Store(storeConfig)
})
import Vuex from 'vuex'
import { createLocalVue } from '@vue/test-utils'
import { fetchItems } from '../api'
import createStoreConfig from './create-store-config'
const localVue = createLocalVue()
localVue.use(Vuex)
jest.mock('../api')
test('returns items', async () => {
const items = [{},{},{}]
fetchItems.mockResolvedValue(items)
const storeConfig = createStoreConfig()
const store = new Vuex.Store(storeConfig)
await store.dispatch('fetchItems')
})
import Vuex from 'vuex'
import { createLocalVue } from '@vue/test-utils'
import { fetchItems } from '../api'
import createStoreConfig from './create-store-config'
const localVue = createLocalVue()
localVue.use(Vuex)
jest.mock('../api')
test('returns items', async () => {
const items = [{},{},{}]
fetchItems.mockResolvedValue(items)
const storeConfig = createStoreConfig()
const store = new Vuex.Store(storeConfig)
await store.dispatch('fetchItems')
expect(store.state.items).toBe(items)
})
Integration test?
Testing store instance
- Less specific
- Not brittle
Which approach?
🤷♂️
Learn more with my book
Copy of Testing a Vuex store
By Masa Tanaka
Copy of Testing a Vuex store
What, why, and how of unit testing a Vuex store
- 657