source: node_modules/@reduxjs/toolkit/src/tests/createAction.test-d.tsx

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

Added visualizations

  • Property mode set to 100644
File size: 9.3 KB
Line 
1import type {
2 Action,
3 ActionCreator,
4 ActionCreatorWithNonInferrablePayload,
5 ActionCreatorWithOptionalPayload,
6 ActionCreatorWithPayload,
7 ActionCreatorWithPreparedPayload,
8 ActionCreatorWithoutPayload,
9 PayloadAction,
10 PayloadActionCreator,
11 UnknownAction,
12} from '@reduxjs/toolkit'
13import { createAction } from '@reduxjs/toolkit'
14
15describe('type tests', () => {
16 describe('PayloadAction', () => {
17 test('PayloadAction has type parameter for the payload.', () => {
18 const action: PayloadAction<number> = { type: '', payload: 5 }
19
20 expectTypeOf(action.payload).toBeNumber()
21
22 expectTypeOf(action.payload).not.toBeString()
23 })
24
25 test('PayloadAction type parameter is required.', () => {
26 expectTypeOf({ type: '', payload: 5 }).not.toMatchTypeOf<PayloadAction>()
27 })
28
29 test('PayloadAction has a string type tag.', () => {
30 expectTypeOf({ type: '', payload: 5 }).toEqualTypeOf<
31 PayloadAction<number>
32 >()
33
34 expectTypeOf({ type: 1, payload: 5 }).not.toMatchTypeOf<PayloadAction>()
35 })
36
37 test('PayloadAction is compatible with Action<string>', () => {
38 const action: PayloadAction<number> = { type: '', payload: 5 }
39
40 expectTypeOf(action).toMatchTypeOf<Action<string>>()
41 })
42 })
43
44 describe('PayloadActionCreator', () => {
45 test('PayloadActionCreator returns correctly typed PayloadAction depending on whether a payload is passed.', () => {
46 const actionCreator = Object.assign(
47 (payload?: number) => ({
48 type: 'action',
49 payload,
50 }),
51 { type: 'action' },
52 ) as PayloadActionCreator<number | undefined>
53
54 expectTypeOf(actionCreator(1)).toEqualTypeOf<
55 PayloadAction<number | undefined>
56 >()
57
58 expectTypeOf(actionCreator()).toEqualTypeOf<
59 PayloadAction<number | undefined>
60 >()
61
62 expectTypeOf(actionCreator(undefined)).toEqualTypeOf<
63 PayloadAction<number | undefined>
64 >()
65
66 expectTypeOf(actionCreator()).not.toMatchTypeOf<PayloadAction<number>>()
67
68 expectTypeOf(actionCreator(1)).not.toMatchTypeOf<
69 PayloadAction<undefined>
70 >()
71 })
72
73 test('PayloadActionCreator is compatible with ActionCreator.', () => {
74 const payloadActionCreator = Object.assign(
75 (payload?: number) => ({
76 type: 'action',
77 payload,
78 }),
79 { type: 'action' },
80 ) as PayloadActionCreator
81
82 expectTypeOf(payloadActionCreator).toMatchTypeOf<
83 ActionCreator<UnknownAction>
84 >()
85
86 const payloadActionCreator2 = Object.assign(
87 (payload?: number) => ({
88 type: 'action',
89 payload: payload || 1,
90 }),
91 { type: 'action' },
92 ) as PayloadActionCreator<number>
93
94 expectTypeOf(payloadActionCreator2).toMatchTypeOf<
95 ActionCreator<PayloadAction<number>>
96 >()
97 })
98 })
99
100 test('createAction() has type parameter for the action payload.', () => {
101 const increment = createAction<number, 'increment'>('increment')
102
103 expectTypeOf(increment).parameter(0).toBeNumber()
104
105 expectTypeOf(increment).parameter(0).not.toBeString()
106 })
107
108 test('createAction() type parameter is required, not inferred (defaults to `void`).', () => {
109 const increment = createAction('increment')
110
111 expectTypeOf(increment).parameter(0).not.toBeNumber()
112
113 expectTypeOf(increment().payload).not.toBeNumber()
114 })
115
116 test('createAction().type is a string literal.', () => {
117 const increment = createAction<number, 'increment'>('increment')
118
119 expectTypeOf(increment(1).type).toBeString()
120
121 expectTypeOf(increment(1).type).toEqualTypeOf<'increment'>()
122
123 expectTypeOf(increment(1).type).not.toMatchTypeOf<'other'>()
124
125 expectTypeOf(increment(1).type).not.toBeNumber()
126 })
127
128 test('type still present when using prepareAction', () => {
129 const strLenAction = createAction('strLen', (payload: string) => ({
130 payload: payload.length,
131 }))
132
133 expectTypeOf(strLenAction('test').type).toBeString()
134 })
135
136 test('changing payload type with prepareAction', () => {
137 const strLenAction = createAction('strLen', (payload: string) => ({
138 payload: payload.length,
139 }))
140
141 expectTypeOf(strLenAction('test').payload).toBeNumber()
142
143 expectTypeOf(strLenAction('test').payload).not.toBeString()
144
145 expectTypeOf(strLenAction('test')).not.toHaveProperty('error')
146 })
147
148 test('adding metadata with prepareAction', () => {
149 const strLenMetaAction = createAction('strLenMeta', (payload: string) => ({
150 payload,
151 meta: payload.length,
152 }))
153
154 expectTypeOf(strLenMetaAction('test').meta).toBeNumber()
155
156 expectTypeOf(strLenMetaAction('test').meta).not.toBeString()
157
158 expectTypeOf(strLenMetaAction('test')).not.toHaveProperty('error')
159 })
160
161 test('adding boolean error with prepareAction', () => {
162 const boolErrorAction = createAction('boolError', (payload: string) => ({
163 payload,
164 error: true,
165 }))
166
167 expectTypeOf(boolErrorAction('test').error).toBeBoolean()
168
169 expectTypeOf(boolErrorAction('test').error).not.toBeString()
170 })
171
172 test('adding string error with prepareAction', () => {
173 const strErrorAction = createAction('strError', (payload: string) => ({
174 payload,
175 error: 'this is an error',
176 }))
177
178 expectTypeOf(strErrorAction('test').error).toBeString()
179
180 expectTypeOf(strErrorAction('test').error).not.toBeBoolean()
181 })
182
183 test('regression test for https://github.com/reduxjs/redux-toolkit/issues/214', () => {
184 const action = createAction<{ input?: string }>('ACTION')
185
186 expectTypeOf(action({ input: '' }).payload.input).toEqualTypeOf<
187 string | undefined
188 >()
189
190 expectTypeOf(action({ input: '' }).payload.input).not.toBeNumber()
191
192 expectTypeOf(action).parameter(0).not.toMatchTypeOf({ input: 3 })
193 })
194
195 test('regression test for https://github.com/reduxjs/redux-toolkit/issues/224', () => {
196 const oops = createAction('oops', (x: any) => ({
197 payload: x,
198 error: x,
199 meta: x,
200 }))
201
202 expectTypeOf(oops('').payload).toBeAny()
203
204 expectTypeOf(oops('').error).toBeAny()
205
206 expectTypeOf(oops('').meta).toBeAny()
207 })
208
209 describe('createAction.match()', () => {
210 test('simple use case', () => {
211 const actionCreator = createAction<string, 'test'>('test')
212
213 const x: Action<string> = {} as any
214
215 if (actionCreator.match(x)) {
216 expectTypeOf(x.type).toEqualTypeOf<'test'>()
217
218 expectTypeOf(x.payload).toBeString()
219 } else {
220 expectTypeOf(x.type).not.toMatchTypeOf<'test'>()
221
222 expectTypeOf(x).not.toHaveProperty('payload')
223 }
224 })
225
226 test('special case: optional argument', () => {
227 const actionCreator = createAction<string | undefined, 'test'>('test')
228
229 const x: Action<string> = {} as any
230
231 if (actionCreator.match(x)) {
232 expectTypeOf(x.type).toEqualTypeOf<'test'>()
233
234 expectTypeOf(x.payload).toEqualTypeOf<string | undefined>()
235 }
236 })
237
238 test('special case: without argument', () => {
239 const actionCreator = createAction('test')
240
241 const x: Action<string> = {} as any
242
243 if (actionCreator.match(x)) {
244 expectTypeOf(x.type).toEqualTypeOf<'test'>()
245
246 expectTypeOf(x.payload).not.toMatchTypeOf<{}>()
247 }
248 })
249
250 test('special case: with prepareAction', () => {
251 const actionCreator = createAction('test', () => ({
252 payload: '',
253 meta: '',
254 error: false,
255 }))
256
257 const x: Action<string> = {} as any
258
259 if (actionCreator.match(x)) {
260 expectTypeOf(x.type).toEqualTypeOf<'test'>()
261
262 expectTypeOf(x.payload).toBeString()
263
264 expectTypeOf(x.meta).toBeString()
265
266 expectTypeOf(x.error).toBeBoolean()
267
268 expectTypeOf(x.payload).not.toBeNumber()
269
270 expectTypeOf(x.meta).not.toBeNumber()
271
272 expectTypeOf(x.error).not.toBeNumber()
273 }
274 })
275 test('potential use: as array filter', () => {
276 const actionCreator = createAction<string, 'test'>('test')
277
278 const x: Action<string>[] = []
279
280 expectTypeOf(x.filter(actionCreator.match)).toEqualTypeOf<
281 PayloadAction<string, 'test'>[]
282 >()
283 })
284 })
285
286 test('ActionCreatorWithOptionalPayload', () => {
287 expectTypeOf(createAction<string | undefined>('')).toEqualTypeOf<
288 ActionCreatorWithOptionalPayload<string | undefined>
289 >()
290
291 expectTypeOf(
292 createAction<void>(''),
293 ).toEqualTypeOf<ActionCreatorWithoutPayload>()
294
295 assertType<ActionCreatorWithNonInferrablePayload>(createAction(''))
296
297 expectTypeOf(createAction<string>('')).toEqualTypeOf<
298 ActionCreatorWithPayload<string>
299 >()
300
301 expectTypeOf(
302 createAction('', (_: 0) => ({
303 payload: 1 as 1,
304 error: 2 as 2,
305 meta: 3 as 3,
306 })),
307 ).toEqualTypeOf<ActionCreatorWithPreparedPayload<[0], 1, '', 2, 3>>()
308
309 const anyCreator = createAction<any>('')
310
311 expectTypeOf(anyCreator).toEqualTypeOf<ActionCreatorWithPayload<any>>()
312
313 expectTypeOf(anyCreator({}).payload).toBeAny()
314 })
315
316 test("Verify action creators should not be passed directly as arguments to React event handlers if there shouldn't be a payload", () => {
317 const emptyAction = createAction<void>('empty/action')
318
319 function TestComponent() {
320 // This typically leads to an error like:
321 // // A non-serializable value was detected in an action, in the path: `payload`.
322 // @ts-expect-error Should error because `void` and `MouseEvent` aren't compatible
323 return <button onClick={emptyAction}>+</button>
324 }
325 })
326})
Note: See TracBrowser for help on using the repository browser.