1
1
import { expect } from 'chai' ;
2
+ import identity from 'lodash/identity' ;
2
3
import { handleAction , createAction , createActions , combineActions } from '../' ;
3
4
4
5
describe ( 'handleAction()' , ( ) => {
5
6
const type = 'TYPE' ;
6
7
const prevState = { counter : 3 } ;
8
+ const defaultState = { counter : 0 } ;
7
9
8
10
it ( 'should throw an error if the reducer is the wrong type' , ( ) => {
9
11
const badReducers = [ 1 , 'string' , [ ] , null ] ;
@@ -26,9 +28,18 @@ describe('handleAction()', () => {
26
28
} ) ;
27
29
28
30
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
+
29
40
describe ( 'resulting reducer' , ( ) => {
30
41
it ( 'returns previous state if type does not match' , ( ) => {
31
- const reducer = handleAction ( 'NOTTYPE' , ( ) => null ) ;
42
+ const reducer = handleAction ( 'NOTTYPE' , ( ) => null , defaultState ) ;
32
43
expect ( reducer ( prevState , { type } ) ) . to . equal ( prevState ) ;
33
44
} ) ;
34
45
@@ -43,7 +54,7 @@ describe('handleAction()', () => {
43
54
it ( 'accepts single function as handler' , ( ) => {
44
55
const reducer = handleAction ( type , ( state , action ) => ( {
45
56
counter : state . counter + action . payload
46
- } ) ) ;
57
+ } ) , defaultState ) ;
47
58
expect ( reducer ( prevState , { type, payload : 7 } ) )
48
59
. to . deep . equal ( {
49
60
counter : 10
@@ -54,15 +65,15 @@ describe('handleAction()', () => {
54
65
const incrementAction = createAction ( type ) ;
55
66
const reducer = handleAction ( incrementAction , ( state , action ) => ( {
56
67
counter : state . counter + action . payload
57
- } ) ) ;
68
+ } ) , defaultState ) ;
58
69
59
70
expect ( reducer ( prevState , incrementAction ( 7 ) ) )
60
71
. to . deep . equal ( {
61
72
counter : 10
62
73
} ) ;
63
74
} ) ;
64
75
65
- it ( 'accepts single function as handler and a default state' , ( ) => {
76
+ it ( 'accepts a default state used when the previous state is undefined ' , ( ) => {
66
77
const reducer = handleAction ( type , ( state , action ) => ( {
67
78
counter : state . counter + action . payload
68
79
} ) , { counter : 3 } ) ;
@@ -78,20 +89,30 @@ describe('handleAction()', () => {
78
89
79
90
const reducer = handleAction ( increment , ( state , { payload } ) => ( {
80
91
counter : state . counter + payload
81
- } ) , { counter : 3 } ) ;
92
+ } ) , defaultState ) ;
82
93
83
94
expect ( reducer ( undefined , increment ( 7 ) ) )
84
95
. to . deep . equal ( {
85
- counter : 10
96
+ counter : 7
86
97
} ) ;
87
98
} ) ;
88
99
} ) ;
89
100
} ) ;
90
101
91
102
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
+
92
113
describe ( 'resulting reducer' , ( ) => {
93
114
it ( 'returns previous state if type does not match' , ( ) => {
94
- const reducer = handleAction ( 'NOTTYPE' , { next : ( ) => null } ) ;
115
+ const reducer = handleAction ( 'NOTTYPE' , { next : ( ) => null } , defaultState ) ;
95
116
expect ( reducer ( prevState , { type } ) ) . to . equal ( prevState ) ;
96
117
} ) ;
97
118
@@ -100,7 +121,7 @@ describe('handleAction()', () => {
100
121
next : ( state , action ) => ( {
101
122
counter : state . counter + action . payload
102
123
} )
103
- } ) ;
124
+ } , defaultState ) ;
104
125
expect ( reducer ( prevState , { type, payload : 7 } ) )
105
126
. to . deep . equal ( {
106
127
counter : 10
@@ -112,7 +133,7 @@ describe('handleAction()', () => {
112
133
throw : ( state , action ) => ( {
113
134
counter : state . counter + action . payload
114
135
} )
115
- } ) ;
136
+ } , defaultState ) ;
116
137
117
138
expect ( reducer ( prevState , { type, payload : 7 , error : true } ) )
118
139
. to . deep . equal ( {
@@ -121,7 +142,7 @@ describe('handleAction()', () => {
121
142
} ) ;
122
143
123
144
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 ) ;
125
146
expect ( reducer ( prevState , { type, payload : 123 } ) ) . to . equal ( prevState ) ;
126
147
expect ( reducer ( prevState , { type, payload : 123 , error : true } ) )
127
148
. to . equal ( prevState ) ;
@@ -134,7 +155,8 @@ describe('handleAction()', () => {
134
155
const action1 = createAction ( 'ACTION_1' ) ;
135
156
const reducer = handleAction (
136
157
combineActions ( action1 , 'ACTION_2' , 'ACTION_3' ) ,
137
- ( state , { payload } ) => ( { ...state , number : state . number + payload } )
158
+ ( state , { payload } ) => ( { ...state , number : state . number + payload } ) ,
159
+ defaultState
138
160
) ;
139
161
140
162
expect ( reducer ( { number : 1 } , action1 ( 1 ) ) ) . to . deep . equal ( { number : 2 } ) ;
@@ -148,7 +170,7 @@ describe('handleAction()', () => {
148
170
next ( state , { payload } ) {
149
171
return { ...state , number : state . number + payload } ;
150
172
}
151
- } ) ;
173
+ } , defaultState ) ;
152
174
153
175
expect ( reducer ( { number : 1 } , action1 ( 1 ) ) ) . to . deep . equal ( { number : 2 } ) ;
154
176
expect ( reducer ( { number : 1 } , { type : 'ACTION_2' , payload : 2 } ) ) . to . deep . equal ( { number : 3 } ) ;
@@ -165,7 +187,7 @@ describe('handleAction()', () => {
165
187
throw ( state ) {
166
188
return { ...state , threw : true } ;
167
189
}
168
- } ) ;
190
+ } , defaultState ) ;
169
191
const error = new Error ;
170
192
171
193
expect ( reducer ( { number : 0 } , action1 ( error ) ) )
@@ -180,6 +202,7 @@ describe('handleAction()', () => {
180
202
const reducer = handleAction (
181
203
combineActions ( 'ACTION_1' , 'ACTION_2' ) ,
182
204
( state , { payload } ) => ( { ...state , state : state . number + payload } ) ,
205
+ defaultState
183
206
) ;
184
207
185
208
const state = { number : 0 } ;
@@ -191,11 +214,11 @@ describe('handleAction()', () => {
191
214
const reducer = handleAction (
192
215
combineActions ( 'INCREMENT' , 'DECREMENT' ) ,
193
216
( state , { payload } ) => ( { ...state , counter : state . counter + payload } ) ,
194
- { counter : 10 }
217
+ defaultState
195
218
) ;
196
219
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 } ) ;
199
222
} ) ;
200
223
201
224
it ( 'should handle combined actions with symbols' , ( ) => {
@@ -204,7 +227,8 @@ describe('handleAction()', () => {
204
227
const action3 = createAction ( Symbol ( 'ACTION_3' ) ) ;
205
228
const reducer = handleAction (
206
229
combineActions ( action1 , action2 , action3 ) ,
207
- ( state , { payload } ) => ( { ...state , number : state . number + payload } )
230
+ ( state , { payload } ) => ( { ...state , number : state . number + payload } ) ,
231
+ defaultState
208
232
) ;
209
233
210
234
expect ( reducer ( { number : 0 } , action1 ( 1 ) ) )
@@ -215,4 +239,36 @@ describe('handleAction()', () => {
215
239
. to . deep . equal ( { number : 3 } ) ;
216
240
} ) ;
217
241
} ) ;
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
+ } ) ;
218
274
} ) ;
0 commit comments