2
votes

Before using vuex modules , my mutation tests were OK :

import mutations from '@/vuex/mutations.js'
import vueAuthInstance from '@/services/auth.js'
import { IS_AUTHENTICATED, CURRENT_USER_ID } from '@/vuex/mutation_types.js'

describe('mutations.js', () => {
  var state
  beforeEach(() => {
    state = {
      isAuthenticated: vueAuthInstance.isAuthenticated(),
      currentUserId: ''
    }
  })

  describe('IS_AUTHENTICATED', () => {
    it('should set authentication status', () => {
      state.isAuthenticated = false
      mutations[IS_AUTHENTICATED](state, {isAuthenticated: true})
      expect(state.isAuthenticated).to.eql(true)
    })
  })
  ...

})

Now I refactored my vuex folders, my state and mutations are inside each vuex/modules/../index.js file

      src
       |_  vuex
       |    L_ modules
       |           L_ login
       |               |_ index.js
       |               |_ actions.js
       |               |_ getters.js
       |               |_ mutation_types.js
       |_ App.vue
       |_ main.js

vuex/modules/login/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import getters from './getters'
import * as types from './mutation_types'
import vueAuthInstance from '@/services/auth.js'
Vue.use(Vuex)

const state = {
  isAuthenticated: vueAuthInstance.isAuthenticated(),
  currentUserId: ''
}

const mutations = {
  [types.IS_AUTHENTICATED]  (state, payload) {
    state.isAuthenticated = payload.isAuthenticated
  },
  ...
}

export default {
  state,
  mutations,
  actions,
  getters
}

Withe a vuex/store.js

import Vue from 'vue'
import Vuex from 'vuex'
import login from '@/vuex/modules/login'
// import other modules

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    login,
    ... (other modules )
  }
})

To take in account this new structure, I rewrote the unit test as following :

test/unit/specs/vuex/modules/login/index.spec.js

import { mutations } from '@/vuex/modules/login/index.js'
import vueAuthInstance from '@/services/auth.js'
import types from '@/vuex/modules/login/mutation_types.js'

describe('mutations.js', () => {
  var state
  beforeEach(() => {
    state = {
      isAuthenticated: vueAuthInstance.isAuthenticated(),
      currentUserId: ''
    }
  })

  describe('IS_AUTHENTICATED', () => {
    it('should set authentication status', () => {
      state.isAuthenticated = false
      mutations[types.IS_AUTHENTICATED](state, {isAuthenticated: true})
      expect(state.isAuthenticated).to.eql(true)
    })
  })

})

And I get an error, on the mutation :

 ✗ should set authentication status
    TypeError: Cannot read property 'IS_AUTHENTICATED' of undefined

I tried to change the import { mutations } statement , and import directly the store.js, in which the modules are defined, and use store._mutations,

LOG: 'MUTATIONS: ', Object{IS_AUTHENTICATED: [function wrappedMutationHandler(payload) { ... }], ...}

using store._mutations.IS_AUTHENTICATED0 , seems to work, ( don't know why an array? ..) but something is wrong with this function and the state, payload args, as the test doesn't pass

import store from '@/vuex/store'
import vueAuthInstance from '@/services/auth.js'

describe('mutations.js', () => {
  var state
  beforeEach(() => {
    state = {
      isAuthenticated: vueAuthInstance.isAuthenticated(),
      currentUserId: ''
    }
  })

  describe('IS_AUTHENTICATED', () => {
    it('should set authentication status', () => {
      state.isAuthenticated = false
      console.log('MUTATIONS: ', store._mutations.IS_AUTHENTICATED())
      store._mutations.IS_AUTHENTICATED[0](state, {isAuthenticated: true})
      expect(state.isAuthenticated).to.eql(true)
    })
  })
  ...
})


1) should set authentication status
     mutations.js IS_AUTHENTICATED
     AssertionError: expected false to deeply equal true

I checked the passed args to the mutation in the index.js file

const mutations = {
  [types.IS_AUTHENTICATED]  (state, payload) {
    console.log('MUTATION state: ', state)
    console.log('MUTATION payload: ', payload)
    state.isAuthenticated = payload.isAuthenticated
  },
  [types.CURRENT_USER_ID]  (state, payload) {
    state.currentUserId = payload.currentUserId
  }
}

And. I do not see the passed arg values, it seems that the state args is the only passed value from my test :

LOG: 'MUTATION state: ', Object{isAuthenticated: false, currentUserId: ''}
LOG: 'MUTATION payload: ', Object{isAuthenticated: false, currentUserId: ''}

What's wrong with this code ? how to proceed for testing the mutations in this case, using vuex modules ?

thanks for feedback

2

2 Answers

3
votes

Actually, this is bad approach. You should create mock state, and use it.

import { createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';    
import { storeModule } from '@path/to/store/modules';
const mutations = storeModule.mutations;


describe('mutations', () => {
  it('testCase#1', () => {
    createLocalVue().use(Vuex);
    const state = {
    //mock state values
    };

    const store = new Vuex.Store({state, mutations});

    store.commit('mutationToTest', arg);

    expect(state.arg).toBe(1);
  })
})
2
votes

I found a way to test the mutation using vuex modules, but I don't know if it's the best way...

my test is quite simple , using store.commit as I cannot call directly the mutation handler, and I import only the vuex/store

src/test/unit/specs/modules/login/index.js

import store from '@/vuex/store'

describe('mutations.js', () => {
  describe('IS_AUTHENTICATED', () => {
    it('should set authentication status', () => {
      store.commit('IS_AUTHENTICATED', {isAuthenticated: true})
      expect(store.state.login.isAuthenticated).to.eql(true)
    })
  })
  ...
})