title: Vuex: Testing actions with API calls
body: <p>I have been following <a href="https://vuex.vuejs.org/en/testing.html" rel="nofollow noreferrer">these</a> testing guidelines to test my vuex store.
  But when I touched upon the actions part, I felt there is a lot going on that I couldn't understand.</p>
  
  <p>The first part goes like:</p>
  
  <pre><code>// actions.js
  import shop from '../api/shop'
  
  export const getAllProducts = ({ commit }) =&gt; {
    commit('REQUEST_PRODUCTS')
    shop.getProducts(products =&gt; {
      commit('RECEIVE_PRODUCTS', products)
    })
  }
  // actions.spec.js
  
  // use require syntax for inline loaders.
  // with inject-loader, this returns a module factory
  // that allows us to inject mocked dependencies.
  import { expect } from 'chai'
  const actionsInjector = require('inject!./actions')
  
  // create the module with our mocks
  const actions = actionsInjector({
    '../api/shop': {
      getProducts (cb) {
        setTimeout(() =&gt; {
          cb([ /* mocked response */ ])
        }, 100)
      }
    }
  })
  </code></pre>
  
  <p>I infer that this is to mock the service inside the action. </p>
  
  <p>The part which follows is:</p>
  
  <pre><code>// helper for testing action with expected mutations
  const testAction = (action, payload, state, expectedMutations, done) =&gt; {
    let count = 0
  
    // mock commit
    const commit = (type, payload) =&gt; {
      const mutation = expectedMutations[count]
      expect(mutation.type).to.equal(type)
      if (payload) {
        expect(mutation.payload).to.deep.equal(payload)
      }
      count++
      if (count &gt;= expectedMutations.length) {
        done()
      }
    }
  
    // call the action with mocked store and arguments
    action({ commit, state }, payload)
  
    // check if no mutations should have been dispatched
    if (expectedMutations.length === 0) {
      expect(count).to.equal(0)
      done()
    }
  }
  
  describe('actions', () =&gt; {
    it('getAllProducts', done =&gt; {
      testAction(actions.getAllProducts, null, {}, [
        { type: 'REQUEST_PRODUCTS' },
        { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }
      ], done)
    })
  })
  </code></pre>
  
  <p>This is where it I find it difficult to follow.</p>
  
  <p>My store looks like:</p>
  
  <pre><code>import * as NameSpace from '../NameSpace'
  import { ParseService } from '../../Services/parse'
  
  const state = {
    [NameSpace.AUTH_STATE]: {
      auth: {},
      error: null
    }
  }
  
  const getters = {
    [NameSpace.AUTH_GETTER]: state =&gt; {
      return state[NameSpace.AUTH_STATE]
    }
  }
  
  const mutations = {
    [NameSpace.AUTH_MUTATION]: (state, payload) =&gt; {
      state[NameSpace.AUTH_STATE] = payload
    }
  }
  
  const actions = {
    [NameSpace.ASYNC_AUTH_ACTION]: ({ commit }, payload) =&gt; {
      ParseService.login(payload.username, payload.password)
        .then((user) =&gt; {
          commit(NameSpace.AUTH_MUTATION, {auth: user, error: null})
        })
        .catch((error) =&gt; {
          commit(NameSpace.AUTH_MUTATION, {auth: [], error: error})
        })
    }
  }
  
  export default {
    state,
    getters,
    mutations,
    actions
  }
  </code></pre>
  
  <p>And This is how I am trying to test:</p>
  
  <pre><code>import * as NameSpace from 'src/store/NameSpace'
  import AuthStore from 'src/store/modules/authorization'
  const actionsInjector = require('inject!../../../../../src/store/modules/authorization')
  // This file is present at: test/unit/specs/store/modules/authorization.spec.js 
  // src and test are siblings
  
  
  describe('AuthStore Actions', () =&gt; {
    const injectedAction = actionsInjector({
      '../../Services/parse': {
        login (username, password) {
          return new Promise((resolve, reject) =&gt; {
            setTimeout(() =&gt; {
              if (Math.random() &gt; 0.5) {
                resolve({})
              } else {
                reject({})
              }
            }, 300)
          })
        }
      }
    })
  
    it('Gets the user profile if the username and password matches', () =&gt; {
      const testAction = (action, payload, state, mutations, done) =&gt; {
        const commit = (payload) =&gt; {
          if (payload) {
            expect(mutations.payload).to.deep.equal(payload)
          }
        }
        action({ commit, state }, payload)
          .then(result =&gt; {
            expect(state).to.deep.equal({auth: result, error: null})
          })
          .catch(error =&gt; {
            expect(state).to.deep.equal({auth: [], error: error})
          })
      }
      testAction(injectedAction.login, null, {}, [])
    })
  })
  </code></pre>
  
  <p>If I try to do this, I get:</p>
  
  <pre><code>"Gets the user profile if the username and password matches"
  undefined is not a constructor (evaluating 'action({ commit: commit, state: state }, payload)')
  "testAction@webpack:///test/unit/specs/store/modules/authorization.spec.js:96:13 &lt;- index.js:26198:14
  webpack:///test/unit/specs/store/modules/authorization.spec.js:104:15 &lt;- index.js:26204:16"
  </code></pre>
  
  <p>I need help understanding what am I supposed to do to test such actions.</p>