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 

Made with Slides.com