UNPKG

14.9 kBPlain TextView Raw
1import {
2 isAllOf,
3 isAnyOf,
4 isAsyncThunkAction,
5 isFulfilled,
6 isPending,
7 isRejected,
8 isRejectedWithValue
9} from './matchers'
10import { createAction } from './createAction'
11import { createAsyncThunk } from './createAsyncThunk'
12import { createReducer } from './createReducer'
13import { ThunkAction } from 'redux-thunk'
14import { AnyAction } from 'redux'
15
16const thunk: ThunkAction<any, any, any, AnyAction> = () => {}
17
18describe('isAnyOf', () => {
19 it('returns true only if any matchers match (match function)', () => {
20 const actionA = createAction<string>('a')
21 const actionB = createAction<number>('b')
22
23 const trueAction = {
24 type: 'a',
25 payload: 'payload'
26 }
27
28 expect(isAnyOf(actionA, actionB)(trueAction)).toEqual(true)
29
30 const falseAction = {
31 type: 'c',
32 payload: 'payload'
33 }
34
35 expect(isAnyOf(actionA, actionB)(falseAction)).toEqual(false)
36 })
37
38 it('returns true only if any type guards match', () => {
39 const actionA = createAction<string>('a')
40 const actionB = createAction<number>('b')
41
42 const isActionA = actionA.match
43 const isActionB = actionB.match
44
45 const trueAction = {
46 type: 'a',
47 payload: 'payload'
48 }
49
50 expect(isAnyOf(isActionA, isActionB)(trueAction)).toEqual(true)
51
52 const falseAction = {
53 type: 'c',
54 payload: 'payload'
55 }
56
57 expect(isAnyOf(isActionA, isActionB)(falseAction)).toEqual(false)
58 })
59
60 it('returns true only if any matchers match (thunk action creators)', () => {
61 const thunkA = createAsyncThunk<string>('a', () => {
62 return 'noop'
63 })
64 const thunkB = createAsyncThunk<number>('b', () => {
65 return 0
66 })
67
68 const action = thunkA.fulfilled('fakeRequestId', 'test')
69
70 expect(isAnyOf(thunkA.fulfilled, thunkB.fulfilled)(action)).toEqual(true)
71
72 expect(
73 isAnyOf(thunkA.pending, thunkA.rejected, thunkB.fulfilled)(action)
74 ).toEqual(false)
75 })
76
77 it('works with reducers', () => {
78 const actionA = createAction<string>('a')
79 const actionB = createAction<number>('b')
80
81 const trueAction = {
82 type: 'a',
83 payload: 'payload'
84 }
85
86 const initialState = { value: false }
87
88 const reducer = createReducer(initialState, builder => {
89 builder.addMatcher(isAnyOf(actionA, actionB), state => {
90 return { ...state, value: true }
91 })
92 })
93
94 expect(reducer(initialState, trueAction)).toEqual({ value: true })
95
96 const falseAction = {
97 type: 'c',
98 payload: 'payload'
99 }
100
101 expect(reducer(initialState, falseAction)).toEqual(initialState)
102 })
103})
104
105describe('isAllOf', () => {
106 it('returns true only if all matchers match', () => {
107 const actionA = createAction<string>('a')
108
109 interface SpecialAction {
110 payload: 'SPECIAL'
111 }
112
113 const isActionSpecial = (action: any): action is SpecialAction => {
114 return action.payload === 'SPECIAL'
115 }
116
117 const trueAction = {
118 type: 'a',
119 payload: 'SPECIAL'
120 }
121
122 expect(isAllOf(actionA, isActionSpecial)(trueAction)).toEqual(true)
123
124 const falseAction = {
125 type: 'a',
126 payload: 'ORDINARY'
127 }
128
129 expect(isAllOf(actionA, isActionSpecial)(falseAction)).toEqual(false)
130
131 const thunkA = createAsyncThunk<string>('a', () => 'result')
132
133 const specialThunkAction = thunkA.fulfilled('SPECIAL', 'fakeRequestId')
134
135 expect(isAllOf(thunkA.fulfilled, isActionSpecial)(specialThunkAction)).toBe(
136 true
137 )
138
139 const ordinaryThunkAction = thunkA.fulfilled('ORDINARY', 'fakeRequestId')
140
141 expect(
142 isAllOf(thunkA.fulfilled, isActionSpecial)(ordinaryThunkAction)
143 ).toBe(false)
144 })
145})
146
147describe('isPending', () => {
148 test('should return false for a regular action', () => {
149 const action = createAction<string>('action/type')('testPayload')
150
151 expect(isPending()(action)).toBe(false)
152 expect(isPending(action)).toBe(false)
153 expect(isPending(thunk)).toBe(false)
154 })
155
156 test('should return true only for pending async thunk actions', () => {
157 const thunk = createAsyncThunk<string>('a', () => 'result')
158
159 const pendingAction = thunk.pending('fakeRequestId')
160 expect(isPending()(pendingAction)).toBe(true)
161 expect(isPending(pendingAction)).toBe(true)
162
163 const rejectedAction = thunk.rejected(
164 new Error('rejected'),
165 'fakeRequestId'
166 )
167 expect(isPending()(rejectedAction)).toBe(false)
168
169 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
170 expect(isPending()(fulfilledAction)).toBe(false)
171 })
172
173 test('should return true only for thunks provided as arguments', () => {
174 const thunkA = createAsyncThunk<string>('a', () => 'result')
175 const thunkB = createAsyncThunk<string>('b', () => 'result')
176 const thunkC = createAsyncThunk<string>('c', () => 'result')
177
178 const matchAC = isPending(thunkA, thunkC)
179 const matchB = isPending(thunkB)
180
181 function testPendingAction(
182 thunk: typeof thunkA | typeof thunkB | typeof thunkC,
183 expected: boolean
184 ) {
185 const pendingAction = thunk.pending('fakeRequestId')
186 expect(matchAC(pendingAction)).toBe(expected)
187 expect(matchB(pendingAction)).toBe(!expected)
188
189 const rejectedAction = thunk.rejected(
190 new Error('rejected'),
191 'fakeRequestId'
192 )
193 expect(matchAC(rejectedAction)).toBe(false)
194
195 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
196 expect(matchAC(fulfilledAction)).toBe(false)
197 }
198
199 testPendingAction(thunkA, true)
200 testPendingAction(thunkC, true)
201 testPendingAction(thunkB, false)
202 })
203})
204
205describe('isRejected', () => {
206 test('should return false for a regular action', () => {
207 const action = createAction<string>('action/type')('testPayload')
208
209 expect(isRejected()(action)).toBe(false)
210 expect(isRejected(action)).toBe(false)
211 expect(isRejected(thunk)).toBe(false)
212 })
213
214 test('should return true only for rejected async thunk actions', () => {
215 const thunk = createAsyncThunk<string>('a', () => 'result')
216
217 const pendingAction = thunk.pending('fakeRequestId')
218 expect(isRejected()(pendingAction)).toBe(false)
219
220 const rejectedAction = thunk.rejected(
221 new Error('rejected'),
222 'fakeRequestId'
223 )
224 expect(isRejected()(rejectedAction)).toBe(true)
225 expect(isRejected(rejectedAction)).toBe(true)
226
227 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
228 expect(isRejected()(fulfilledAction)).toBe(false)
229 })
230
231 test('should return true only for thunks provided as arguments', () => {
232 const thunkA = createAsyncThunk<string>('a', () => 'result')
233 const thunkB = createAsyncThunk<string>('b', () => 'result')
234 const thunkC = createAsyncThunk<string>('c', () => 'result')
235
236 const matchAC = isRejected(thunkA, thunkC)
237 const matchB = isRejected(thunkB)
238
239 function testRejectedAction(
240 thunk: typeof thunkA | typeof thunkB | typeof thunkC,
241 expected: boolean
242 ) {
243 const pendingAction = thunk.pending('fakeRequestId')
244 expect(matchAC(pendingAction)).toBe(false)
245
246 const rejectedAction = thunk.rejected(
247 new Error('rejected'),
248 'fakeRequestId'
249 )
250 expect(matchAC(rejectedAction)).toBe(expected)
251 expect(matchB(rejectedAction)).toBe(!expected)
252
253 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
254 expect(matchAC(fulfilledAction)).toBe(false)
255 }
256
257 testRejectedAction(thunkA, true)
258 testRejectedAction(thunkC, true)
259 testRejectedAction(thunkB, false)
260 })
261})
262
263describe('isRejectedWithValue', () => {
264 test('should return false for a regular action', () => {
265 const action = createAction<string>('action/type')('testPayload')
266
267 expect(isRejectedWithValue()(action)).toBe(false)
268 expect(isRejectedWithValue(action)).toBe(false)
269 expect(isRejectedWithValue(thunk)).toBe(false)
270 })
271
272 test('should return true only for rejected-with-value async thunk actions', async () => {
273 const thunk = createAsyncThunk<string>('a', (_, { rejectWithValue }) => {
274 return rejectWithValue('rejectWithValue!')
275 })
276
277 const pendingAction = thunk.pending('fakeRequestId')
278 expect(isRejectedWithValue()(pendingAction)).toBe(false)
279
280 const rejectedAction = thunk.rejected(
281 new Error('rejected'),
282 'fakeRequestId'
283 )
284 expect(isRejectedWithValue()(rejectedAction)).toBe(false)
285
286 const getState = jest.fn(() => ({}))
287 const dispatch = jest.fn((x: any) => x)
288 const extra = {}
289
290 // note: doesn't throw because we don't unwrap it
291 const rejectedWithValueAction = await thunk()(dispatch, getState, extra)
292
293 expect(isRejectedWithValue()(rejectedWithValueAction)).toBe(true)
294
295 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
296 expect(isRejectedWithValue()(fulfilledAction)).toBe(false)
297 })
298
299 test('should return true only for thunks provided as arguments', async () => {
300 const payloadCreator = (_: any, { rejectWithValue }: any) => {
301 return rejectWithValue('rejectWithValue!')
302 }
303
304 const thunkA = createAsyncThunk<string>('a', payloadCreator)
305 const thunkB = createAsyncThunk<string>('b', payloadCreator)
306 const thunkC = createAsyncThunk<string>('c', payloadCreator)
307
308 const matchAC = isRejectedWithValue(thunkA, thunkC)
309 const matchB = isRejectedWithValue(thunkB)
310
311 async function testRejectedAction(
312 thunk: typeof thunkA | typeof thunkB | typeof thunkC,
313 expected: boolean
314 ) {
315 const pendingAction = thunk.pending('fakeRequestId')
316 expect(matchAC(pendingAction)).toBe(false)
317
318 const rejectedAction = thunk.rejected(
319 new Error('rejected'),
320 'fakeRequestId'
321 )
322 // rejected-with-value is a narrower requirement than rejected
323 expect(matchAC(rejectedAction)).toBe(false)
324
325 const getState = jest.fn(() => ({}))
326 const dispatch = jest.fn((x: any) => x)
327 const extra = {}
328
329 // note: doesn't throw because we don't unwrap it
330 const rejectedWithValueAction = await thunk()(dispatch, getState, extra)
331
332 expect(matchAC(rejectedWithValueAction)).toBe(expected)
333 expect(matchB(rejectedWithValueAction)).toBe(!expected)
334
335 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
336 expect(matchAC(fulfilledAction)).toBe(false)
337 }
338
339 await testRejectedAction(thunkA, true)
340 await testRejectedAction(thunkC, true)
341 await testRejectedAction(thunkB, false)
342 })
343})
344
345describe('isFulfilled', () => {
346 test('should return false for a regular action', () => {
347 const action = createAction<string>('action/type')('testPayload')
348
349 expect(isFulfilled()(action)).toBe(false)
350 expect(isFulfilled(action)).toBe(false)
351 expect(isFulfilled(thunk)).toBe(false)
352 })
353
354 test('should return true only for fulfilled async thunk actions', () => {
355 const thunk = createAsyncThunk<string>('a', () => 'result')
356
357 const pendingAction = thunk.pending('fakeRequestId')
358 expect(isFulfilled()(pendingAction)).toBe(false)
359
360 const rejectedAction = thunk.rejected(
361 new Error('rejected'),
362 'fakeRequestId'
363 )
364 expect(isFulfilled()(rejectedAction)).toBe(false)
365
366 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
367 expect(isFulfilled()(fulfilledAction)).toBe(true)
368 expect(isFulfilled(fulfilledAction)).toBe(true)
369 })
370
371 test('should return true only for thunks provided as arguments', () => {
372 const thunkA = createAsyncThunk<string>('a', () => 'result')
373 const thunkB = createAsyncThunk<string>('b', () => 'result')
374 const thunkC = createAsyncThunk<string>('c', () => 'result')
375
376 const matchAC = isFulfilled(thunkA, thunkC)
377 const matchB = isFulfilled(thunkB)
378
379 function testFulfilledAction(
380 thunk: typeof thunkA | typeof thunkB | typeof thunkC,
381 expected: boolean
382 ) {
383 const pendingAction = thunk.pending('fakeRequestId')
384 expect(matchAC(pendingAction)).toBe(false)
385
386 const rejectedAction = thunk.rejected(
387 new Error('rejected'),
388 'fakeRequestId'
389 )
390 expect(matchAC(rejectedAction)).toBe(false)
391
392 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
393 expect(matchAC(fulfilledAction)).toBe(expected)
394 expect(matchB(fulfilledAction)).toBe(!expected)
395 }
396
397 testFulfilledAction(thunkA, true)
398 testFulfilledAction(thunkC, true)
399 testFulfilledAction(thunkB, false)
400 })
401})
402
403describe('isAsyncThunkAction', () => {
404 test('should return false for a regular action', () => {
405 const action = createAction<string>('action/type')('testPayload')
406
407 expect(isAsyncThunkAction()(action)).toBe(false)
408 expect(isAsyncThunkAction(action)).toBe(false)
409 expect(isAsyncThunkAction(thunk)).toBe(false)
410 })
411
412 test('should return true for any async thunk action if no arguments were provided', () => {
413 const thunk = createAsyncThunk<string>('a', () => 'result')
414 const matcher = isAsyncThunkAction()
415
416 const pendingAction = thunk.pending('fakeRequestId')
417 expect(matcher(pendingAction)).toBe(true)
418
419 const rejectedAction = thunk.rejected(
420 new Error('rejected'),
421 'fakeRequestId'
422 )
423 expect(matcher(rejectedAction)).toBe(true)
424
425 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
426 expect(matcher(fulfilledAction)).toBe(true)
427 })
428
429 test('should return true only for thunks provided as arguments', () => {
430 const thunkA = createAsyncThunk<string>('a', () => 'result')
431 const thunkB = createAsyncThunk<string>('b', () => 'result')
432 const thunkC = createAsyncThunk<string>('c', () => 'result')
433
434 const matchAC = isAsyncThunkAction(thunkA, thunkC)
435 const matchB = isAsyncThunkAction(thunkB)
436
437 function testAllActions(
438 thunk: typeof thunkA | typeof thunkB | typeof thunkC,
439 expected: boolean
440 ) {
441 const pendingAction = thunk.pending('fakeRequestId')
442 expect(matchAC(pendingAction)).toBe(expected)
443 expect(matchB(pendingAction)).toBe(!expected)
444
445 const rejectedAction = thunk.rejected(
446 new Error('rejected'),
447 'fakeRequestId'
448 )
449 expect(matchAC(rejectedAction)).toBe(expected)
450 expect(matchB(rejectedAction)).toBe(!expected)
451
452 const fulfilledAction = thunk.fulfilled('result', 'fakeRequestId')
453 expect(matchAC(fulfilledAction)).toBe(expected)
454 expect(matchB(fulfilledAction)).toBe(!expected)
455 }
456
457 testAllActions(thunkA, true)
458 testAllActions(thunkC, true)
459 testAllActions(thunkB, false)
460 })
461})
462
\No newline at end of file