@tanstack/query-core 5.59.17 → 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/package.json +3 -2
- 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,1049 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest'
|
|
2
|
-
import { waitFor } from '@testing-library/react'
|
|
3
|
-
import { QueryObserver, dehydrate, hydrate, isCancelledError } from '..'
|
|
4
|
-
import {
|
|
5
|
-
createQueryClient,
|
|
6
|
-
mockOnlineManagerIsOnline,
|
|
7
|
-
mockVisibilityState,
|
|
8
|
-
queryKey,
|
|
9
|
-
setIsServer,
|
|
10
|
-
sleep,
|
|
11
|
-
} from './utils'
|
|
12
|
-
import type {
|
|
13
|
-
QueryCache,
|
|
14
|
-
QueryClient,
|
|
15
|
-
QueryFunctionContext,
|
|
16
|
-
QueryObserverResult,
|
|
17
|
-
} from '..'
|
|
18
|
-
|
|
19
|
-
describe('query', () => {
|
|
20
|
-
let queryClient: QueryClient
|
|
21
|
-
let queryCache: QueryCache
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
queryClient = createQueryClient()
|
|
25
|
-
queryCache = queryClient.getQueryCache()
|
|
26
|
-
queryClient.mount()
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
afterEach(() => {
|
|
30
|
-
queryClient.clear()
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('should use the longest garbage collection time it has seen', async () => {
|
|
34
|
-
const key = queryKey()
|
|
35
|
-
await queryClient.prefetchQuery({
|
|
36
|
-
queryKey: key,
|
|
37
|
-
queryFn: () => 'data',
|
|
38
|
-
gcTime: 100,
|
|
39
|
-
})
|
|
40
|
-
await queryClient.prefetchQuery({
|
|
41
|
-
queryKey: key,
|
|
42
|
-
queryFn: () => 'data',
|
|
43
|
-
gcTime: 200,
|
|
44
|
-
})
|
|
45
|
-
await queryClient.prefetchQuery({
|
|
46
|
-
queryKey: key,
|
|
47
|
-
queryFn: () => 'data',
|
|
48
|
-
gcTime: 10,
|
|
49
|
-
})
|
|
50
|
-
const query = queryCache.find({ queryKey: key })!
|
|
51
|
-
expect(query.gcTime).toBe(200)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should continue retry after focus regain and resolve all promises', async () => {
|
|
55
|
-
const key = queryKey()
|
|
56
|
-
|
|
57
|
-
// make page unfocused
|
|
58
|
-
const visibilityMock = mockVisibilityState('hidden')
|
|
59
|
-
|
|
60
|
-
let count = 0
|
|
61
|
-
let result
|
|
62
|
-
|
|
63
|
-
const promise = queryClient.fetchQuery({
|
|
64
|
-
queryKey: key,
|
|
65
|
-
queryFn: async () => {
|
|
66
|
-
count++
|
|
67
|
-
|
|
68
|
-
if (count === 3) {
|
|
69
|
-
return `data${count}`
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
throw new Error(`error${count}`)
|
|
73
|
-
},
|
|
74
|
-
retry: 3,
|
|
75
|
-
retryDelay: 1,
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
promise.then((data) => {
|
|
79
|
-
result = data
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
// Check if we do not have a result
|
|
83
|
-
expect(result).toBeUndefined()
|
|
84
|
-
|
|
85
|
-
// Check if the query is really paused
|
|
86
|
-
await sleep(50)
|
|
87
|
-
expect(result).toBeUndefined()
|
|
88
|
-
|
|
89
|
-
// Reset visibilityState to original value
|
|
90
|
-
visibilityMock.mockRestore()
|
|
91
|
-
window.dispatchEvent(new Event('visibilitychange'))
|
|
92
|
-
|
|
93
|
-
// There should not be a result yet
|
|
94
|
-
expect(result).toBeUndefined()
|
|
95
|
-
|
|
96
|
-
// By now we should have a value
|
|
97
|
-
await sleep(50)
|
|
98
|
-
expect(result).toBe('data3')
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should continue retry after reconnect and resolve all promises', async () => {
|
|
102
|
-
const key = queryKey()
|
|
103
|
-
|
|
104
|
-
const onlineMock = mockOnlineManagerIsOnline(false)
|
|
105
|
-
|
|
106
|
-
let count = 0
|
|
107
|
-
let result
|
|
108
|
-
|
|
109
|
-
const promise = queryClient.fetchQuery({
|
|
110
|
-
queryKey: key,
|
|
111
|
-
queryFn: async () => {
|
|
112
|
-
count++
|
|
113
|
-
|
|
114
|
-
if (count === 3) {
|
|
115
|
-
return `data${count}`
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
throw new Error(`error${count}`)
|
|
119
|
-
},
|
|
120
|
-
retry: 3,
|
|
121
|
-
retryDelay: 1,
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
promise.then((data) => {
|
|
125
|
-
result = data
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
// Check if we do not have a result
|
|
129
|
-
expect(result).toBeUndefined()
|
|
130
|
-
|
|
131
|
-
// Check if the query is really paused
|
|
132
|
-
await sleep(50)
|
|
133
|
-
expect(result).toBeUndefined()
|
|
134
|
-
|
|
135
|
-
// Reset navigator to original value
|
|
136
|
-
onlineMock.mockReturnValue(true)
|
|
137
|
-
// trigger online event
|
|
138
|
-
queryClient.getQueryCache().onOnline()
|
|
139
|
-
|
|
140
|
-
// There should not be a result yet
|
|
141
|
-
expect(result).toBeUndefined()
|
|
142
|
-
|
|
143
|
-
// Promise should eventually be resolved
|
|
144
|
-
await promise
|
|
145
|
-
|
|
146
|
-
console.log('has finished')
|
|
147
|
-
expect(result).toBe('data3')
|
|
148
|
-
onlineMock.mockRestore()
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should throw a CancelledError when a paused query is cancelled', async () => {
|
|
152
|
-
const key = queryKey()
|
|
153
|
-
|
|
154
|
-
// make page unfocused
|
|
155
|
-
const visibilityMock = mockVisibilityState('hidden')
|
|
156
|
-
|
|
157
|
-
let count = 0
|
|
158
|
-
let result: unknown
|
|
159
|
-
|
|
160
|
-
const promise = queryClient.fetchQuery({
|
|
161
|
-
queryKey: key,
|
|
162
|
-
queryFn: async (): Promise<unknown> => {
|
|
163
|
-
count++
|
|
164
|
-
throw new Error(`error${count}`)
|
|
165
|
-
},
|
|
166
|
-
retry: 3,
|
|
167
|
-
retryDelay: 1,
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
promise.catch((data) => {
|
|
171
|
-
result = data
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
const query = queryCache.find({ queryKey: key })!
|
|
175
|
-
|
|
176
|
-
// Check if the query is really paused
|
|
177
|
-
await sleep(50)
|
|
178
|
-
expect(result).toBeUndefined()
|
|
179
|
-
|
|
180
|
-
// Cancel query
|
|
181
|
-
query.cancel()
|
|
182
|
-
|
|
183
|
-
// Check if the error is set to the cancelled error
|
|
184
|
-
try {
|
|
185
|
-
await promise
|
|
186
|
-
expect.unreachable()
|
|
187
|
-
} catch {
|
|
188
|
-
expect(isCancelledError(result)).toBe(true)
|
|
189
|
-
expect(result instanceof Error).toBe(true)
|
|
190
|
-
} finally {
|
|
191
|
-
// Reset visibilityState to original value
|
|
192
|
-
visibilityMock.mockRestore()
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
test('should provide context to queryFn', async () => {
|
|
197
|
-
const key = queryKey()
|
|
198
|
-
|
|
199
|
-
const queryFn = vi
|
|
200
|
-
.fn<
|
|
201
|
-
(
|
|
202
|
-
context: QueryFunctionContext<ReturnType<typeof queryKey>>,
|
|
203
|
-
) => Promise<'data'>
|
|
204
|
-
>()
|
|
205
|
-
.mockResolvedValue('data')
|
|
206
|
-
|
|
207
|
-
queryClient.prefetchQuery({ queryKey: key, queryFn })
|
|
208
|
-
|
|
209
|
-
await sleep(10)
|
|
210
|
-
|
|
211
|
-
expect(queryFn).toHaveBeenCalledTimes(1)
|
|
212
|
-
const args = queryFn.mock.calls[0]![0]
|
|
213
|
-
expect(args).toBeDefined()
|
|
214
|
-
expect(args.pageParam).toBeUndefined()
|
|
215
|
-
expect(args.queryKey).toEqual(key)
|
|
216
|
-
expect(args.signal).toBeInstanceOf(AbortSignal)
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
test('should continue if cancellation is not supported and signal is not consumed', async () => {
|
|
220
|
-
const key = queryKey()
|
|
221
|
-
|
|
222
|
-
queryClient.prefetchQuery({
|
|
223
|
-
queryKey: key,
|
|
224
|
-
queryFn: async () => {
|
|
225
|
-
await sleep(100)
|
|
226
|
-
return 'data'
|
|
227
|
-
},
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
await sleep(10)
|
|
231
|
-
|
|
232
|
-
// Subscribe and unsubscribe to simulate cancellation because the last observer unsubscribed
|
|
233
|
-
const observer = new QueryObserver(queryClient, {
|
|
234
|
-
queryKey: key,
|
|
235
|
-
enabled: false,
|
|
236
|
-
})
|
|
237
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
238
|
-
unsubscribe()
|
|
239
|
-
|
|
240
|
-
await sleep(100)
|
|
241
|
-
|
|
242
|
-
const query = queryCache.find({ queryKey: key })!
|
|
243
|
-
|
|
244
|
-
expect(query.state).toMatchObject({
|
|
245
|
-
data: 'data',
|
|
246
|
-
status: 'success',
|
|
247
|
-
dataUpdateCount: 1,
|
|
248
|
-
})
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
test('should not continue when last observer unsubscribed if the signal was consumed', async () => {
|
|
252
|
-
const key = queryKey()
|
|
253
|
-
|
|
254
|
-
queryClient.prefetchQuery({
|
|
255
|
-
queryKey: key,
|
|
256
|
-
queryFn: async ({ signal }) => {
|
|
257
|
-
await sleep(100)
|
|
258
|
-
return signal.aborted ? 'aborted' : 'data'
|
|
259
|
-
},
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
await sleep(10)
|
|
263
|
-
|
|
264
|
-
// Subscribe and unsubscribe to simulate cancellation because the last observer unsubscribed
|
|
265
|
-
const observer = new QueryObserver(queryClient, {
|
|
266
|
-
queryKey: key,
|
|
267
|
-
enabled: false,
|
|
268
|
-
})
|
|
269
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
270
|
-
unsubscribe()
|
|
271
|
-
|
|
272
|
-
await sleep(100)
|
|
273
|
-
|
|
274
|
-
const query = queryCache.find({ queryKey: key })!
|
|
275
|
-
|
|
276
|
-
expect(query.state).toMatchObject({
|
|
277
|
-
data: undefined,
|
|
278
|
-
status: 'pending',
|
|
279
|
-
fetchStatus: 'idle',
|
|
280
|
-
})
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
test('should provide an AbortSignal to the queryFn that provides info about the cancellation state', async () => {
|
|
284
|
-
const key = queryKey()
|
|
285
|
-
|
|
286
|
-
const queryFn =
|
|
287
|
-
vi.fn<
|
|
288
|
-
(
|
|
289
|
-
context: QueryFunctionContext<ReturnType<typeof queryKey>>,
|
|
290
|
-
) => Promise<unknown>
|
|
291
|
-
>()
|
|
292
|
-
const onAbort = vi.fn()
|
|
293
|
-
const abortListener = vi.fn()
|
|
294
|
-
let error
|
|
295
|
-
|
|
296
|
-
queryFn.mockImplementation(async ({ signal }) => {
|
|
297
|
-
signal.onabort = onAbort
|
|
298
|
-
signal.addEventListener('abort', abortListener)
|
|
299
|
-
await sleep(10)
|
|
300
|
-
signal.onabort = null
|
|
301
|
-
signal.removeEventListener('abort', abortListener)
|
|
302
|
-
throw new Error()
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
const promise = queryClient.fetchQuery({
|
|
306
|
-
queryKey: key,
|
|
307
|
-
queryFn,
|
|
308
|
-
retry: 3,
|
|
309
|
-
retryDelay: 10,
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
promise.catch((e) => {
|
|
313
|
-
error = e
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
const query = queryCache.find({ queryKey: key })!
|
|
317
|
-
|
|
318
|
-
expect(queryFn).toHaveBeenCalledTimes(1)
|
|
319
|
-
|
|
320
|
-
const signal = queryFn.mock.calls[0]![0].signal
|
|
321
|
-
expect(signal.aborted).toBe(false)
|
|
322
|
-
expect(onAbort).not.toHaveBeenCalled()
|
|
323
|
-
expect(abortListener).not.toHaveBeenCalled()
|
|
324
|
-
|
|
325
|
-
query.cancel()
|
|
326
|
-
|
|
327
|
-
await sleep(100)
|
|
328
|
-
|
|
329
|
-
expect(signal.aborted).toBe(true)
|
|
330
|
-
expect(onAbort).toHaveBeenCalledTimes(1)
|
|
331
|
-
expect(abortListener).toHaveBeenCalledTimes(1)
|
|
332
|
-
expect(isCancelledError(error)).toBe(true)
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
test('should not continue if explicitly cancelled', async () => {
|
|
336
|
-
const key = queryKey()
|
|
337
|
-
|
|
338
|
-
const queryFn = vi.fn<(...args: Array<unknown>) => unknown>()
|
|
339
|
-
|
|
340
|
-
queryFn.mockImplementation(async () => {
|
|
341
|
-
await sleep(10)
|
|
342
|
-
throw new Error()
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
let error
|
|
346
|
-
|
|
347
|
-
const promise = queryClient.fetchQuery({
|
|
348
|
-
queryKey: key,
|
|
349
|
-
queryFn,
|
|
350
|
-
retry: 3,
|
|
351
|
-
retryDelay: 10,
|
|
352
|
-
})
|
|
353
|
-
|
|
354
|
-
promise.catch((e) => {
|
|
355
|
-
error = e
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
const query = queryCache.find({ queryKey: key })!
|
|
359
|
-
query.cancel()
|
|
360
|
-
|
|
361
|
-
await sleep(100)
|
|
362
|
-
|
|
363
|
-
expect(queryFn).toHaveBeenCalledTimes(1)
|
|
364
|
-
expect(isCancelledError(error)).toBe(true)
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
test('should not error if reset while pending', async () => {
|
|
368
|
-
const key = queryKey()
|
|
369
|
-
|
|
370
|
-
const queryFn = vi.fn<(...args: Array<unknown>) => unknown>()
|
|
371
|
-
|
|
372
|
-
queryFn.mockImplementation(async () => {
|
|
373
|
-
await sleep(10)
|
|
374
|
-
throw new Error()
|
|
375
|
-
})
|
|
376
|
-
|
|
377
|
-
queryClient.fetchQuery({ queryKey: key, queryFn, retry: 3, retryDelay: 10 })
|
|
378
|
-
|
|
379
|
-
// Ensure the query is pending
|
|
380
|
-
const query = queryCache.find({ queryKey: key })!
|
|
381
|
-
expect(query.state.status).toBe('pending')
|
|
382
|
-
|
|
383
|
-
// Reset the query while it is pending
|
|
384
|
-
query.reset()
|
|
385
|
-
|
|
386
|
-
await sleep(100)
|
|
387
|
-
|
|
388
|
-
// The query should
|
|
389
|
-
expect(queryFn).toHaveBeenCalledTimes(1) // have been called,
|
|
390
|
-
expect(query.state.error).toBe(null) // not have an error, and
|
|
391
|
-
expect(query.state.fetchStatus).toBe('idle') // not be loading any longer
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
test('should reset to default state when created from hydration', async () => {
|
|
395
|
-
const client = createQueryClient()
|
|
396
|
-
await client.prefetchQuery({
|
|
397
|
-
queryKey: ['string'],
|
|
398
|
-
queryFn: () => Promise.resolve('string'),
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
const dehydrated = dehydrate(client)
|
|
402
|
-
|
|
403
|
-
const hydrationClient = createQueryClient()
|
|
404
|
-
hydrate(hydrationClient, dehydrated)
|
|
405
|
-
|
|
406
|
-
expect(hydrationClient.getQueryData(['string'])).toBe('string')
|
|
407
|
-
|
|
408
|
-
const query = hydrationClient.getQueryCache().find({ queryKey: ['string'] })
|
|
409
|
-
query?.reset()
|
|
410
|
-
|
|
411
|
-
expect(hydrationClient.getQueryData(['string'])).toBe(undefined)
|
|
412
|
-
})
|
|
413
|
-
|
|
414
|
-
test('should be able to refetch a cancelled query', async () => {
|
|
415
|
-
const key = queryKey()
|
|
416
|
-
|
|
417
|
-
const queryFn = vi.fn<(...args: Array<unknown>) => unknown>()
|
|
418
|
-
|
|
419
|
-
queryFn.mockImplementation(async () => {
|
|
420
|
-
await sleep(50)
|
|
421
|
-
return 'data'
|
|
422
|
-
})
|
|
423
|
-
|
|
424
|
-
queryClient.prefetchQuery({ queryKey: key, queryFn })
|
|
425
|
-
const query = queryCache.find({ queryKey: key })!
|
|
426
|
-
await sleep(10)
|
|
427
|
-
query.cancel()
|
|
428
|
-
await sleep(100)
|
|
429
|
-
|
|
430
|
-
expect(queryFn).toHaveBeenCalledTimes(1)
|
|
431
|
-
expect(isCancelledError(query.state.error)).toBe(true)
|
|
432
|
-
const result = await query.fetch()
|
|
433
|
-
expect(result).toBe('data')
|
|
434
|
-
expect(query.state.error).toBe(null)
|
|
435
|
-
expect(queryFn).toHaveBeenCalledTimes(2)
|
|
436
|
-
})
|
|
437
|
-
|
|
438
|
-
test('cancelling a resolved query should not have any effect', async () => {
|
|
439
|
-
const key = queryKey()
|
|
440
|
-
await queryClient.prefetchQuery({
|
|
441
|
-
queryKey: key,
|
|
442
|
-
queryFn: async () => 'data',
|
|
443
|
-
})
|
|
444
|
-
const query = queryCache.find({ queryKey: key })!
|
|
445
|
-
query.cancel()
|
|
446
|
-
await sleep(10)
|
|
447
|
-
expect(query.state.data).toBe('data')
|
|
448
|
-
})
|
|
449
|
-
|
|
450
|
-
test('cancelling a rejected query should not have any effect', async () => {
|
|
451
|
-
const key = queryKey()
|
|
452
|
-
const error = new Error('error')
|
|
453
|
-
|
|
454
|
-
await queryClient.prefetchQuery({
|
|
455
|
-
queryKey: key,
|
|
456
|
-
queryFn: async (): Promise<unknown> => {
|
|
457
|
-
throw error
|
|
458
|
-
},
|
|
459
|
-
})
|
|
460
|
-
const query = queryCache.find({ queryKey: key })!
|
|
461
|
-
query.cancel()
|
|
462
|
-
await sleep(10)
|
|
463
|
-
|
|
464
|
-
expect(query.state.error).toBe(error)
|
|
465
|
-
expect(isCancelledError(query.state.error)).toBe(false)
|
|
466
|
-
})
|
|
467
|
-
|
|
468
|
-
test('the previous query status should be kept when refetching', async () => {
|
|
469
|
-
const key = queryKey()
|
|
470
|
-
|
|
471
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn: () => 'data' })
|
|
472
|
-
const query = queryCache.find({ queryKey: key })!
|
|
473
|
-
expect(query.state.status).toBe('success')
|
|
474
|
-
|
|
475
|
-
await queryClient.prefetchQuery({
|
|
476
|
-
queryKey: key,
|
|
477
|
-
queryFn: () => Promise.reject<string>('reject'),
|
|
478
|
-
retry: false,
|
|
479
|
-
})
|
|
480
|
-
expect(query.state.status).toBe('error')
|
|
481
|
-
|
|
482
|
-
queryClient.prefetchQuery({
|
|
483
|
-
queryKey: key,
|
|
484
|
-
queryFn: async () => {
|
|
485
|
-
await sleep(10)
|
|
486
|
-
return Promise.reject<unknown>('reject')
|
|
487
|
-
},
|
|
488
|
-
retry: false,
|
|
489
|
-
})
|
|
490
|
-
expect(query.state.status).toBe('error')
|
|
491
|
-
|
|
492
|
-
await sleep(100)
|
|
493
|
-
expect(query.state.status).toBe('error')
|
|
494
|
-
})
|
|
495
|
-
|
|
496
|
-
test('queries with gcTime 0 should be removed immediately after unsubscribing', async () => {
|
|
497
|
-
const key = queryKey()
|
|
498
|
-
let count = 0
|
|
499
|
-
const observer = new QueryObserver(queryClient, {
|
|
500
|
-
queryKey: key,
|
|
501
|
-
queryFn: () => {
|
|
502
|
-
count++
|
|
503
|
-
return 'data'
|
|
504
|
-
},
|
|
505
|
-
gcTime: 0,
|
|
506
|
-
staleTime: Infinity,
|
|
507
|
-
})
|
|
508
|
-
const unsubscribe1 = observer.subscribe(() => undefined)
|
|
509
|
-
unsubscribe1()
|
|
510
|
-
await waitFor(() =>
|
|
511
|
-
expect(queryCache.find({ queryKey: key })).toBeUndefined(),
|
|
512
|
-
)
|
|
513
|
-
const unsubscribe2 = observer.subscribe(() => undefined)
|
|
514
|
-
unsubscribe2()
|
|
515
|
-
|
|
516
|
-
await waitFor(() =>
|
|
517
|
-
expect(queryCache.find({ queryKey: key })).toBeUndefined(),
|
|
518
|
-
)
|
|
519
|
-
expect(count).toBe(1)
|
|
520
|
-
})
|
|
521
|
-
|
|
522
|
-
test('should be garbage collected when unsubscribed to', async () => {
|
|
523
|
-
const key = queryKey()
|
|
524
|
-
const observer = new QueryObserver(queryClient, {
|
|
525
|
-
queryKey: key,
|
|
526
|
-
queryFn: async () => 'data',
|
|
527
|
-
gcTime: 0,
|
|
528
|
-
})
|
|
529
|
-
expect(queryCache.find({ queryKey: key })).toBeDefined()
|
|
530
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
531
|
-
expect(queryCache.find({ queryKey: key })).toBeDefined()
|
|
532
|
-
unsubscribe()
|
|
533
|
-
await waitFor(() =>
|
|
534
|
-
expect(queryCache.find({ queryKey: key })).toBeUndefined(),
|
|
535
|
-
)
|
|
536
|
-
})
|
|
537
|
-
|
|
538
|
-
test('should be garbage collected later when unsubscribed and query is fetching', async () => {
|
|
539
|
-
const key = queryKey()
|
|
540
|
-
const observer = new QueryObserver(queryClient, {
|
|
541
|
-
queryKey: key,
|
|
542
|
-
queryFn: async () => {
|
|
543
|
-
await sleep(20)
|
|
544
|
-
return 'data'
|
|
545
|
-
},
|
|
546
|
-
gcTime: 10,
|
|
547
|
-
})
|
|
548
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
549
|
-
await sleep(20)
|
|
550
|
-
expect(queryCache.find({ queryKey: key })).toBeDefined()
|
|
551
|
-
observer.refetch()
|
|
552
|
-
unsubscribe()
|
|
553
|
-
await sleep(10)
|
|
554
|
-
// unsubscribe should not remove even though gcTime has elapsed b/c query is still fetching
|
|
555
|
-
expect(queryCache.find({ queryKey: key })).toBeDefined()
|
|
556
|
-
await sleep(10)
|
|
557
|
-
// should be removed after an additional staleTime wait
|
|
558
|
-
await waitFor(() =>
|
|
559
|
-
expect(queryCache.find({ queryKey: key })).toBeUndefined(),
|
|
560
|
-
)
|
|
561
|
-
})
|
|
562
|
-
|
|
563
|
-
test('should not be garbage collected unless there are no subscribers', async () => {
|
|
564
|
-
const key = queryKey()
|
|
565
|
-
const observer = new QueryObserver(queryClient, {
|
|
566
|
-
queryKey: key,
|
|
567
|
-
queryFn: async () => 'data',
|
|
568
|
-
gcTime: 0,
|
|
569
|
-
})
|
|
570
|
-
expect(queryCache.find({ queryKey: key })).toBeDefined()
|
|
571
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
572
|
-
await sleep(100)
|
|
573
|
-
expect(queryCache.find({ queryKey: key })).toBeDefined()
|
|
574
|
-
unsubscribe()
|
|
575
|
-
await sleep(100)
|
|
576
|
-
expect(queryCache.find({ queryKey: key })).toBeUndefined()
|
|
577
|
-
queryClient.setQueryData(key, 'data')
|
|
578
|
-
await sleep(100)
|
|
579
|
-
expect(queryCache.find({ queryKey: key })).toBeDefined()
|
|
580
|
-
})
|
|
581
|
-
|
|
582
|
-
test('should return proper count of observers', async () => {
|
|
583
|
-
const key = queryKey()
|
|
584
|
-
const options = { queryKey: key, queryFn: async () => 'data' }
|
|
585
|
-
const observer = new QueryObserver(queryClient, options)
|
|
586
|
-
const observer2 = new QueryObserver(queryClient, options)
|
|
587
|
-
const observer3 = new QueryObserver(queryClient, options)
|
|
588
|
-
const query = queryCache.find({ queryKey: key })
|
|
589
|
-
|
|
590
|
-
expect(query?.getObserversCount()).toEqual(0)
|
|
591
|
-
|
|
592
|
-
const unsubscribe1 = observer.subscribe(() => undefined)
|
|
593
|
-
const unsubscribe2 = observer2.subscribe(() => undefined)
|
|
594
|
-
const unsubscribe3 = observer3.subscribe(() => undefined)
|
|
595
|
-
expect(query?.getObserversCount()).toEqual(3)
|
|
596
|
-
|
|
597
|
-
unsubscribe3()
|
|
598
|
-
expect(query?.getObserversCount()).toEqual(2)
|
|
599
|
-
|
|
600
|
-
unsubscribe2()
|
|
601
|
-
expect(query?.getObserversCount()).toEqual(1)
|
|
602
|
-
|
|
603
|
-
unsubscribe1()
|
|
604
|
-
expect(query?.getObserversCount()).toEqual(0)
|
|
605
|
-
})
|
|
606
|
-
|
|
607
|
-
test('stores meta object in query', async () => {
|
|
608
|
-
const meta = {
|
|
609
|
-
it: 'works',
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
const key = queryKey()
|
|
613
|
-
|
|
614
|
-
await queryClient.prefetchQuery({
|
|
615
|
-
queryKey: key,
|
|
616
|
-
queryFn: () => 'data',
|
|
617
|
-
meta,
|
|
618
|
-
})
|
|
619
|
-
|
|
620
|
-
const query = queryCache.find({ queryKey: key })!
|
|
621
|
-
|
|
622
|
-
expect(query.meta).toBe(meta)
|
|
623
|
-
expect(query.options.meta).toBe(meta)
|
|
624
|
-
})
|
|
625
|
-
|
|
626
|
-
test('updates meta object on change', async () => {
|
|
627
|
-
const meta = {
|
|
628
|
-
it: 'works',
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
const key = queryKey()
|
|
632
|
-
const queryFn = () => 'data'
|
|
633
|
-
|
|
634
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn, meta })
|
|
635
|
-
|
|
636
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn, meta: undefined })
|
|
637
|
-
|
|
638
|
-
const query = queryCache.find({ queryKey: key })!
|
|
639
|
-
|
|
640
|
-
expect(query.meta).toBeUndefined()
|
|
641
|
-
expect(query.options.meta).toBeUndefined()
|
|
642
|
-
})
|
|
643
|
-
|
|
644
|
-
test('can use default meta', async () => {
|
|
645
|
-
const meta = {
|
|
646
|
-
it: 'works',
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
const key = queryKey()
|
|
650
|
-
const queryFn = () => 'data'
|
|
651
|
-
|
|
652
|
-
queryClient.setQueryDefaults(key, { meta })
|
|
653
|
-
|
|
654
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn })
|
|
655
|
-
|
|
656
|
-
const query = queryCache.find({ queryKey: key })!
|
|
657
|
-
|
|
658
|
-
expect(query.meta).toBe(meta)
|
|
659
|
-
})
|
|
660
|
-
|
|
661
|
-
test('provides meta object inside query function', async () => {
|
|
662
|
-
const meta = {
|
|
663
|
-
it: 'works',
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
const queryFn = vi.fn(() => 'data')
|
|
667
|
-
|
|
668
|
-
const key = queryKey()
|
|
669
|
-
|
|
670
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn, meta })
|
|
671
|
-
|
|
672
|
-
expect(queryFn).toBeCalledWith(
|
|
673
|
-
expect.objectContaining({
|
|
674
|
-
meta,
|
|
675
|
-
}),
|
|
676
|
-
)
|
|
677
|
-
})
|
|
678
|
-
|
|
679
|
-
test('should refetch the observer when online method is called', async () => {
|
|
680
|
-
const key = queryKey()
|
|
681
|
-
|
|
682
|
-
const observer = new QueryObserver(queryClient, {
|
|
683
|
-
queryKey: key,
|
|
684
|
-
queryFn: () => 'data',
|
|
685
|
-
})
|
|
686
|
-
|
|
687
|
-
const refetchSpy = vi.spyOn(observer, 'refetch')
|
|
688
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
689
|
-
queryCache.onOnline()
|
|
690
|
-
|
|
691
|
-
// Should refetch the observer
|
|
692
|
-
expect(refetchSpy).toHaveBeenCalledTimes(1)
|
|
693
|
-
|
|
694
|
-
unsubscribe()
|
|
695
|
-
refetchSpy.mockRestore()
|
|
696
|
-
})
|
|
697
|
-
|
|
698
|
-
test('should not add an existing observer', async () => {
|
|
699
|
-
const key = queryKey()
|
|
700
|
-
|
|
701
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn: () => 'data' })
|
|
702
|
-
const query = queryCache.find({ queryKey: key })!
|
|
703
|
-
expect(query.getObserversCount()).toEqual(0)
|
|
704
|
-
|
|
705
|
-
const observer = new QueryObserver(queryClient, {
|
|
706
|
-
queryKey: key,
|
|
707
|
-
})
|
|
708
|
-
expect(query.getObserversCount()).toEqual(0)
|
|
709
|
-
|
|
710
|
-
query.addObserver(observer)
|
|
711
|
-
expect(query.getObserversCount()).toEqual(1)
|
|
712
|
-
|
|
713
|
-
query.addObserver(observer)
|
|
714
|
-
expect(query.getObserversCount()).toEqual(1)
|
|
715
|
-
})
|
|
716
|
-
|
|
717
|
-
test('should not try to remove an observer that does not exist', async () => {
|
|
718
|
-
const key = queryKey()
|
|
719
|
-
|
|
720
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn: () => 'data' })
|
|
721
|
-
const query = queryCache.find({ queryKey: key })!
|
|
722
|
-
const observer = new QueryObserver(queryClient, {
|
|
723
|
-
queryKey: key,
|
|
724
|
-
})
|
|
725
|
-
expect(query.getObserversCount()).toEqual(0)
|
|
726
|
-
|
|
727
|
-
const notifySpy = vi.spyOn(queryCache, 'notify')
|
|
728
|
-
expect(() => query.removeObserver(observer)).not.toThrow()
|
|
729
|
-
expect(notifySpy).not.toHaveBeenCalled()
|
|
730
|
-
|
|
731
|
-
notifySpy.mockRestore()
|
|
732
|
-
})
|
|
733
|
-
|
|
734
|
-
test('should not change state on invalidate() if already invalidated', async () => {
|
|
735
|
-
const key = queryKey()
|
|
736
|
-
|
|
737
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn: () => 'data' })
|
|
738
|
-
const query = queryCache.find({ queryKey: key })!
|
|
739
|
-
|
|
740
|
-
query.invalidate()
|
|
741
|
-
expect(query.state.isInvalidated).toBeTruthy()
|
|
742
|
-
|
|
743
|
-
const previousState = query.state
|
|
744
|
-
|
|
745
|
-
query.invalidate()
|
|
746
|
-
|
|
747
|
-
expect(query.state).toBe(previousState)
|
|
748
|
-
})
|
|
749
|
-
|
|
750
|
-
test('fetch should not dispatch "fetch" query is already fetching', async () => {
|
|
751
|
-
const key = queryKey()
|
|
752
|
-
|
|
753
|
-
const queryFn = async () => {
|
|
754
|
-
await sleep(10)
|
|
755
|
-
return 'data'
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
const updates: Array<string> = []
|
|
759
|
-
|
|
760
|
-
await queryClient.prefetchQuery({ queryKey: key, queryFn })
|
|
761
|
-
const query = queryCache.find({ queryKey: key })!
|
|
762
|
-
|
|
763
|
-
const unsubscribe = queryClient.getQueryCache().subscribe((event) => {
|
|
764
|
-
updates.push(event.type)
|
|
765
|
-
})
|
|
766
|
-
|
|
767
|
-
void query.fetch({
|
|
768
|
-
queryKey: key,
|
|
769
|
-
queryFn,
|
|
770
|
-
})
|
|
771
|
-
|
|
772
|
-
await query.fetch({
|
|
773
|
-
queryKey: key,
|
|
774
|
-
queryFn,
|
|
775
|
-
})
|
|
776
|
-
|
|
777
|
-
expect(updates).toEqual([
|
|
778
|
-
'updated', // type: 'fetch'
|
|
779
|
-
'updated', // type: 'success'
|
|
780
|
-
])
|
|
781
|
-
|
|
782
|
-
unsubscribe()
|
|
783
|
-
})
|
|
784
|
-
|
|
785
|
-
test('fetch should throw an error if the queryFn is not defined', async () => {
|
|
786
|
-
const key = queryKey()
|
|
787
|
-
|
|
788
|
-
const observer = new QueryObserver(queryClient, {
|
|
789
|
-
queryKey: key,
|
|
790
|
-
queryFn: undefined,
|
|
791
|
-
retry: false,
|
|
792
|
-
})
|
|
793
|
-
|
|
794
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
795
|
-
|
|
796
|
-
await sleep(10)
|
|
797
|
-
const query = queryCache.find({ queryKey: key })!
|
|
798
|
-
expect(observer.getCurrentResult()).toMatchObject({
|
|
799
|
-
status: 'error',
|
|
800
|
-
error: new Error(`Missing queryFn: '${query.queryHash}'`),
|
|
801
|
-
})
|
|
802
|
-
unsubscribe()
|
|
803
|
-
})
|
|
804
|
-
|
|
805
|
-
test('fetch should dispatch an error if the queryFn returns undefined', async () => {
|
|
806
|
-
const consoleMock = vi.spyOn(console, 'error')
|
|
807
|
-
consoleMock.mockImplementation(() => undefined)
|
|
808
|
-
const key = queryKey()
|
|
809
|
-
|
|
810
|
-
const observer = new QueryObserver(queryClient, {
|
|
811
|
-
queryKey: key,
|
|
812
|
-
queryFn: () => undefined,
|
|
813
|
-
retry: false,
|
|
814
|
-
})
|
|
815
|
-
|
|
816
|
-
let observerResult: QueryObserverResult<unknown, unknown> | undefined
|
|
817
|
-
|
|
818
|
-
const unsubscribe = observer.subscribe((result) => {
|
|
819
|
-
observerResult = result
|
|
820
|
-
})
|
|
821
|
-
|
|
822
|
-
await sleep(10)
|
|
823
|
-
|
|
824
|
-
const error = new Error(`${JSON.stringify(key)} data is undefined`)
|
|
825
|
-
|
|
826
|
-
expect(observerResult).toMatchObject({
|
|
827
|
-
isError: true,
|
|
828
|
-
error,
|
|
829
|
-
})
|
|
830
|
-
|
|
831
|
-
expect(consoleMock).toHaveBeenCalledWith(
|
|
832
|
-
`Query data cannot be undefined. Please make sure to return a value other than undefined from your query function. Affected query key: ["${key}"]`,
|
|
833
|
-
)
|
|
834
|
-
unsubscribe()
|
|
835
|
-
consoleMock.mockRestore()
|
|
836
|
-
})
|
|
837
|
-
|
|
838
|
-
it('should not retry on the server', async () => {
|
|
839
|
-
const resetIsServer = setIsServer(true)
|
|
840
|
-
|
|
841
|
-
const key = queryKey()
|
|
842
|
-
let count = 0
|
|
843
|
-
|
|
844
|
-
const observer = new QueryObserver(queryClient, {
|
|
845
|
-
queryKey: key,
|
|
846
|
-
queryFn: () => {
|
|
847
|
-
count++
|
|
848
|
-
return Promise.reject(new Error('error'))
|
|
849
|
-
},
|
|
850
|
-
})
|
|
851
|
-
|
|
852
|
-
await observer.refetch()
|
|
853
|
-
|
|
854
|
-
expect(count).toBe(1)
|
|
855
|
-
|
|
856
|
-
resetIsServer()
|
|
857
|
-
})
|
|
858
|
-
|
|
859
|
-
test('constructor should call initialDataUpdatedAt if defined as a function', async () => {
|
|
860
|
-
const key = queryKey()
|
|
861
|
-
|
|
862
|
-
const initialDataUpdatedAtSpy = vi.fn()
|
|
863
|
-
|
|
864
|
-
await queryClient.prefetchQuery({
|
|
865
|
-
queryKey: key,
|
|
866
|
-
queryFn: () => 'data',
|
|
867
|
-
initialData: 'initial',
|
|
868
|
-
initialDataUpdatedAt: initialDataUpdatedAtSpy,
|
|
869
|
-
})
|
|
870
|
-
|
|
871
|
-
expect(initialDataUpdatedAtSpy).toHaveBeenCalled()
|
|
872
|
-
})
|
|
873
|
-
|
|
874
|
-
test('should work with initialDataUpdatedAt set to zero', async () => {
|
|
875
|
-
const key = queryKey()
|
|
876
|
-
|
|
877
|
-
await queryClient.prefetchQuery({
|
|
878
|
-
queryKey: key,
|
|
879
|
-
queryFn: () => 'data',
|
|
880
|
-
staleTime: Infinity,
|
|
881
|
-
initialData: 'initial',
|
|
882
|
-
initialDataUpdatedAt: 0,
|
|
883
|
-
})
|
|
884
|
-
|
|
885
|
-
expect(queryCache.find({ queryKey: key })?.state).toMatchObject({
|
|
886
|
-
data: 'initial',
|
|
887
|
-
status: 'success',
|
|
888
|
-
dataUpdatedAt: 0,
|
|
889
|
-
})
|
|
890
|
-
})
|
|
891
|
-
|
|
892
|
-
test('queries should be garbage collected even if they never fetched', async () => {
|
|
893
|
-
const key = queryKey()
|
|
894
|
-
|
|
895
|
-
queryClient.setQueryDefaults(key, { gcTime: 10 })
|
|
896
|
-
|
|
897
|
-
const fn = vi.fn()
|
|
898
|
-
|
|
899
|
-
const unsubscribe = queryClient.getQueryCache().subscribe(fn)
|
|
900
|
-
|
|
901
|
-
queryClient.setQueryData(key, 'data')
|
|
902
|
-
|
|
903
|
-
await waitFor(() =>
|
|
904
|
-
expect(fn).toHaveBeenCalledWith(
|
|
905
|
-
expect.objectContaining({
|
|
906
|
-
type: 'removed',
|
|
907
|
-
}),
|
|
908
|
-
),
|
|
909
|
-
)
|
|
910
|
-
|
|
911
|
-
expect(queryClient.getQueryCache().findAll()).toHaveLength(0)
|
|
912
|
-
|
|
913
|
-
unsubscribe()
|
|
914
|
-
})
|
|
915
|
-
|
|
916
|
-
test('should always revert to idle state (#5958)', async () => {
|
|
917
|
-
let mockedData = [1]
|
|
918
|
-
|
|
919
|
-
const key = queryKey()
|
|
920
|
-
|
|
921
|
-
const queryFn = vi
|
|
922
|
-
.fn<
|
|
923
|
-
(
|
|
924
|
-
context: QueryFunctionContext<ReturnType<typeof queryKey>>,
|
|
925
|
-
) => Promise<unknown>
|
|
926
|
-
>()
|
|
927
|
-
.mockImplementation(({ signal }) => {
|
|
928
|
-
return new Promise((resolve, reject) => {
|
|
929
|
-
const abortListener = () => {
|
|
930
|
-
clearTimeout(timerId)
|
|
931
|
-
reject(signal.reason)
|
|
932
|
-
}
|
|
933
|
-
signal.addEventListener('abort', abortListener)
|
|
934
|
-
|
|
935
|
-
const timerId = setTimeout(() => {
|
|
936
|
-
signal.removeEventListener('abort', abortListener)
|
|
937
|
-
resolve(mockedData.join(' - '))
|
|
938
|
-
}, 50)
|
|
939
|
-
})
|
|
940
|
-
})
|
|
941
|
-
|
|
942
|
-
const observer = new QueryObserver(queryClient, {
|
|
943
|
-
queryKey: key,
|
|
944
|
-
queryFn,
|
|
945
|
-
})
|
|
946
|
-
const unsubscribe = observer.subscribe(() => undefined)
|
|
947
|
-
await sleep(60) // let it resolve
|
|
948
|
-
|
|
949
|
-
mockedData = [1, 2] // update "server" state in the background
|
|
950
|
-
|
|
951
|
-
queryClient.invalidateQueries({ queryKey: key })
|
|
952
|
-
await sleep(1)
|
|
953
|
-
queryClient.invalidateQueries({ queryKey: key })
|
|
954
|
-
await sleep(1)
|
|
955
|
-
unsubscribe() // unsubscribe to simulate unmount
|
|
956
|
-
|
|
957
|
-
// set up a new observer to simulate a mount of new component
|
|
958
|
-
const newObserver = new QueryObserver(queryClient, {
|
|
959
|
-
queryKey: key,
|
|
960
|
-
queryFn,
|
|
961
|
-
})
|
|
962
|
-
|
|
963
|
-
const spy = vi.fn()
|
|
964
|
-
newObserver.subscribe(({ data }) => spy(data))
|
|
965
|
-
await sleep(60) // let it resolve
|
|
966
|
-
expect(spy).toHaveBeenCalledWith('1 - 2')
|
|
967
|
-
})
|
|
968
|
-
|
|
969
|
-
it('should have an error log when queryFn data is not serializable', async () => {
|
|
970
|
-
const consoleMock = vi.spyOn(console, 'error')
|
|
971
|
-
|
|
972
|
-
consoleMock.mockImplementation(() => undefined)
|
|
973
|
-
|
|
974
|
-
const key = queryKey()
|
|
975
|
-
|
|
976
|
-
const queryFn = vi.fn()
|
|
977
|
-
|
|
978
|
-
const data: Array<{
|
|
979
|
-
id: number
|
|
980
|
-
name: string
|
|
981
|
-
link: null | { id: number; name: string; link: unknown }
|
|
982
|
-
}> = Array.from({ length: 5 })
|
|
983
|
-
.fill(null)
|
|
984
|
-
.map((_, index) => ({
|
|
985
|
-
id: index,
|
|
986
|
-
name: `name-${index}`,
|
|
987
|
-
link: null,
|
|
988
|
-
}))
|
|
989
|
-
|
|
990
|
-
if (data[0] && data[1]) {
|
|
991
|
-
data[0].link = data[1]
|
|
992
|
-
data[1].link = data[0]
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
queryFn.mockImplementation(async () => {
|
|
996
|
-
await sleep(10)
|
|
997
|
-
return data
|
|
998
|
-
})
|
|
999
|
-
|
|
1000
|
-
await queryClient.prefetchQuery({
|
|
1001
|
-
queryKey: key,
|
|
1002
|
-
queryFn,
|
|
1003
|
-
initialData: structuredClone(data),
|
|
1004
|
-
})
|
|
1005
|
-
|
|
1006
|
-
const query = queryCache.find({ queryKey: key })!
|
|
1007
|
-
|
|
1008
|
-
expect(queryFn).toHaveBeenCalledTimes(1)
|
|
1009
|
-
|
|
1010
|
-
expect(query.state.status).toBe('error')
|
|
1011
|
-
expect(
|
|
1012
|
-
query.state.error?.message.includes('Maximum call stack size exceeded'),
|
|
1013
|
-
).toBeTruthy()
|
|
1014
|
-
|
|
1015
|
-
expect(consoleMock).toHaveBeenCalledWith(
|
|
1016
|
-
expect.stringContaining(
|
|
1017
|
-
'Structural sharing requires data to be JSON serializable',
|
|
1018
|
-
),
|
|
1019
|
-
)
|
|
1020
|
-
|
|
1021
|
-
consoleMock.mockRestore()
|
|
1022
|
-
})
|
|
1023
|
-
|
|
1024
|
-
it('should have an error status when setData has any error inside', async () => {
|
|
1025
|
-
const key = queryKey()
|
|
1026
|
-
|
|
1027
|
-
const queryFn = vi.fn()
|
|
1028
|
-
|
|
1029
|
-
queryFn.mockImplementation(async () => {
|
|
1030
|
-
await sleep(10)
|
|
1031
|
-
|
|
1032
|
-
return 'data'
|
|
1033
|
-
})
|
|
1034
|
-
|
|
1035
|
-
await queryClient.prefetchQuery({
|
|
1036
|
-
queryKey: key,
|
|
1037
|
-
queryFn,
|
|
1038
|
-
structuralSharing: () => {
|
|
1039
|
-
throw Error('Any error')
|
|
1040
|
-
},
|
|
1041
|
-
})
|
|
1042
|
-
|
|
1043
|
-
const query = queryCache.find({ queryKey: key })!
|
|
1044
|
-
|
|
1045
|
-
expect(queryFn).toHaveBeenCalledTimes(1)
|
|
1046
|
-
|
|
1047
|
-
expect(query.state.status).toBe('error')
|
|
1048
|
-
})
|
|
1049
|
-
})
|