diff --git a/package.json b/package.json index 6e61e595..072c7c50 100644 --- a/package.json +++ b/package.json @@ -50,12 +50,13 @@ "eslint-config-airbnb-base": "^1.0.3", "eslint-plugin-import": "^1.5.0", "eslint-watch": "^2.1.13", - "flux-standard-action": "^0.6.0", "mocha": "^2.2.5", "rimraf": "^2.5.3", "webpack": "^1.13.1" }, "dependencies": { + "flux-standard-action": "^1.0.0", + "invariant": "^2.2.1", "lodash": "^4.13.1", "reduce-reducers": "^0.1.0" } diff --git a/src/__tests__/handleAction-test.js b/src/__tests__/handleAction-test.js index caa43051..ff8f5018 100644 --- a/src/__tests__/handleAction-test.js +++ b/src/__tests__/handleAction-test.js @@ -1,4 +1,5 @@ import { expect } from 'chai'; +import identity from 'lodash/identity'; import { handleAction, createAction, createActions, combineActions } from '../'; describe('handleAction()', () => { @@ -195,4 +196,36 @@ describe('handleAction()', () => { .to.deep.equal({ number: 3 }); }); }); + + describe('with invalid actions', () => { + it('should throw a descriptive error when the action object is missing', () => { + const reducer = handleAction(createAction('ACTION_1'), identity); + expect( + () => reducer(undefined) + ).to.throw( + Error, + 'The FSA spec mandates an action object with a type. Try using the createAction(s) method.' + ); + }); + + it('should throw a descriptive error when the action type is missing', () => { + const reducer = handleAction(createAction('ACTION_1'), identity); + expect( + () => reducer(undefined, {}) + ).to.throw( + Error, + 'The FSA spec mandates an action object with a type. Try using the createAction(s) method.' + ); + }); + + it('should throw a descriptive error when the action type is not a string or symbol', () => { + const reducer = handleAction(createAction('ACTION_1'), identity); + expect( + () => reducer(undefined, { type: false }) + ).to.throw( + Error, + 'The FSA spec mandates an action object with a type. Try using the createAction(s) method.' + ); + }); + }); }); diff --git a/src/handleAction.js b/src/handleAction.js index 207f9071..ed9f56af 100644 --- a/src/handleAction.js +++ b/src/handleAction.js @@ -2,6 +2,8 @@ import isFunction from 'lodash/isFunction'; import identity from 'lodash/identity'; import isNil from 'lodash/isNil'; import includes from 'lodash/includes'; +import invariant from 'invariant'; +import { isFSA } from 'flux-standard-action'; import { ACTION_TYPE_DELIMITER } from './combineActions'; export default function handleAction(actionType, reducers, defaultState) { @@ -12,6 +14,11 @@ export default function handleAction(actionType, reducers, defaultState) { : [reducers.next, reducers.throw].map(reducer => (isNil(reducer) ? identity : reducer)); return (state = defaultState, action) => { + invariant( + isFSA(action), + 'The FSA spec mandates an action object with a type. Try using the createAction(s) method.' + ); + if (!includes(actionTypes, action.type.toString())) { return state; }