11import { expect } from 'chai' ;
2+ import identity from 'lodash/identity' ;
23import { handleAction , createAction , createActions , combineActions } from '../' ;
34
45describe ( 'handleAction()' , ( ) => {
56 const type = 'TYPE' ;
67 const prevState = { counter : 3 } ;
8+ const defaultState = { counter : 0 } ;
79
810 it ( 'should throw an error if the reducer is the wrong type' , ( ) => {
911 const badReducers = [ 1 , 'string' , [ ] , null ] ;
@@ -26,9 +28,18 @@ describe('handleAction()', () => {
2628 } ) ;
2729
2830 describe ( 'single handler form' , ( ) => {
31+ it ( 'should throw an error if defaultState is not specified' , ( ) => {
32+ expect ( ( ) => {
33+ handleAction ( type , undefined ) ;
34+ } ) . to . throw (
35+ Error ,
36+ 'defaultState for reducer handling TYPE should be defined'
37+ ) ;
38+ } ) ;
39+
2940 describe ( 'resulting reducer' , ( ) => {
3041 it ( 'returns previous state if type does not match' , ( ) => {
31- const reducer = handleAction ( 'NOTTYPE' , ( ) => null ) ;
42+ const reducer = handleAction ( 'NOTTYPE' , ( ) => null , defaultState ) ;
3243 expect ( reducer ( prevState , { type } ) ) . to . equal ( prevState ) ;
3344 } ) ;
3445
@@ -43,7 +54,7 @@ describe('handleAction()', () => {
4354 it ( 'accepts single function as handler' , ( ) => {
4455 const reducer = handleAction ( type , ( state , action ) => ( {
4556 counter : state . counter + action . payload
46- } ) ) ;
57+ } ) , defaultState ) ;
4758 expect ( reducer ( prevState , { type, payload : 7 } ) )
4859 . to . deep . equal ( {
4960 counter : 10
@@ -54,15 +65,15 @@ describe('handleAction()', () => {
5465 const incrementAction = createAction ( type ) ;
5566 const reducer = handleAction ( incrementAction , ( state , action ) => ( {
5667 counter : state . counter + action . payload
57- } ) ) ;
68+ } ) , defaultState ) ;
5869
5970 expect ( reducer ( prevState , incrementAction ( 7 ) ) )
6071 . to . deep . equal ( {
6172 counter : 10
6273 } ) ;
6374 } ) ;
6475
65- it ( 'accepts single function as handler and a default state' , ( ) => {
76+ it ( 'accepts a default state used when the previous state is undefined ' , ( ) => {
6677 const reducer = handleAction ( type , ( state , action ) => ( {
6778 counter : state . counter + action . payload
6879 } ) , { counter : 3 } ) ;
@@ -78,20 +89,30 @@ describe('handleAction()', () => {
7889
7990 const reducer = handleAction ( increment , ( state , { payload } ) => ( {
8091 counter : state . counter + payload
81- } ) , { counter : 3 } ) ;
92+ } ) , defaultState ) ;
8293
8394 expect ( reducer ( undefined , increment ( 7 ) ) )
8495 . to . deep . equal ( {
85- counter : 10
96+ counter : 7
8697 } ) ;
8798 } ) ;
8899 } ) ;
89100 } ) ;
90101
91102 describe ( 'map of handlers form' , ( ) => {
103+ it ( 'should throw an error if defaultState is not specified' , ( ) => {
104+ expect ( ( ) => {
105+ handleAction ( type , { next : ( ) => null } ) ;
106+ } )
107+ . to . throw (
108+ Error ,
109+ 'defaultState for reducer handling TYPE should be defined'
110+ ) ;
111+ } ) ;
112+
92113 describe ( 'resulting reducer' , ( ) => {
93114 it ( 'returns previous state if type does not match' , ( ) => {
94- const reducer = handleAction ( 'NOTTYPE' , { next : ( ) => null } ) ;
115+ const reducer = handleAction ( 'NOTTYPE' , { next : ( ) => null } , defaultState ) ;
95116 expect ( reducer ( prevState , { type } ) ) . to . equal ( prevState ) ;
96117 } ) ;
97118
@@ -100,7 +121,7 @@ describe('handleAction()', () => {
100121 next : ( state , action ) => ( {
101122 counter : state . counter + action . payload
102123 } )
103- } ) ;
124+ } , defaultState ) ;
104125 expect ( reducer ( prevState , { type, payload : 7 } ) )
105126 . to . deep . equal ( {
106127 counter : 10
@@ -112,7 +133,7 @@ describe('handleAction()', () => {
112133 throw : ( state , action ) => ( {
113134 counter : state . counter + action . payload
114135 } )
115- } ) ;
136+ } , defaultState ) ;
116137
117138 expect ( reducer ( prevState , { type, payload : 7 , error : true } ) )
118139 . to . deep . equal ( {
@@ -121,7 +142,7 @@ describe('handleAction()', () => {
121142 } ) ;
122143
123144 it ( 'returns previous state if matching handler is not function' , ( ) => {
124- const reducer = handleAction ( type , { next : null , error : 123 } ) ;
145+ const reducer = handleAction ( type , { next : null , error : 123 } , defaultState ) ;
125146 expect ( reducer ( prevState , { type, payload : 123 } ) ) . to . equal ( prevState ) ;
126147 expect ( reducer ( prevState , { type, payload : 123 , error : true } ) )
127148 . to . equal ( prevState ) ;
@@ -134,7 +155,8 @@ describe('handleAction()', () => {
134155 const action1 = createAction ( 'ACTION_1' ) ;
135156 const reducer = handleAction (
136157 combineActions ( action1 , 'ACTION_2' , 'ACTION_3' ) ,
137- ( state , { payload } ) => ( { ...state , number : state . number + payload } )
158+ ( state , { payload } ) => ( { ...state , number : state . number + payload } ) ,
159+ defaultState
138160 ) ;
139161
140162 expect ( reducer ( { number : 1 } , action1 ( 1 ) ) ) . to . deep . equal ( { number : 2 } ) ;
@@ -148,7 +170,7 @@ describe('handleAction()', () => {
148170 next ( state , { payload } ) {
149171 return { ...state , number : state . number + payload } ;
150172 }
151- } ) ;
173+ } , defaultState ) ;
152174
153175 expect ( reducer ( { number : 1 } , action1 ( 1 ) ) ) . to . deep . equal ( { number : 2 } ) ;
154176 expect ( reducer ( { number : 1 } , { type : 'ACTION_2' , payload : 2 } ) ) . to . deep . equal ( { number : 3 } ) ;
@@ -165,7 +187,7 @@ describe('handleAction()', () => {
165187 throw ( state ) {
166188 return { ...state , threw : true } ;
167189 }
168- } ) ;
190+ } , defaultState ) ;
169191 const error = new Error ;
170192
171193 expect ( reducer ( { number : 0 } , action1 ( error ) ) )
@@ -180,6 +202,7 @@ describe('handleAction()', () => {
180202 const reducer = handleAction (
181203 combineActions ( 'ACTION_1' , 'ACTION_2' ) ,
182204 ( state , { payload } ) => ( { ...state , state : state . number + payload } ) ,
205+ defaultState
183206 ) ;
184207
185208 const state = { number : 0 } ;
@@ -191,11 +214,11 @@ describe('handleAction()', () => {
191214 const reducer = handleAction (
192215 combineActions ( 'INCREMENT' , 'DECREMENT' ) ,
193216 ( state , { payload } ) => ( { ...state , counter : state . counter + payload } ) ,
194- { counter : 10 }
217+ defaultState
195218 ) ;
196219
197- expect ( reducer ( undefined , { type : 'INCREMENT' , payload : + 1 } ) ) . to . deep . equal ( { counter : 11 } ) ;
198- expect ( reducer ( undefined , { type : 'DECREMENT' , payload : - 1 } ) ) . to . deep . equal ( { counter : 9 } ) ;
220+ expect ( reducer ( undefined , { type : 'INCREMENT' , payload : + 1 } ) ) . to . deep . equal ( { counter : + 1 } ) ;
221+ expect ( reducer ( undefined , { type : 'DECREMENT' , payload : - 1 } ) ) . to . deep . equal ( { counter : - 1 } ) ;
199222 } ) ;
200223
201224 it ( 'should handle combined actions with symbols' , ( ) => {
@@ -204,7 +227,8 @@ describe('handleAction()', () => {
204227 const action3 = createAction ( Symbol ( 'ACTION_3' ) ) ;
205228 const reducer = handleAction (
206229 combineActions ( action1 , action2 , action3 ) ,
207- ( state , { payload } ) => ( { ...state , number : state . number + payload } )
230+ ( state , { payload } ) => ( { ...state , number : state . number + payload } ) ,
231+ defaultState
208232 ) ;
209233
210234 expect ( reducer ( { number : 0 } , action1 ( 1 ) ) )
@@ -215,4 +239,36 @@ describe('handleAction()', () => {
215239 . to . deep . equal ( { number : 3 } ) ;
216240 } ) ;
217241 } ) ;
242+
243+ describe ( 'with invalid actions' , ( ) => {
244+ it ( 'should throw a descriptive error when the action object is missing' , ( ) => {
245+ const reducer = handleAction ( createAction ( 'ACTION_1' ) , identity , { } ) ;
246+ expect (
247+ ( ) => reducer ( undefined )
248+ ) . to . throw (
249+ Error ,
250+ 'The FSA spec mandates an action object with a type. Try using the createAction(s) method.'
251+ ) ;
252+ } ) ;
253+
254+ it ( 'should throw a descriptive error when the action type is missing' , ( ) => {
255+ const reducer = handleAction ( createAction ( 'ACTION_1' ) , identity , { } ) ;
256+ expect (
257+ ( ) => reducer ( undefined , { } )
258+ ) . to . throw (
259+ Error ,
260+ 'The FSA spec mandates an action object with a type. Try using the createAction(s) method.'
261+ ) ;
262+ } ) ;
263+
264+ it ( 'should throw a descriptive error when the action type is not a string or symbol' , ( ) => {
265+ const reducer = handleAction ( createAction ( 'ACTION_1' ) , identity , { } ) ;
266+ expect (
267+ ( ) => reducer ( undefined , { type : false } )
268+ ) . to . throw (
269+ Error ,
270+ 'The FSA spec mandates an action object with a type. Try using the createAction(s) method.'
271+ ) ;
272+ } ) ;
273+ } ) ;
218274} ) ;
0 commit comments