1 | import {
|
2 | isAllOf,
|
3 | isAnyOf,
|
4 | isAsyncThunkAction,
|
5 | isFulfilled,
|
6 | isPending,
|
7 | isRejected,
|
8 | isRejectedWithValue
|
9 | } from './matchers'
|
10 | import { createAction } from './createAction'
|
11 | import { createAsyncThunk } from './createAsyncThunk'
|
12 | import { createReducer } from './createReducer'
|
13 | import { ThunkAction } from 'redux-thunk'
|
14 | import { AnyAction } from 'redux'
|
15 |
|
16 | const thunk: ThunkAction<any, any, any, AnyAction> = () => {}
|
17 |
|
18 | describe('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 |
|
105 | describe('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 |
|
147 | describe('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 |
|
205 | describe('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 |
|
263 | describe('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 |
|
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 |
|
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 |
|
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 |
|
345 | describe('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 |
|
403 | describe('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 |