title: Testing non-promises after promise completes with Mocha, Chai and Sinon
body: <p>I've created a small learning project in Redux, and have essentially copied the middleware for asynchronous actions from the <a href="http://redux.js.org/docs/recipes/ReducingBoilerplate.html#async-action-creators" rel="nofollow noreferrer">documentation</a>. Now I want to write some tests for it, to make sure that it will work fine after I change around some things.</p>
  <p>To write my tests, I'm using Mocha, with chai, chai-as-promised and sinon.</p>
  <p>I have no problems with redux in any way, but I'm unsure of how to test things.</p>
  <p>The relevant code from the middleware:</p>
  <pre><code>export default function callApiMiddleware({ dispatch }) {
    return next =&gt; action =&gt; {
      // ... various checks
  
      const [ requestType, successType, errorType ] = types;
      dispatch({ ...payload, type: requestType });
  
      return callApi().then(
        response =&gt; dispatch({ ...payload, type: successType, response }),
        error =&gt; dispatch({ ...payload, type: errorType, error })
      );
    }
  }
  </code></pre>
  <p>The middleware dispatches the appropriate action whether the promise is fulfilled or rejected.</p>
  <p>To test this, I'm stubbing out the dispatch function, along with others, and I also pass in a dummy promise, that I fulfill or reject depending on what I want to test.</p>
  <p>A test I have written looks like this:</p>
  <pre><code>it('should trigger success action when successful', () =&gt; {
    let promise = callApiMiddleware({ dispatch, getState })(next)({
      ...action,
      callApi: () =&gt; new Promise((resolve, reject) =&gt; resolve('SUCCESS'))
    });
    return expect(promise).to.eventually.be.fulfilled;
  });
  </code></pre>
  <p>This works fine, but the first problem I ran into was when I tried to simulate a rejected promise that could result from no internet connection, so I wrote this test:</p>
  <pre><code>it('should trigger failure action when failure occurs', () =&gt; {
    let promise = callApiMiddleware({ dispatch, getState })(next)({
      ...action,
      callApi: () =&gt; new Promise((resolve, reject) =&gt; reject('ERROR'))
    });
    return expect(promise).to.eventually.be.rejected;
  });
  </code></pre>
  <p>But this fails with the following message:</p>
  <blockquote>
  <p>AssertionError: expected promise to be rejected but it was fulfilled with undefined</p>
  <p>Expected :[undefined]</p>
  <p>Actual   :[undefined]</p>
  </blockquote>
  <p>This makes no sense to me, since I clearly pass in a promise that's only function is to be rejected.</p>
  <p>My other problem is that I also want to make other assertions, that don't necessarly have anything to do with the promise itself, but have to be evaluated when the promise finishes e.g. I want to assert that the <code>dispatch</code> method was called twice. The <code>dispatch</code> method itself is stubbed out in the test using sinon in order to perform the desired assertions. Potentially, I want to make multiple assertions in this way.</p>
  <p>I have tried the following:</p>
  <pre><code>it('should trigger success action when successful', () =&gt; {
    let promise = callApiMiddleware({ dispatch, getState })(next)({
      ...action,
      callApi: () =&gt; new Promise((resolve, reject) =&gt; resolve('SUCCESS'))
    });
    return Q.all([
      expect(promise).to.eventually.be.fulfilled,
      expect(dispatch).to.eventually.be.calledTwice
    ]);
  });
  </code></pre>
  <p>But this returns some very large error that simply tells me that <code>dispatch</code> is not <code>thenable</code> i.e. not a promise.</p>
  <p>I am out of ideas on how to do this, so any input would greatly be appreciated.</p>