diff --git a/package.json b/package.json index b8a667c..6db1d6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redux-promise", - "version": "0.5.0", + "version": "0.6.0-alpha", "description": "FSA-compliant promise middleware for Redux.", "main": "lib/index.js", "scripts": { @@ -34,6 +34,7 @@ "sinon": "^1.15.4" }, "dependencies": { - "flux-standard-action": "0.6.0" + "flux-standard-action": "0.6.0", + "lodash": "^3.10.0" } } diff --git a/src/__tests__/promiseMiddleware-test.js b/src/__tests__/promiseMiddleware-test.js index c322aad..418fcbc 100644 --- a/src/__tests__/promiseMiddleware-test.js +++ b/src/__tests__/promiseMiddleware-test.js @@ -27,28 +27,46 @@ describe('promiseMiddleware', () => { }); it('handles Flux standard actions', async () => { + const meta = { 'do': 'wop' }; + await dispatch({ type: 'ACTION_TYPE', - payload: Promise.resolve(foobar) + payload: Promise.resolve(foobar), + meta }); - expect(baseDispatch.calledOnce).to.be.true; - expect(baseDispatch.firstCall.args[0]).to.deep.equal({ - type: 'ACTION_TYPE', - payload: foobar - }); + expect(baseDispatch.calledTwice).to.be.true; + const action1 = baseDispatch.firstCall.args[0]; + expect(action1.type).to.equal('ACTION_TYPE'); + expect(action1.payload).to.be.undefined; + expect(action1.meta).to.eql(meta); + expect(action1.sequence.type).to.equal('start'); + const action2 = baseDispatch.secondCall.args[0]; + expect(action2.type).to.equal('ACTION_TYPE'); + expect(action2.payload).to.eql(foobar); + expect(action2.meta).to.eql(meta); + expect(action2.sequence.type).to.equal('next'); + expect(action1.sequence.id).to.equal(action2.sequence.id); await dispatch({ type: 'ACTION_TYPE', - payload: Promise.reject(err) + payload: Promise.reject(err), + meta }).catch(noop); - expect(baseDispatch.calledTwice).to.be.true; - expect(baseDispatch.secondCall.args[0]).to.deep.equal({ - type: 'ACTION_TYPE', - payload: err, - error: true - }); + expect(baseDispatch.callCount).to.equal(4); + const action3 = baseDispatch.args[2][0]; + expect(action3.type).to.equal('ACTION_TYPE'); + expect(action3.payload).to.be.undefined; + expect(action3.meta).to.eql(meta); + expect(action3.sequence.type).to.equal('start'); + const action4 = baseDispatch.args[3][0]; + expect(action4.type).to.equal('ACTION_TYPE'); + expect(action4.payload).to.eql(err); + expect(action4.error).to.be.true; + expect(action4.meta).to.eql(meta); + expect(action4.sequence.type).to.equal('next'); + expect(action3.sequence.id).to.equal(action4.sequence.id); }); it('handles promises', async () => { diff --git a/src/index.js b/src/index.js index 4467474..c2d4e36 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ import { isFSA } from 'flux-standard-action'; +import uniqueId from 'lodash/utility/uniqueId'; function isPromise(val) { return val && typeof val.then === 'function'; @@ -12,11 +13,39 @@ export default function promiseMiddleware({ dispatch }) { : next(action); } - return isPromise(action.payload) - ? action.payload.then( - result => dispatch({ ...action, payload: result }), - error => dispatch({ ...action, payload: error, error: true }) - ) - : next(action); + if (isPromise(action.payload)) { + const sequenceId = uniqueId(); + + dispatch({ + ...action, + payload: undefined, + sequence: { + type: 'start', + id: sequenceId + } + }); + + return action.payload.then( + result => dispatch({ + ...action, + payload: result, + sequence: { + type: 'next', + id: sequenceId + } + }), + error => dispatch({ + ...action, + payload: error, + error: true, + sequence: { + type: 'next', + id: sequenceId + } + }) + ); + } + + return next(action); }; }