title: Testing VueJS method inside of a promise which is returned from a vuex action
body: <p>I have a Vue component, which is using a mapped action from a vuex store, which returns a promise. When the component calls the mapped action, and the mapped action is resolved, I am calling another vue method <code>vm.$router.push()</code>. I want to assert that the <code>push</code> method gets called. Here is my component, test, and some helper methods I created to sub out the component with vuex and vue-router. </p>
  
  <p><strong>Here is my <code>.vue</code> component with some console.logs to track what's going on.</strong> </p>
  
  <pre class="lang-javascript prettyprint-override"><code>&lt;template&gt;
    &lt;div&gt;
      &lt;button @click="promise" class="click-promise"&gt;Promise&lt;/button&gt;
    &lt;/div&gt;
  &lt;/template&gt;
  
  &lt;script&gt;
    import { mapActions } from 'vuex'
  
    export default {
    methods: {
      ...mapActions(['promiseAction']),
      promise(){
        const vm = this
        vm.$router.push('/some/route')
        console.log('before promiseAction')
        console.log(vm.promiseAction())
        return vm.promiseAction().then(function (response) {
          console.log('inside promiseAction')
          vm.$router.push('/some/other/route')
        })
      }
    }
  }
  &lt;/script&gt;
  </code></pre>
  
  
  
  <p><strong>Here is my test. I'm using Mocha, Karma, Chai, and jquery-chia</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import Testing from '@/components/Testing'
  
  describe('Testing.vue', () =&gt; {
    const mount = componentHelper(Testing)
  
    it.only('assert something in a promise returned from an action', () =&gt; {
      const promise = new Promise(resolve =&gt; resolve('success'))
      const promiseAction = stubAction('promiseAction').returns(promise)
      const vm = mount()
      const routerPush = sinon.spy(vm.$router, 'push')
  
      $('.click-promise').click()
      expect(promiseAction).to.have.been.called
      expect(routerPush).to.have.been.calledWith('/some/route') //this passes
  
      return vm.$nextTick(() =&gt; {
        console.log('inside nextTick')
        expect(routerPush).to.have.been.calledWith('/some/other/routes') //this never happens
      })
    })
  })
  </code></pre>
  
  
  
  <p><strong>And here is my helpers file. I'm not sure if this is 100% neccisary, but I wanted to include everything in this post</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import Vue from 'vue'
  import Vuex from 'vuex'
  import VueRouter from 'vue-router'
  Vue.use(Vuex)
  Vue.use(VueRouter)
  
  let div
  
  beforeEach(() =&gt; {
    // create a dom element for the component to mount to
    div = document.createElement('div')
    document.body.appendChild(div)
  })
  
  afterEach(() =&gt; {
    // clean up the document nodes after each test
    Array.prototype.forEach.call(document.querySelectorAll('body *:not([type="text/javascript"])'), node =&gt; {
      node.parentNode.removeChild(node)
    })
  })
  
  // stub out a store config object
  const storeConfig = {
    actions: {}
  }
  
  /**
   * Set up a function that will attach the mock store to the component
   * and mount the component to the test div element
   *
   * Use like this:
   * const mount = componentHelper(YourComponent)
   * do some setup
   * call mount() to instantiate the mocked component
   *
   * @param component
   * @returns {function()}
   */
  window.componentHelper = function (component) {
    const router = new VueRouter({})
      return () =&gt; {
      // 1. attaches the stubbed store to the component
      component.store = new Vuex.Store(storeConfig)
      component.router = router
      // 2. mounts the component to the dom element
      // 3. returns the vue instance
      return new Vue(component).$mount(div)
    }
  }
  
  /**
   * Creates an action to be added to the fake store
   * returns a sinon stub which can be asserted against
   * @param actionName
   */
  window.stubAction = (actionName) =&gt; {
    // 1. create a stub
    const stub = sinon.stub()
    // 2. create the action function that will be placed in the store and add it to the store
    storeConfig.actions[actionName] = function (context, ...args) {
      // 3. when this action is called it will call the stub
      // return the stub so you can assert against the stubbed return value
      // example: stubAction('fakeAction').returns('xyz')
      return stub(...args)
      }
    // 4. return the stub that was placed in the return of the action for assertions
    return stub
  }
  </code></pre>
  
  
  
  <p><strong>When I run this test this is what I get.</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>LOG LOG: 'before promiseAction'
  LOG LOG: Promise{_c: [], _a: undefined, _s: 1, _d: true, _v: 'success', _h: 0, _n: true}
  
    Testing.vue
      ✓ assert something in a promise returned from an action
  
  PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 4 SUCCESS (0.045 secs / 0.018 secs)
  TOTAL: 1 SUCCESS
  
  
  =============================== Coverage summary ===============================
  Statements   : 31.58% ( 6/19 )
  Branches     : 100% ( 0/0 )
  Functions    : 0% ( 0/2 )
  Lines        : 31.58% ( 6/19 )
  ================================================================================
  LOG LOG: 'inside nextTick'
  ERROR LOG: '[Vue warn]: Error in nextTick: "AssertionError: expected push to have been called with arguments /some/other/routes
  /some/route /some/other/routes "
  
  (found in &lt;Root&gt;)'
  ERROR LOG: AssertionError{message: 'expected push to have been called with arguments /some/other/routes
  /some/route /some/other/routes ', showDiff: false, actual: push, expected: undefined, stack: undefined, line: 210, sourceURL: 'http://localhost:9877/absolute/home/doug/Code/projects/vue-testing-sandbox/node_modules/chai/chai.js?ab7cf506d9d77c111c878b1e10b7f25348630760'}
  LOG LOG: 'inside promiseAction'
  </code></pre>
  
  
  
  <p>As you can see the test passes, but the code inside of the promise does not run until after the test is done. I'm talking about this section</p>
  
  <pre><code>return vm.promiseAction().then(function (response) {
      console.log('inside promiseAction')
      vm.$router.push('/some/other/route')
    })
  </code></pre>
  
  <p>I also logged out the promise function <code>console.log(vm.promiseAction())</code>  and you can see it is what you would expect.</p>
  
  <p>How can I get the test to wait for the promise? I thought <code>nextTick</code> might be the answer, but it doesn't seem to be working.</p>
  
  <p>Thanks for any help.</p>