@tanstack/query-core 5.59.16 → 5.59.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/legacy/queriesObserver.cjs +8 -0
- package/build/legacy/queriesObserver.cjs.map +1 -1
- package/build/legacy/queriesObserver.js +8 -0
- package/build/legacy/queriesObserver.js.map +1 -1
- package/build/modern/queriesObserver.cjs +8 -0
- package/build/modern/queriesObserver.cjs.map +1 -1
- package/build/modern/queriesObserver.js +8 -0
- package/build/modern/queriesObserver.js.map +1 -1
- package/package.json +3 -2
- package/src/queriesObserver.ts +9 -0
- package/src/__tests__/OmitKeyof.test-d.ts +0 -175
- package/src/__tests__/focusManager.test.tsx +0 -163
- package/src/__tests__/hydration.test.tsx +0 -1069
- package/src/__tests__/infiniteQueryBehavior.test.tsx +0 -427
- package/src/__tests__/infiniteQueryObserver.test-d.tsx +0 -64
- package/src/__tests__/infiniteQueryObserver.test.tsx +0 -198
- package/src/__tests__/mutationCache.test.tsx +0 -376
- package/src/__tests__/mutationObserver.test.tsx +0 -326
- package/src/__tests__/mutations.test.tsx +0 -603
- package/src/__tests__/notifyManager.test.tsx +0 -85
- package/src/__tests__/onlineManager.test.tsx +0 -168
- package/src/__tests__/queriesObserver.test.tsx +0 -267
- package/src/__tests__/query.test.tsx +0 -1049
- package/src/__tests__/queryCache.test.tsx +0 -350
- package/src/__tests__/queryClient.test-d.tsx +0 -156
- package/src/__tests__/queryClient.test.tsx +0 -2031
- package/src/__tests__/queryObserver.test-d.tsx +0 -108
- package/src/__tests__/queryObserver.test.tsx +0 -1236
- package/src/__tests__/utils.test.tsx +0 -468
- package/src/__tests__/utils.ts +0 -59
|
@@ -1,603 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
|
|
2
|
-
import { waitFor } from '@testing-library/react'
|
|
3
|
-
import { MutationObserver } from '../mutationObserver'
|
|
4
|
-
import { createQueryClient, executeMutation, queryKey, sleep } from './utils'
|
|
5
|
-
import type { QueryClient } from '..'
|
|
6
|
-
import type { MutationState } from '../mutation'
|
|
7
|
-
|
|
8
|
-
describe('mutations', () => {
|
|
9
|
-
let queryClient: QueryClient
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
queryClient = createQueryClient()
|
|
13
|
-
queryClient.mount()
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
queryClient.clear()
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test('mutate should accept null values', async () => {
|
|
21
|
-
let variables
|
|
22
|
-
|
|
23
|
-
const mutation = new MutationObserver(queryClient, {
|
|
24
|
-
mutationFn: async (vars: unknown) => {
|
|
25
|
-
variables = vars
|
|
26
|
-
return vars
|
|
27
|
-
},
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
await mutation.mutate(null)
|
|
31
|
-
|
|
32
|
-
expect(variables).toBe(null)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('setMutationDefaults should be able to set defaults', async () => {
|
|
36
|
-
const key = queryKey()
|
|
37
|
-
const fn = vi.fn()
|
|
38
|
-
|
|
39
|
-
queryClient.setMutationDefaults(key, {
|
|
40
|
-
mutationFn: fn,
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
await executeMutation(
|
|
44
|
-
queryClient,
|
|
45
|
-
{
|
|
46
|
-
mutationKey: key,
|
|
47
|
-
},
|
|
48
|
-
'vars',
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
expect(fn).toHaveBeenCalledTimes(1)
|
|
52
|
-
expect(fn).toHaveBeenCalledWith('vars')
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test('mutation should set correct success states', async () => {
|
|
56
|
-
const mutation = new MutationObserver(queryClient, {
|
|
57
|
-
mutationFn: async (text: string) => {
|
|
58
|
-
await sleep(10)
|
|
59
|
-
return text
|
|
60
|
-
},
|
|
61
|
-
onMutate: (text) => text,
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
expect(mutation.getCurrentResult()).toEqual({
|
|
65
|
-
context: undefined,
|
|
66
|
-
data: undefined,
|
|
67
|
-
error: null,
|
|
68
|
-
failureCount: 0,
|
|
69
|
-
failureReason: null,
|
|
70
|
-
isError: false,
|
|
71
|
-
isIdle: true,
|
|
72
|
-
isPending: false,
|
|
73
|
-
isPaused: false,
|
|
74
|
-
isSuccess: false,
|
|
75
|
-
mutate: expect.any(Function),
|
|
76
|
-
reset: expect.any(Function),
|
|
77
|
-
status: 'idle',
|
|
78
|
-
variables: undefined,
|
|
79
|
-
submittedAt: 0,
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
const states: Array<MutationState<string, unknown, string, string>> = []
|
|
83
|
-
|
|
84
|
-
mutation.subscribe((state) => {
|
|
85
|
-
states.push(state)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
mutation.mutate('todo')
|
|
89
|
-
|
|
90
|
-
await sleep(0)
|
|
91
|
-
|
|
92
|
-
expect(states[0]).toEqual({
|
|
93
|
-
context: undefined,
|
|
94
|
-
data: undefined,
|
|
95
|
-
error: null,
|
|
96
|
-
failureCount: 0,
|
|
97
|
-
failureReason: null,
|
|
98
|
-
isError: false,
|
|
99
|
-
isIdle: false,
|
|
100
|
-
isPending: true,
|
|
101
|
-
isPaused: false,
|
|
102
|
-
isSuccess: false,
|
|
103
|
-
mutate: expect.any(Function),
|
|
104
|
-
reset: expect.any(Function),
|
|
105
|
-
status: 'pending',
|
|
106
|
-
variables: 'todo',
|
|
107
|
-
submittedAt: expect.any(Number),
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
await sleep(5)
|
|
111
|
-
|
|
112
|
-
expect(states[1]).toEqual({
|
|
113
|
-
context: 'todo',
|
|
114
|
-
data: undefined,
|
|
115
|
-
error: null,
|
|
116
|
-
failureCount: 0,
|
|
117
|
-
failureReason: null,
|
|
118
|
-
isError: false,
|
|
119
|
-
isIdle: false,
|
|
120
|
-
isPending: true,
|
|
121
|
-
isPaused: false,
|
|
122
|
-
isSuccess: false,
|
|
123
|
-
mutate: expect.any(Function),
|
|
124
|
-
reset: expect.any(Function),
|
|
125
|
-
status: 'pending',
|
|
126
|
-
variables: 'todo',
|
|
127
|
-
submittedAt: expect.any(Number),
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
await sleep(20)
|
|
131
|
-
|
|
132
|
-
expect(states[2]).toEqual({
|
|
133
|
-
context: 'todo',
|
|
134
|
-
data: 'todo',
|
|
135
|
-
error: null,
|
|
136
|
-
failureCount: 0,
|
|
137
|
-
failureReason: null,
|
|
138
|
-
isError: false,
|
|
139
|
-
isIdle: false,
|
|
140
|
-
isPending: false,
|
|
141
|
-
isPaused: false,
|
|
142
|
-
isSuccess: true,
|
|
143
|
-
mutate: expect.any(Function),
|
|
144
|
-
reset: expect.any(Function),
|
|
145
|
-
status: 'success',
|
|
146
|
-
variables: 'todo',
|
|
147
|
-
submittedAt: expect.any(Number),
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
test('mutation should set correct error states', async () => {
|
|
152
|
-
const mutation = new MutationObserver(queryClient, {
|
|
153
|
-
mutationFn: async (_: string) => {
|
|
154
|
-
await sleep(20)
|
|
155
|
-
return Promise.reject(new Error('err'))
|
|
156
|
-
},
|
|
157
|
-
onMutate: (text) => text,
|
|
158
|
-
retry: 1,
|
|
159
|
-
retryDelay: 1,
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
const states: Array<MutationState<string, unknown, string, string>> = []
|
|
163
|
-
|
|
164
|
-
mutation.subscribe((state) => {
|
|
165
|
-
states.push(state)
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
mutation.mutate('todo').catch(() => undefined)
|
|
169
|
-
|
|
170
|
-
await sleep(0)
|
|
171
|
-
|
|
172
|
-
expect(states[0]).toEqual({
|
|
173
|
-
context: undefined,
|
|
174
|
-
data: undefined,
|
|
175
|
-
error: null,
|
|
176
|
-
failureCount: 0,
|
|
177
|
-
failureReason: null,
|
|
178
|
-
isError: false,
|
|
179
|
-
isIdle: false,
|
|
180
|
-
isPending: true,
|
|
181
|
-
isPaused: false,
|
|
182
|
-
isSuccess: false,
|
|
183
|
-
mutate: expect.any(Function),
|
|
184
|
-
reset: expect.any(Function),
|
|
185
|
-
status: 'pending',
|
|
186
|
-
variables: 'todo',
|
|
187
|
-
submittedAt: expect.any(Number),
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
await sleep(10)
|
|
191
|
-
|
|
192
|
-
expect(states[1]).toEqual({
|
|
193
|
-
context: 'todo',
|
|
194
|
-
data: undefined,
|
|
195
|
-
error: null,
|
|
196
|
-
failureCount: 0,
|
|
197
|
-
failureReason: null,
|
|
198
|
-
isError: false,
|
|
199
|
-
isIdle: false,
|
|
200
|
-
isPending: true,
|
|
201
|
-
isPaused: false,
|
|
202
|
-
isSuccess: false,
|
|
203
|
-
mutate: expect.any(Function),
|
|
204
|
-
reset: expect.any(Function),
|
|
205
|
-
status: 'pending',
|
|
206
|
-
variables: 'todo',
|
|
207
|
-
submittedAt: expect.any(Number),
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
await sleep(20)
|
|
211
|
-
|
|
212
|
-
expect(states[2]).toEqual({
|
|
213
|
-
context: 'todo',
|
|
214
|
-
data: undefined,
|
|
215
|
-
error: null,
|
|
216
|
-
failureCount: 1,
|
|
217
|
-
failureReason: new Error('err'),
|
|
218
|
-
isError: false,
|
|
219
|
-
isIdle: false,
|
|
220
|
-
isPending: true,
|
|
221
|
-
isPaused: false,
|
|
222
|
-
isSuccess: false,
|
|
223
|
-
mutate: expect.any(Function),
|
|
224
|
-
reset: expect.any(Function),
|
|
225
|
-
status: 'pending',
|
|
226
|
-
variables: 'todo',
|
|
227
|
-
submittedAt: expect.any(Number),
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
await sleep(30)
|
|
231
|
-
|
|
232
|
-
expect(states[3]).toEqual({
|
|
233
|
-
context: 'todo',
|
|
234
|
-
data: undefined,
|
|
235
|
-
error: new Error('err'),
|
|
236
|
-
failureCount: 2,
|
|
237
|
-
failureReason: new Error('err'),
|
|
238
|
-
isError: true,
|
|
239
|
-
isIdle: false,
|
|
240
|
-
isPending: false,
|
|
241
|
-
isPaused: false,
|
|
242
|
-
isSuccess: false,
|
|
243
|
-
mutate: expect.any(Function),
|
|
244
|
-
reset: expect.any(Function),
|
|
245
|
-
status: 'error',
|
|
246
|
-
variables: 'todo',
|
|
247
|
-
submittedAt: expect.any(Number),
|
|
248
|
-
})
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
test('should be able to restore a mutation', async () => {
|
|
252
|
-
const key = queryKey()
|
|
253
|
-
|
|
254
|
-
const onMutate = vi.fn()
|
|
255
|
-
const onSuccess = vi.fn()
|
|
256
|
-
const onSettled = vi.fn()
|
|
257
|
-
|
|
258
|
-
queryClient.setMutationDefaults(key, {
|
|
259
|
-
mutationFn: async (text: string) => text,
|
|
260
|
-
onMutate,
|
|
261
|
-
onSuccess,
|
|
262
|
-
onSettled,
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
const mutation = queryClient
|
|
266
|
-
.getMutationCache()
|
|
267
|
-
.build<string, unknown, string, string>(
|
|
268
|
-
queryClient,
|
|
269
|
-
{
|
|
270
|
-
mutationKey: key,
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
context: 'todo',
|
|
274
|
-
data: undefined,
|
|
275
|
-
error: null,
|
|
276
|
-
failureCount: 1,
|
|
277
|
-
failureReason: 'err',
|
|
278
|
-
isPaused: true,
|
|
279
|
-
status: 'pending',
|
|
280
|
-
variables: 'todo',
|
|
281
|
-
submittedAt: 1,
|
|
282
|
-
},
|
|
283
|
-
)
|
|
284
|
-
|
|
285
|
-
expect(mutation.state).toEqual({
|
|
286
|
-
context: 'todo',
|
|
287
|
-
data: undefined,
|
|
288
|
-
error: null,
|
|
289
|
-
failureCount: 1,
|
|
290
|
-
failureReason: 'err',
|
|
291
|
-
isPaused: true,
|
|
292
|
-
status: 'pending',
|
|
293
|
-
variables: 'todo',
|
|
294
|
-
submittedAt: 1,
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
await queryClient.resumePausedMutations()
|
|
298
|
-
|
|
299
|
-
expect(mutation.state).toEqual({
|
|
300
|
-
context: 'todo',
|
|
301
|
-
data: 'todo',
|
|
302
|
-
error: null,
|
|
303
|
-
failureCount: 0,
|
|
304
|
-
failureReason: null,
|
|
305
|
-
isPaused: false,
|
|
306
|
-
status: 'success',
|
|
307
|
-
variables: 'todo',
|
|
308
|
-
submittedAt: 1,
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
expect(onMutate).not.toHaveBeenCalled()
|
|
312
|
-
expect(onSuccess).toHaveBeenCalled()
|
|
313
|
-
expect(onSettled).toHaveBeenCalled()
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
test('addObserver should not add an existing observer', async () => {
|
|
317
|
-
const mutationCache = queryClient.getMutationCache()
|
|
318
|
-
const observer = new MutationObserver(queryClient, {})
|
|
319
|
-
const currentMutation = mutationCache.build(queryClient, {})
|
|
320
|
-
|
|
321
|
-
const fn = vi.fn()
|
|
322
|
-
|
|
323
|
-
const unsubscribe = mutationCache.subscribe((event) => {
|
|
324
|
-
fn(event.type)
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
currentMutation.addObserver(observer)
|
|
328
|
-
currentMutation.addObserver(observer)
|
|
329
|
-
|
|
330
|
-
expect(fn).toHaveBeenCalledTimes(1)
|
|
331
|
-
expect(fn).toHaveBeenCalledWith('observerAdded')
|
|
332
|
-
|
|
333
|
-
unsubscribe()
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
test('mutate should throw an error if no mutationFn found', async () => {
|
|
337
|
-
const mutation = new MutationObserver(queryClient, {
|
|
338
|
-
mutationFn: undefined,
|
|
339
|
-
retry: false,
|
|
340
|
-
})
|
|
341
|
-
|
|
342
|
-
let error: any
|
|
343
|
-
try {
|
|
344
|
-
await mutation.mutate()
|
|
345
|
-
} catch (err) {
|
|
346
|
-
error = err
|
|
347
|
-
}
|
|
348
|
-
expect(error).toEqual(new Error('No mutationFn found'))
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
test('mutate update the mutation state even without an active subscription 1', async () => {
|
|
352
|
-
const onSuccess = vi.fn()
|
|
353
|
-
const onSettled = vi.fn()
|
|
354
|
-
|
|
355
|
-
const mutation = new MutationObserver(queryClient, {
|
|
356
|
-
mutationFn: async () => {
|
|
357
|
-
return 'update'
|
|
358
|
-
},
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
await mutation.mutate(undefined, { onSuccess, onSettled })
|
|
362
|
-
expect(mutation.getCurrentResult().data).toEqual('update')
|
|
363
|
-
expect(onSuccess).not.toHaveBeenCalled()
|
|
364
|
-
expect(onSettled).not.toHaveBeenCalled()
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
test('mutate update the mutation state even without an active subscription 2', async () => {
|
|
368
|
-
const onSuccess = vi.fn()
|
|
369
|
-
const onSettled = vi.fn()
|
|
370
|
-
|
|
371
|
-
const mutation = new MutationObserver(queryClient, {
|
|
372
|
-
mutationFn: async () => {
|
|
373
|
-
return 'update'
|
|
374
|
-
},
|
|
375
|
-
})
|
|
376
|
-
|
|
377
|
-
await mutation.mutate(undefined, { onSuccess, onSettled })
|
|
378
|
-
expect(mutation.getCurrentResult().data).toEqual('update')
|
|
379
|
-
expect(onSuccess).not.toHaveBeenCalled()
|
|
380
|
-
expect(onSettled).not.toHaveBeenCalled()
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
test('mutation callbacks should see updated options', async () => {
|
|
384
|
-
const onSuccess = vi.fn()
|
|
385
|
-
|
|
386
|
-
const mutation = new MutationObserver(queryClient, {
|
|
387
|
-
mutationFn: async () => {
|
|
388
|
-
sleep(100)
|
|
389
|
-
return 'update'
|
|
390
|
-
},
|
|
391
|
-
onSuccess: () => {
|
|
392
|
-
onSuccess(1)
|
|
393
|
-
},
|
|
394
|
-
})
|
|
395
|
-
|
|
396
|
-
void mutation.mutate()
|
|
397
|
-
|
|
398
|
-
mutation.setOptions({
|
|
399
|
-
mutationFn: async () => {
|
|
400
|
-
sleep(100)
|
|
401
|
-
return 'update'
|
|
402
|
-
},
|
|
403
|
-
onSuccess: () => {
|
|
404
|
-
onSuccess(2)
|
|
405
|
-
},
|
|
406
|
-
})
|
|
407
|
-
|
|
408
|
-
await waitFor(() => expect(onSuccess).toHaveBeenCalledTimes(1))
|
|
409
|
-
|
|
410
|
-
expect(onSuccess).toHaveBeenCalledWith(2)
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
describe('scoped mutations', () => {
|
|
414
|
-
test('mutations in the same scope should run in serial', async () => {
|
|
415
|
-
const key1 = queryKey()
|
|
416
|
-
const key2 = queryKey()
|
|
417
|
-
|
|
418
|
-
const results: Array<string> = []
|
|
419
|
-
|
|
420
|
-
const execute1 = executeMutation(
|
|
421
|
-
queryClient,
|
|
422
|
-
{
|
|
423
|
-
mutationKey: key1,
|
|
424
|
-
scope: {
|
|
425
|
-
id: 'scope',
|
|
426
|
-
},
|
|
427
|
-
mutationFn: async () => {
|
|
428
|
-
results.push('start-A')
|
|
429
|
-
await sleep(10)
|
|
430
|
-
results.push('finish-A')
|
|
431
|
-
return 'a'
|
|
432
|
-
},
|
|
433
|
-
},
|
|
434
|
-
'vars1',
|
|
435
|
-
)
|
|
436
|
-
|
|
437
|
-
expect(
|
|
438
|
-
queryClient.getMutationCache().find({ mutationKey: key1 })?.state,
|
|
439
|
-
).toMatchObject({
|
|
440
|
-
status: 'pending',
|
|
441
|
-
isPaused: false,
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
const execute2 = executeMutation(
|
|
445
|
-
queryClient,
|
|
446
|
-
{
|
|
447
|
-
mutationKey: key2,
|
|
448
|
-
scope: {
|
|
449
|
-
id: 'scope',
|
|
450
|
-
},
|
|
451
|
-
mutationFn: async () => {
|
|
452
|
-
results.push('start-B')
|
|
453
|
-
await sleep(10)
|
|
454
|
-
results.push('finish-B')
|
|
455
|
-
return 'b'
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
'vars2',
|
|
459
|
-
)
|
|
460
|
-
|
|
461
|
-
expect(
|
|
462
|
-
queryClient.getMutationCache().find({ mutationKey: key2 })?.state,
|
|
463
|
-
).toMatchObject({
|
|
464
|
-
status: 'pending',
|
|
465
|
-
isPaused: true,
|
|
466
|
-
})
|
|
467
|
-
|
|
468
|
-
await Promise.all([execute1, execute2])
|
|
469
|
-
|
|
470
|
-
expect(results).toStrictEqual([
|
|
471
|
-
'start-A',
|
|
472
|
-
'finish-A',
|
|
473
|
-
'start-B',
|
|
474
|
-
'finish-B',
|
|
475
|
-
])
|
|
476
|
-
})
|
|
477
|
-
})
|
|
478
|
-
|
|
479
|
-
test('mutations without scope should run in parallel', async () => {
|
|
480
|
-
const key1 = queryKey()
|
|
481
|
-
const key2 = queryKey()
|
|
482
|
-
|
|
483
|
-
const results: Array<string> = []
|
|
484
|
-
|
|
485
|
-
const execute1 = executeMutation(
|
|
486
|
-
queryClient,
|
|
487
|
-
{
|
|
488
|
-
mutationKey: key1,
|
|
489
|
-
mutationFn: async () => {
|
|
490
|
-
results.push('start-A')
|
|
491
|
-
await sleep(10)
|
|
492
|
-
results.push('finish-A')
|
|
493
|
-
return 'a'
|
|
494
|
-
},
|
|
495
|
-
},
|
|
496
|
-
'vars1',
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
const execute2 = executeMutation(
|
|
500
|
-
queryClient,
|
|
501
|
-
{
|
|
502
|
-
mutationKey: key2,
|
|
503
|
-
mutationFn: async () => {
|
|
504
|
-
results.push('start-B')
|
|
505
|
-
await sleep(10)
|
|
506
|
-
results.push('finish-B')
|
|
507
|
-
return 'b'
|
|
508
|
-
},
|
|
509
|
-
},
|
|
510
|
-
'vars2',
|
|
511
|
-
)
|
|
512
|
-
|
|
513
|
-
await Promise.all([execute1, execute2])
|
|
514
|
-
|
|
515
|
-
expect(results).toStrictEqual([
|
|
516
|
-
'start-A',
|
|
517
|
-
'start-B',
|
|
518
|
-
'finish-A',
|
|
519
|
-
'finish-B',
|
|
520
|
-
])
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
test('each scope should run should run in parallel, serial within scope', async () => {
|
|
524
|
-
const results: Array<string> = []
|
|
525
|
-
|
|
526
|
-
const execute1 = executeMutation(
|
|
527
|
-
queryClient,
|
|
528
|
-
{
|
|
529
|
-
scope: {
|
|
530
|
-
id: '1',
|
|
531
|
-
},
|
|
532
|
-
mutationFn: async () => {
|
|
533
|
-
results.push('start-A1')
|
|
534
|
-
await sleep(10)
|
|
535
|
-
results.push('finish-A1')
|
|
536
|
-
return 'a'
|
|
537
|
-
},
|
|
538
|
-
},
|
|
539
|
-
'vars1',
|
|
540
|
-
)
|
|
541
|
-
|
|
542
|
-
const execute2 = executeMutation(
|
|
543
|
-
queryClient,
|
|
544
|
-
{
|
|
545
|
-
scope: {
|
|
546
|
-
id: '1',
|
|
547
|
-
},
|
|
548
|
-
mutationFn: async () => {
|
|
549
|
-
results.push('start-B1')
|
|
550
|
-
await sleep(10)
|
|
551
|
-
results.push('finish-B1')
|
|
552
|
-
return 'b'
|
|
553
|
-
},
|
|
554
|
-
},
|
|
555
|
-
'vars2',
|
|
556
|
-
)
|
|
557
|
-
|
|
558
|
-
const execute3 = executeMutation(
|
|
559
|
-
queryClient,
|
|
560
|
-
{
|
|
561
|
-
scope: {
|
|
562
|
-
id: '2',
|
|
563
|
-
},
|
|
564
|
-
mutationFn: async () => {
|
|
565
|
-
results.push('start-A2')
|
|
566
|
-
await sleep(10)
|
|
567
|
-
results.push('finish-A2')
|
|
568
|
-
return 'a'
|
|
569
|
-
},
|
|
570
|
-
},
|
|
571
|
-
'vars1',
|
|
572
|
-
)
|
|
573
|
-
|
|
574
|
-
const execute4 = executeMutation(
|
|
575
|
-
queryClient,
|
|
576
|
-
{
|
|
577
|
-
scope: {
|
|
578
|
-
id: '2',
|
|
579
|
-
},
|
|
580
|
-
mutationFn: async () => {
|
|
581
|
-
results.push('start-B2')
|
|
582
|
-
await sleep(10)
|
|
583
|
-
results.push('finish-B2')
|
|
584
|
-
return 'b'
|
|
585
|
-
},
|
|
586
|
-
},
|
|
587
|
-
'vars2',
|
|
588
|
-
)
|
|
589
|
-
|
|
590
|
-
await Promise.all([execute1, execute2, execute3, execute4])
|
|
591
|
-
|
|
592
|
-
expect(results).toStrictEqual([
|
|
593
|
-
'start-A1',
|
|
594
|
-
'start-A2',
|
|
595
|
-
'finish-A1',
|
|
596
|
-
'start-B1',
|
|
597
|
-
'finish-A2',
|
|
598
|
-
'start-B2',
|
|
599
|
-
'finish-B1',
|
|
600
|
-
'finish-B2',
|
|
601
|
-
])
|
|
602
|
-
})
|
|
603
|
-
})
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
-
import { createNotifyManager } from '../notifyManager'
|
|
3
|
-
import { sleep } from './utils'
|
|
4
|
-
|
|
5
|
-
describe('notifyManager', () => {
|
|
6
|
-
it('should use default notifyFn', async () => {
|
|
7
|
-
const notifyManagerTest = createNotifyManager()
|
|
8
|
-
const callbackSpy = vi.fn()
|
|
9
|
-
notifyManagerTest.schedule(callbackSpy)
|
|
10
|
-
await sleep(1)
|
|
11
|
-
expect(callbackSpy).toHaveBeenCalled()
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('should use default batchNotifyFn', async () => {
|
|
15
|
-
const notifyManagerTest = createNotifyManager()
|
|
16
|
-
const callbackScheduleSpy = vi
|
|
17
|
-
.fn()
|
|
18
|
-
.mockImplementation(async () => await sleep(20))
|
|
19
|
-
const callbackBatchLevel2Spy = vi.fn().mockImplementation(async () => {
|
|
20
|
-
notifyManagerTest.schedule(callbackScheduleSpy)
|
|
21
|
-
})
|
|
22
|
-
const callbackBatchLevel1Spy = vi.fn().mockImplementation(async () => {
|
|
23
|
-
notifyManagerTest.batch(callbackBatchLevel2Spy)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
notifyManagerTest.batch(callbackBatchLevel1Spy)
|
|
27
|
-
|
|
28
|
-
await sleep(30)
|
|
29
|
-
expect(callbackBatchLevel1Spy).toHaveBeenCalledTimes(1)
|
|
30
|
-
expect(callbackBatchLevel2Spy).toHaveBeenCalledTimes(1)
|
|
31
|
-
expect(callbackScheduleSpy).toHaveBeenCalledTimes(1)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('should use a custom scheduler when configured', async () => {
|
|
35
|
-
const customCallback = vi.fn((cb) => queueMicrotask(cb))
|
|
36
|
-
|
|
37
|
-
const notifyManagerTest = createNotifyManager()
|
|
38
|
-
const notifySpy = vi.fn()
|
|
39
|
-
notifyManagerTest.setScheduler(customCallback)
|
|
40
|
-
notifyManagerTest.setNotifyFunction(notifySpy)
|
|
41
|
-
|
|
42
|
-
notifyManagerTest.batch(() => notifyManagerTest.schedule(vi.fn))
|
|
43
|
-
|
|
44
|
-
expect(customCallback).toHaveBeenCalledOnce()
|
|
45
|
-
|
|
46
|
-
// wait until the microtask has run
|
|
47
|
-
await new Promise<void>((res) => queueMicrotask(res))
|
|
48
|
-
|
|
49
|
-
expect(notifySpy).toHaveBeenCalledTimes(1)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('should notify if error is thrown', async () => {
|
|
53
|
-
const notifyManagerTest = createNotifyManager()
|
|
54
|
-
const notifySpy = vi.fn()
|
|
55
|
-
|
|
56
|
-
notifyManagerTest.setNotifyFunction(notifySpy)
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
notifyManagerTest.batch(() => {
|
|
60
|
-
notifyManagerTest.schedule(vi.fn)
|
|
61
|
-
throw new Error('Foo')
|
|
62
|
-
})
|
|
63
|
-
} catch {}
|
|
64
|
-
|
|
65
|
-
// needed for setTimeout to kick in
|
|
66
|
-
await sleep(1)
|
|
67
|
-
|
|
68
|
-
expect(notifySpy).toHaveBeenCalledTimes(1)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('typeDefs should catch proper signatures', async () => {
|
|
72
|
-
const notifyManagerTest = createNotifyManager()
|
|
73
|
-
|
|
74
|
-
// we define some fn with its signature:
|
|
75
|
-
const fn: (a: string, b: number) => string = (a, b) => a + b
|
|
76
|
-
|
|
77
|
-
// now someFn expect to be called with args [a: string, b: number]
|
|
78
|
-
const someFn = notifyManagerTest.batchCalls(fn)
|
|
79
|
-
|
|
80
|
-
someFn('im happy', 4)
|
|
81
|
-
|
|
82
|
-
// @ts-expect-error
|
|
83
|
-
someFn('im not happy', false)
|
|
84
|
-
})
|
|
85
|
-
})
|