source: node_modules/@reduxjs/toolkit/src/tests/matchers.test-d.ts

Last change on this file was a762898, checked in by istevanoska <ilinastevanoska@…>, 5 months ago

Added visualizations

  • Property mode set to 100644
File size: 7.8 KB
Line 
1import type { UnknownAction } from 'redux'
2import type { SerializedError } from '../../src'
3import {
4 createAction,
5 createAsyncThunk,
6 isAllOf,
7 isAnyOf,
8 isAsyncThunkAction,
9 isFulfilled,
10 isPending,
11 isRejected,
12 isRejectedWithValue,
13} from '../../src'
14
15const action: UnknownAction = { type: 'foo' }
16
17describe('type tests', () => {
18 describe('isAnyOf', () => {
19 test('isAnyOf correctly narrows types when used with action creators', () => {
20 const actionA = createAction('a', () => {
21 return {
22 payload: {
23 prop1: 1,
24 prop3: 2,
25 },
26 }
27 })
28
29 const actionB = createAction('b', () => {
30 return {
31 payload: {
32 prop1: 1,
33 prop2: 2,
34 },
35 }
36 })
37
38 if (isAnyOf(actionA, actionB)(action)) {
39 expectTypeOf(action.payload).toHaveProperty('prop1')
40
41 expectTypeOf(action.payload).not.toHaveProperty('prop2')
42
43 expectTypeOf(action.payload).not.toHaveProperty('prop3')
44 }
45 })
46
47 test('isAnyOf correctly narrows types when used with async thunks', () => {
48 const asyncThunk1 = createAsyncThunk<{ prop1: number; prop3: number }>(
49 'asyncThunk1',
50
51 async () => {
52 return {
53 prop1: 1,
54 prop3: 3,
55 }
56 },
57 )
58
59 const asyncThunk2 = createAsyncThunk<{ prop1: number; prop2: number }>(
60 'asyncThunk2',
61
62 async () => {
63 return {
64 prop1: 1,
65 prop2: 2,
66 }
67 },
68 )
69
70 if (isAnyOf(asyncThunk1.fulfilled, asyncThunk2.fulfilled)(action)) {
71 expectTypeOf(action.payload).toHaveProperty('prop1')
72
73 expectTypeOf(action.payload).not.toHaveProperty('prop2')
74
75 expectTypeOf(action.payload).not.toHaveProperty('prop3')
76 }
77 })
78
79 test('isAnyOf correctly narrows types when used with type guards', () => {
80 interface ActionA {
81 type: 'a'
82 payload: {
83 prop1: 1
84 prop3: 2
85 }
86 }
87
88 interface ActionB {
89 type: 'b'
90 payload: {
91 prop1: 1
92 prop2: 2
93 }
94 }
95
96 const guardA = (v: any): v is ActionA => {
97 return v.type === 'a'
98 }
99
100 const guardB = (v: any): v is ActionB => {
101 return v.type === 'b'
102 }
103
104 if (isAnyOf(guardA, guardB)(action)) {
105 expectTypeOf(action.payload).toHaveProperty('prop1')
106
107 expectTypeOf(action.payload).not.toHaveProperty('prop2')
108
109 expectTypeOf(action.payload).not.toHaveProperty('prop3')
110 }
111 })
112 })
113
114 describe('isAllOf', () => {
115 interface SpecialAction {
116 payload: {
117 special: boolean
118 }
119 }
120
121 const isSpecialAction = (v: any): v is SpecialAction => {
122 return v.meta.isSpecial
123 }
124
125 test('isAllOf correctly narrows types when used with action creators and type guards', () => {
126 const actionA = createAction('a', () => {
127 return {
128 payload: {
129 prop1: 1,
130 prop3: 2,
131 },
132 }
133 })
134
135 if (isAllOf(actionA, isSpecialAction)(action)) {
136 expectTypeOf(action.payload).toHaveProperty('prop1')
137
138 expectTypeOf(action.payload).not.toHaveProperty('prop2')
139
140 expectTypeOf(action.payload).toHaveProperty('prop3')
141
142 expectTypeOf(action.payload).toHaveProperty('special')
143 }
144 })
145
146 test('isAllOf correctly narrows types when used with async thunks and type guards', () => {
147 const asyncThunk1 = createAsyncThunk<{ prop1: number; prop3: number }>(
148 'asyncThunk1',
149
150 async () => {
151 return {
152 prop1: 1,
153 prop3: 3,
154 }
155 },
156 )
157
158 if (isAllOf(asyncThunk1.fulfilled, isSpecialAction)(action)) {
159 expectTypeOf(action.payload).toHaveProperty('prop1')
160
161 expectTypeOf(action.payload).not.toHaveProperty('prop2')
162
163 expectTypeOf(action.payload).toHaveProperty('prop3')
164
165 expectTypeOf(action.payload).toHaveProperty('special')
166 }
167 })
168
169 test('isAnyOf correctly narrows types when used with type guards', () => {
170 interface ActionA {
171 type: 'a'
172 payload: {
173 prop1: 1
174 prop3: 2
175 }
176 }
177
178 const guardA = (v: any): v is ActionA => {
179 return v.type === 'a'
180 }
181
182 if (isAllOf(guardA, isSpecialAction)(action)) {
183 expectTypeOf(action.payload).toHaveProperty('prop1')
184
185 expectTypeOf(action.payload).not.toHaveProperty('prop2')
186
187 expectTypeOf(action.payload).toHaveProperty('prop3')
188
189 expectTypeOf(action.payload).toHaveProperty('special')
190 }
191 })
192
193 test('isPending correctly narrows types', () => {
194 if (isPending(action)) {
195 expectTypeOf(action.payload).toBeUndefined()
196
197 expectTypeOf(action).not.toHaveProperty('error')
198 }
199
200 const thunk = createAsyncThunk<string>('a', () => 'result')
201
202 if (isPending(thunk)(action)) {
203 expectTypeOf(action.payload).toBeUndefined()
204
205 expectTypeOf(action).not.toHaveProperty('error')
206 }
207 })
208
209 test('isRejected correctly narrows types', () => {
210 if (isRejected(action)) {
211 // might be there if rejected with payload
212 expectTypeOf(action.payload).toBeUnknown()
213
214 expectTypeOf(action.error).toEqualTypeOf<SerializedError>()
215 }
216
217 const thunk = createAsyncThunk<string>('a', () => 'result')
218
219 if (isRejected(thunk)(action)) {
220 // might be there if rejected with payload
221 expectTypeOf(action.payload).toBeUnknown()
222
223 expectTypeOf(action.error).toEqualTypeOf<SerializedError>()
224 }
225 })
226
227 test('isFulfilled correctly narrows types', () => {
228 if (isFulfilled(action)) {
229 expectTypeOf(action.payload).toBeUnknown()
230
231 expectTypeOf(action).not.toHaveProperty('error')
232 }
233
234 const thunk = createAsyncThunk<string>('a', () => 'result')
235 if (isFulfilled(thunk)(action)) {
236 expectTypeOf(action.payload).toBeString()
237
238 expectTypeOf(action).not.toHaveProperty('error')
239 }
240 })
241
242 test('isAsyncThunkAction correctly narrows types', () => {
243 if (isAsyncThunkAction(action)) {
244 expectTypeOf(action.payload).toBeUnknown()
245
246 // do not expect an error property because pending/fulfilled lack it
247 expectTypeOf(action).not.toHaveProperty('error')
248 }
249
250 const thunk = createAsyncThunk<string>('a', () => 'result')
251 if (isAsyncThunkAction(thunk)(action)) {
252 // we should expect the payload to be available, but of unknown type because the action may be pending/rejected
253 expectTypeOf(action.payload).toBeUnknown()
254
255 // do not expect an error property because pending/fulfilled lack it
256 expectTypeOf(action).not.toHaveProperty('error')
257 }
258 })
259
260 test('isRejectedWithValue correctly narrows types', () => {
261 if (isRejectedWithValue(action)) {
262 expectTypeOf(action.payload).toBeUnknown()
263
264 expectTypeOf(action.error).toEqualTypeOf<SerializedError>()
265 }
266
267 const thunk = createAsyncThunk<
268 string,
269 void,
270 { rejectValue: { message: string } }
271 >('a', () => 'result')
272 if (isRejectedWithValue(thunk)(action)) {
273 expectTypeOf(action.payload).toEqualTypeOf({ message: '' as string })
274
275 expectTypeOf(action.error).toEqualTypeOf<SerializedError>()
276 }
277 })
278 })
279
280 test('matchersAcceptSpreadArguments', () => {
281 const thunk1 = createAsyncThunk('a', () => 'a')
282 const thunk2 = createAsyncThunk('b', () => 'b')
283 const interestingThunks = [thunk1, thunk2]
284 const interestingPendingThunks = interestingThunks.map(
285 (thunk) => thunk.pending,
286 )
287 const interestingFulfilledThunks = interestingThunks.map(
288 (thunk) => thunk.fulfilled,
289 )
290
291 const isLoading = isAnyOf(...interestingPendingThunks)
292 const isNotLoading = isAnyOf(...interestingFulfilledThunks)
293
294 const isAllLoading = isAllOf(...interestingPendingThunks)
295 })
296})
Note: See TracBrowser for help on using the repository browser.