@tanstack/query-core 4.0.0
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/cjs/focusManager.js +101 -0
- package/build/cjs/focusManager.js.map +1 -0
- package/build/cjs/hydration.js +112 -0
- package/build/cjs/hydration.js.map +1 -0
- package/build/cjs/index.js +51 -0
- package/build/cjs/index.js.map +1 -0
- package/build/cjs/infiniteQueryBehavior.js +160 -0
- package/build/cjs/infiniteQueryBehavior.js.map +1 -0
- package/build/cjs/infiniteQueryObserver.js +92 -0
- package/build/cjs/infiniteQueryObserver.js.map +1 -0
- package/build/cjs/logger.js +18 -0
- package/build/cjs/logger.js.map +1 -0
- package/build/cjs/mutation.js +258 -0
- package/build/cjs/mutation.js.map +1 -0
- package/build/cjs/mutationCache.js +99 -0
- package/build/cjs/mutationCache.js.map +1 -0
- package/build/cjs/mutationObserver.js +130 -0
- package/build/cjs/mutationObserver.js.map +1 -0
- package/build/cjs/notifyManager.js +114 -0
- package/build/cjs/notifyManager.js.map +1 -0
- package/build/cjs/onlineManager.js +100 -0
- package/build/cjs/onlineManager.js.map +1 -0
- package/build/cjs/queriesObserver.js +170 -0
- package/build/cjs/queriesObserver.js.map +1 -0
- package/build/cjs/query.js +474 -0
- package/build/cjs/query.js.map +1 -0
- package/build/cjs/queryCache.js +140 -0
- package/build/cjs/queryCache.js.map +1 -0
- package/build/cjs/queryClient.js +357 -0
- package/build/cjs/queryClient.js.map +1 -0
- package/build/cjs/queryObserver.js +521 -0
- package/build/cjs/queryObserver.js.map +1 -0
- package/build/cjs/removable.js +47 -0
- package/build/cjs/removable.js.map +1 -0
- package/build/cjs/retryer.js +177 -0
- package/build/cjs/retryer.js.map +1 -0
- package/build/cjs/subscribable.js +43 -0
- package/build/cjs/subscribable.js.map +1 -0
- package/build/cjs/utils.js +356 -0
- package/build/cjs/utils.js.map +1 -0
- package/build/esm/index.js +3077 -0
- package/build/esm/index.js.map +1 -0
- package/build/stats-html.html +2689 -0
- package/build/umd/index.development.js +3106 -0
- package/build/umd/index.development.js.map +1 -0
- package/build/umd/index.production.js +12 -0
- package/build/umd/index.production.js.map +1 -0
- package/package.json +25 -0
- package/src/focusManager.ts +89 -0
- package/src/hydration.ts +164 -0
- package/src/index.ts +35 -0
- package/src/infiniteQueryBehavior.ts +214 -0
- package/src/infiniteQueryObserver.ts +159 -0
- package/src/logger.native.ts +11 -0
- package/src/logger.ts +9 -0
- package/src/mutation.ts +349 -0
- package/src/mutationCache.ts +157 -0
- package/src/mutationObserver.ts +195 -0
- package/src/notifyManager.ts +96 -0
- package/src/onlineManager.ts +89 -0
- package/src/queriesObserver.ts +211 -0
- package/src/query.ts +612 -0
- package/src/queryCache.ts +206 -0
- package/src/queryClient.ts +716 -0
- package/src/queryObserver.ts +748 -0
- package/src/removable.ts +37 -0
- package/src/retryer.ts +215 -0
- package/src/subscribable.ts +33 -0
- package/src/tests/focusManager.test.tsx +155 -0
- package/src/tests/hydration.test.tsx +429 -0
- package/src/tests/infiniteQueryBehavior.test.tsx +124 -0
- package/src/tests/infiniteQueryObserver.test.tsx +64 -0
- package/src/tests/mutationCache.test.tsx +260 -0
- package/src/tests/mutationObserver.test.tsx +75 -0
- package/src/tests/mutations.test.tsx +363 -0
- package/src/tests/notifyManager.test.tsx +51 -0
- package/src/tests/onlineManager.test.tsx +148 -0
- package/src/tests/queriesObserver.test.tsx +330 -0
- package/src/tests/query.test.tsx +888 -0
- package/src/tests/queryCache.test.tsx +236 -0
- package/src/tests/queryClient.test.tsx +1435 -0
- package/src/tests/queryObserver.test.tsx +802 -0
- package/src/tests/utils.test.tsx +360 -0
- package/src/types.ts +705 -0
- package/src/utils.ts +435 -0
|
@@ -0,0 +1,1435 @@
|
|
|
1
|
+
import { waitFor } from '@testing-library/react'
|
|
2
|
+
import '@testing-library/jest-dom'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
sleep,
|
|
6
|
+
queryKey,
|
|
7
|
+
mockLogger,
|
|
8
|
+
createQueryClient,
|
|
9
|
+
} from '../../../../tests/utils'
|
|
10
|
+
import {
|
|
11
|
+
InfiniteQueryObserver,
|
|
12
|
+
QueryCache,
|
|
13
|
+
QueryClient,
|
|
14
|
+
QueryFunction,
|
|
15
|
+
QueryObserver,
|
|
16
|
+
} from '..'
|
|
17
|
+
import { focusManager, onlineManager } from '..'
|
|
18
|
+
|
|
19
|
+
describe('queryClient', () => {
|
|
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
|
+
describe('defaultOptions', () => {
|
|
34
|
+
test('should merge defaultOptions', async () => {
|
|
35
|
+
const key = queryKey()
|
|
36
|
+
|
|
37
|
+
const queryFn = () => 'data'
|
|
38
|
+
const testClient = createQueryClient({
|
|
39
|
+
defaultOptions: { queries: { queryFn } },
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
expect(() => testClient.prefetchQuery(key)).not.toThrow()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('should merge defaultOptions when query is added to cache', async () => {
|
|
46
|
+
const key = queryKey()
|
|
47
|
+
|
|
48
|
+
const testClient = createQueryClient({
|
|
49
|
+
defaultOptions: {
|
|
50
|
+
queries: { cacheTime: Infinity },
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const fetchData = () => Promise.resolve('data')
|
|
55
|
+
await testClient.prefetchQuery(key, fetchData)
|
|
56
|
+
const newQuery = testClient.getQueryCache().find(key)
|
|
57
|
+
expect(newQuery?.options.cacheTime).toBe(Infinity)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('should get defaultOptions', async () => {
|
|
61
|
+
const queryFn = () => 'data'
|
|
62
|
+
const defaultOptions = { queries: { queryFn } }
|
|
63
|
+
const testClient = createQueryClient({
|
|
64
|
+
defaultOptions,
|
|
65
|
+
})
|
|
66
|
+
expect(testClient.getDefaultOptions()).toMatchObject(defaultOptions)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe('setQueryDefaults', () => {
|
|
71
|
+
test('should not trigger a fetch', async () => {
|
|
72
|
+
const key = queryKey()
|
|
73
|
+
queryClient.setQueryDefaults(key, { queryFn: () => 'data' })
|
|
74
|
+
await sleep(1)
|
|
75
|
+
const data = queryClient.getQueryData(key)
|
|
76
|
+
expect(data).toBeUndefined()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test('should be able to override defaults', async () => {
|
|
80
|
+
const key = queryKey()
|
|
81
|
+
queryClient.setQueryDefaults(key, { queryFn: () => 'data' })
|
|
82
|
+
const observer = new QueryObserver(queryClient, { queryKey: key })
|
|
83
|
+
const { data } = await observer.refetch()
|
|
84
|
+
expect(data).toBe('data')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test('should match the query key partially', async () => {
|
|
88
|
+
const key = queryKey()
|
|
89
|
+
queryClient.setQueryDefaults([key], { queryFn: () => 'data' })
|
|
90
|
+
const observer = new QueryObserver(queryClient, {
|
|
91
|
+
queryKey: [key, 'a'],
|
|
92
|
+
})
|
|
93
|
+
const { data } = await observer.refetch()
|
|
94
|
+
expect(data).toBe('data')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test('should not match if the query key is a subset', async () => {
|
|
98
|
+
const key = queryKey()
|
|
99
|
+
queryClient.setQueryDefaults([key, 'a'], { queryFn: () => 'data' })
|
|
100
|
+
const observer = new QueryObserver(queryClient, {
|
|
101
|
+
queryKey: [key],
|
|
102
|
+
retry: false,
|
|
103
|
+
enabled: false,
|
|
104
|
+
})
|
|
105
|
+
const { status } = await observer.refetch()
|
|
106
|
+
expect(status).toBe('error')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
test('should also set defaults for observers', async () => {
|
|
110
|
+
const key = queryKey()
|
|
111
|
+
queryClient.setQueryDefaults(key, {
|
|
112
|
+
queryFn: () => 'data',
|
|
113
|
+
enabled: false,
|
|
114
|
+
})
|
|
115
|
+
const observer = new QueryObserver(queryClient, {
|
|
116
|
+
queryKey: [key],
|
|
117
|
+
})
|
|
118
|
+
expect(observer.getCurrentResult().status).toBe('loading')
|
|
119
|
+
expect(observer.getCurrentResult().fetchStatus).toBe('idle')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test('should update existing query defaults', async () => {
|
|
123
|
+
const key = queryKey()
|
|
124
|
+
const queryOptions1 = { queryFn: () => 'data' }
|
|
125
|
+
const queryOptions2 = { retry: false }
|
|
126
|
+
queryClient.setQueryDefaults(key, queryOptions1)
|
|
127
|
+
queryClient.setQueryDefaults(key, queryOptions2)
|
|
128
|
+
expect(queryClient.getQueryDefaults(key)).toMatchObject(queryOptions2)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test('should warn in dev if several query defaults match a given key', () => {
|
|
132
|
+
// Check discussion here: https://github.com/tannerlinsley/react-query/discussions/3199
|
|
133
|
+
const keyABCD = [
|
|
134
|
+
{
|
|
135
|
+
a: 'a',
|
|
136
|
+
b: 'b',
|
|
137
|
+
c: 'c',
|
|
138
|
+
d: 'd',
|
|
139
|
+
},
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
// The key below "contains" keyABCD => it is more generic
|
|
143
|
+
const keyABC = [
|
|
144
|
+
{
|
|
145
|
+
a: 'a',
|
|
146
|
+
b: 'b',
|
|
147
|
+
c: 'c',
|
|
148
|
+
},
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
// The defaults for query matching key "ABCD" (least generic)
|
|
152
|
+
const defaultsOfABCD = {
|
|
153
|
+
queryFn: function ABCDQueryFn() {
|
|
154
|
+
return 'ABCD'
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// The defaults for query matching key "ABC" (most generic)
|
|
159
|
+
const defaultsOfABC = {
|
|
160
|
+
queryFn: function ABCQueryFn() {
|
|
161
|
+
return 'ABC'
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// No defaults, no warning
|
|
166
|
+
const noDefaults = queryClient.getQueryDefaults(keyABCD)
|
|
167
|
+
expect(noDefaults).toBeUndefined()
|
|
168
|
+
expect(mockLogger.error).not.toHaveBeenCalled()
|
|
169
|
+
|
|
170
|
+
// If defaults for key ABCD are registered **before** the ones of key ABC (more generic)…
|
|
171
|
+
queryClient.setQueryDefaults(keyABCD, defaultsOfABCD)
|
|
172
|
+
queryClient.setQueryDefaults(keyABC, defaultsOfABC)
|
|
173
|
+
// … then the "good" defaults are retrieved: we get the ones for key "ABCD"
|
|
174
|
+
const goodDefaults = queryClient.getQueryDefaults(keyABCD)
|
|
175
|
+
expect(goodDefaults).toBe(defaultsOfABCD)
|
|
176
|
+
// The warning is still raised since several defaults are matching
|
|
177
|
+
expect(mockLogger.error).toHaveBeenCalledTimes(1)
|
|
178
|
+
|
|
179
|
+
// Let's create another queryClient and change the order of registration
|
|
180
|
+
const newQueryClient = createQueryClient()
|
|
181
|
+
// The defaults for key ABC (more generic) are registered **before** the ones of key ABCD…
|
|
182
|
+
newQueryClient.setQueryDefaults(keyABC, defaultsOfABC)
|
|
183
|
+
newQueryClient.setQueryDefaults(keyABCD, defaultsOfABCD)
|
|
184
|
+
// … then the "wrong" defaults are retrieved: we get the ones for key "ABC"
|
|
185
|
+
const badDefaults = newQueryClient.getQueryDefaults(keyABCD)
|
|
186
|
+
expect(badDefaults).not.toBe(defaultsOfABCD)
|
|
187
|
+
expect(badDefaults).toBe(defaultsOfABC)
|
|
188
|
+
expect(mockLogger.error).toHaveBeenCalledTimes(2)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test('should warn in dev if several mutation defaults match a given key', () => {
|
|
192
|
+
// Check discussion here: https://github.com/tannerlinsley/react-query/discussions/3199
|
|
193
|
+
const keyABCD = [
|
|
194
|
+
{
|
|
195
|
+
a: 'a',
|
|
196
|
+
b: 'b',
|
|
197
|
+
c: 'c',
|
|
198
|
+
d: 'd',
|
|
199
|
+
},
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
// The key below "contains" keyABCD => it is more generic
|
|
203
|
+
const keyABC = [
|
|
204
|
+
{
|
|
205
|
+
a: 'a',
|
|
206
|
+
b: 'b',
|
|
207
|
+
c: 'c',
|
|
208
|
+
},
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
// The defaults for mutation matching key "ABCD" (least generic)
|
|
212
|
+
const defaultsOfABCD = {
|
|
213
|
+
mutationFn: Promise.resolve,
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// The defaults for mutation matching key "ABC" (most generic)
|
|
217
|
+
const defaultsOfABC = {
|
|
218
|
+
mutationFn: Promise.resolve,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// No defaults, no warning
|
|
222
|
+
const noDefaults = queryClient.getMutationDefaults(keyABCD)
|
|
223
|
+
expect(noDefaults).toBeUndefined()
|
|
224
|
+
expect(mockLogger.error).not.toHaveBeenCalled()
|
|
225
|
+
|
|
226
|
+
// If defaults for key ABCD are registered **before** the ones of key ABC (more generic)…
|
|
227
|
+
queryClient.setMutationDefaults(keyABCD, defaultsOfABCD)
|
|
228
|
+
queryClient.setMutationDefaults(keyABC, defaultsOfABC)
|
|
229
|
+
// … then the "good" defaults are retrieved: we get the ones for key "ABCD"
|
|
230
|
+
const goodDefaults = queryClient.getMutationDefaults(keyABCD)
|
|
231
|
+
expect(goodDefaults).toBe(defaultsOfABCD)
|
|
232
|
+
// The warning is still raised since several defaults are matching
|
|
233
|
+
expect(mockLogger.error).toHaveBeenCalledTimes(1)
|
|
234
|
+
|
|
235
|
+
// Let's create another queryClient and change the order of registration
|
|
236
|
+
const newQueryClient = createQueryClient()
|
|
237
|
+
// The defaults for key ABC (more generic) are registered **before** the ones of key ABCD…
|
|
238
|
+
newQueryClient.setMutationDefaults(keyABC, defaultsOfABC)
|
|
239
|
+
newQueryClient.setMutationDefaults(keyABCD, defaultsOfABCD)
|
|
240
|
+
// … then the "wrong" defaults are retrieved: we get the ones for key "ABC"
|
|
241
|
+
const badDefaults = newQueryClient.getMutationDefaults(keyABCD)
|
|
242
|
+
expect(badDefaults).not.toBe(defaultsOfABCD)
|
|
243
|
+
expect(badDefaults).toBe(defaultsOfABC)
|
|
244
|
+
expect(mockLogger.error).toHaveBeenCalledTimes(2)
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
describe('setQueryData', () => {
|
|
249
|
+
test('should not crash if query could not be found', () => {
|
|
250
|
+
const key = queryKey()
|
|
251
|
+
const user = { userId: 1 }
|
|
252
|
+
expect(() => {
|
|
253
|
+
queryClient.setQueryData([key, user], (prevUser?: typeof user) => ({
|
|
254
|
+
...prevUser!,
|
|
255
|
+
name: 'Edvin',
|
|
256
|
+
}))
|
|
257
|
+
}).not.toThrow()
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test('should not crash when variable is null', () => {
|
|
261
|
+
const key = queryKey()
|
|
262
|
+
queryClient.setQueryData([key, { userId: null }], 'Old Data')
|
|
263
|
+
expect(() => {
|
|
264
|
+
queryClient.setQueryData([key, { userId: null }], 'New Data')
|
|
265
|
+
}).not.toThrow()
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
test('should use default options', () => {
|
|
269
|
+
const key = queryKey()
|
|
270
|
+
const testClient = createQueryClient({
|
|
271
|
+
defaultOptions: { queries: { queryKeyHashFn: () => 'someKey' } },
|
|
272
|
+
})
|
|
273
|
+
const testCache = testClient.getQueryCache()
|
|
274
|
+
testClient.setQueryData(key, 'data')
|
|
275
|
+
expect(testClient.getQueryData(key)).toBe('data')
|
|
276
|
+
expect(testCache.find(key)).toBe(testCache.get('someKey'))
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
test('should create a new query if query was not found', () => {
|
|
280
|
+
const key = queryKey()
|
|
281
|
+
queryClient.setQueryData(key, 'bar')
|
|
282
|
+
expect(queryClient.getQueryData(key)).toBe('bar')
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
test('should create a new query if query was not found', () => {
|
|
286
|
+
const key = queryKey()
|
|
287
|
+
queryClient.setQueryData(key, 'qux')
|
|
288
|
+
expect(queryClient.getQueryData(key)).toBe('qux')
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
test('should not create a new query if query was not found and data is undefined', () => {
|
|
292
|
+
const key = queryKey()
|
|
293
|
+
expect(queryClient.getQueryCache().find(key)).toBe(undefined)
|
|
294
|
+
queryClient.setQueryData(key, undefined)
|
|
295
|
+
expect(queryClient.getQueryCache().find(key)).toBe(undefined)
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
test('should not create a new query if query was not found and updater returns undefined', () => {
|
|
299
|
+
const key = queryKey()
|
|
300
|
+
expect(queryClient.getQueryCache().find(key)).toBe(undefined)
|
|
301
|
+
queryClient.setQueryData(key, () => undefined)
|
|
302
|
+
expect(queryClient.getQueryCache().find(key)).toBe(undefined)
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
test('should not update query data if data is undefined', () => {
|
|
306
|
+
const key = queryKey()
|
|
307
|
+
queryClient.setQueryData(key, 'qux')
|
|
308
|
+
queryClient.setQueryData(key, undefined)
|
|
309
|
+
expect(queryClient.getQueryData(key)).toBe('qux')
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
test('should not update query data if updater returns undefined', () => {
|
|
313
|
+
const key = queryKey()
|
|
314
|
+
queryClient.setQueryData<string>(key, 'qux')
|
|
315
|
+
queryClient.setQueryData<string>(key, () => undefined)
|
|
316
|
+
expect(queryClient.getQueryData(key)).toBe('qux')
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
test('should accept an update function', () => {
|
|
320
|
+
const key = queryKey()
|
|
321
|
+
|
|
322
|
+
const updater = jest.fn((oldData) => `new data + ${oldData}`)
|
|
323
|
+
|
|
324
|
+
queryClient.setQueryData(key, 'test data')
|
|
325
|
+
queryClient.setQueryData(key, updater)
|
|
326
|
+
|
|
327
|
+
expect(updater).toHaveBeenCalled()
|
|
328
|
+
expect(queryCache.find(key)!.state.data).toEqual('new data + test data')
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
test('should use prev data if an isDataEqual function is defined and returns "true"', () => {
|
|
332
|
+
const key = queryKey()
|
|
333
|
+
|
|
334
|
+
queryClient.setDefaultOptions({
|
|
335
|
+
queries: { isDataEqual: (_prev, data) => data === 'data' },
|
|
336
|
+
})
|
|
337
|
+
queryClient.setQueryData(key, 'prev data')
|
|
338
|
+
queryClient.setQueryData(key, 'data')
|
|
339
|
+
|
|
340
|
+
expect(queryCache.find(key)!.state.data).toEqual('prev data')
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
test('should set the new data without comparison if structuralSharing is set to false', () => {
|
|
344
|
+
const key = queryKey()
|
|
345
|
+
|
|
346
|
+
queryClient.setDefaultOptions({
|
|
347
|
+
queries: {
|
|
348
|
+
structuralSharing: false,
|
|
349
|
+
},
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
const oldData = { value: true }
|
|
353
|
+
const newData = { value: true }
|
|
354
|
+
queryClient.setQueryData(key, oldData)
|
|
355
|
+
queryClient.setQueryData(key, newData)
|
|
356
|
+
|
|
357
|
+
expect(queryCache.find(key)!.state.data).toBe(newData)
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
test('should not set isFetching to false', async () => {
|
|
361
|
+
const key = queryKey()
|
|
362
|
+
queryClient.prefetchQuery(key, async () => {
|
|
363
|
+
await sleep(10)
|
|
364
|
+
return 23
|
|
365
|
+
})
|
|
366
|
+
expect(queryClient.getQueryState(key)).toMatchObject({
|
|
367
|
+
data: undefined,
|
|
368
|
+
fetchStatus: 'fetching',
|
|
369
|
+
})
|
|
370
|
+
queryClient.setQueryData(key, 42)
|
|
371
|
+
expect(queryClient.getQueryState(key)).toMatchObject({
|
|
372
|
+
data: 42,
|
|
373
|
+
fetchStatus: 'fetching',
|
|
374
|
+
})
|
|
375
|
+
await waitFor(() =>
|
|
376
|
+
expect(queryClient.getQueryState(key)).toMatchObject({
|
|
377
|
+
data: 23,
|
|
378
|
+
fetchStatus: 'idle',
|
|
379
|
+
}),
|
|
380
|
+
)
|
|
381
|
+
})
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
describe('setQueriesData', () => {
|
|
385
|
+
test('should update all existing, matching queries', () => {
|
|
386
|
+
queryClient.setQueryData(['key', 1], 1)
|
|
387
|
+
queryClient.setQueryData(['key', 2], 2)
|
|
388
|
+
|
|
389
|
+
const result = queryClient.setQueriesData<number>(['key'], (old) =>
|
|
390
|
+
old ? old + 5 : undefined,
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
expect(result).toEqual([
|
|
394
|
+
[['key', 1], 6],
|
|
395
|
+
[['key', 2], 7],
|
|
396
|
+
])
|
|
397
|
+
expect(queryClient.getQueryData(['key', 1])).toBe(6)
|
|
398
|
+
expect(queryClient.getQueryData(['key', 2])).toBe(7)
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
test('should accept queryFilters', () => {
|
|
402
|
+
queryClient.setQueryData(['key', 1], 1)
|
|
403
|
+
queryClient.setQueryData(['key', 2], 2)
|
|
404
|
+
const query1 = queryCache.find(['key', 1])!
|
|
405
|
+
|
|
406
|
+
const result = queryClient.setQueriesData<number>(
|
|
407
|
+
{ predicate: (query) => query === query1 },
|
|
408
|
+
(old) => old! + 5,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
expect(result).toEqual([[['key', 1], 6]])
|
|
412
|
+
expect(queryClient.getQueryData(['key', 1])).toBe(6)
|
|
413
|
+
expect(queryClient.getQueryData(['key', 2])).toBe(2)
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
test('should not update non existing queries', () => {
|
|
417
|
+
const result = queryClient.setQueriesData<string>(['key'], 'data')
|
|
418
|
+
|
|
419
|
+
expect(result).toEqual([])
|
|
420
|
+
expect(queryClient.getQueryData(['key'])).toBe(undefined)
|
|
421
|
+
})
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
describe('getQueryData', () => {
|
|
425
|
+
test('should return the query data if the query is found', () => {
|
|
426
|
+
const key = queryKey()
|
|
427
|
+
queryClient.setQueryData([key, 'id'], 'bar')
|
|
428
|
+
expect(queryClient.getQueryData([key, 'id'])).toBe('bar')
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
test('should return undefined if the query is not found', () => {
|
|
432
|
+
const key = queryKey()
|
|
433
|
+
expect(queryClient.getQueryData(key)).toBeUndefined()
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
test('should match exact by default', () => {
|
|
437
|
+
const key = queryKey()
|
|
438
|
+
queryClient.setQueryData([key, 'id'], 'bar')
|
|
439
|
+
expect(queryClient.getQueryData([key])).toBeUndefined()
|
|
440
|
+
})
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
describe('getQueriesData', () => {
|
|
444
|
+
test('should return the query data for all matched queries', () => {
|
|
445
|
+
const key1 = queryKey()
|
|
446
|
+
const key2 = queryKey()
|
|
447
|
+
queryClient.setQueryData([key1, 1], 1)
|
|
448
|
+
queryClient.setQueryData([key1, 2], 2)
|
|
449
|
+
queryClient.setQueryData([key2, 2], 2)
|
|
450
|
+
expect(queryClient.getQueriesData([key1])).toEqual([
|
|
451
|
+
[[key1, 1], 1],
|
|
452
|
+
[[key1, 2], 2],
|
|
453
|
+
])
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
test('should return empty array if queries are not found', () => {
|
|
457
|
+
const key = queryKey()
|
|
458
|
+
expect(queryClient.getQueriesData(key)).toEqual([])
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
test('should accept query filters', () => {
|
|
462
|
+
queryClient.setQueryData(['key', 1], 1)
|
|
463
|
+
queryClient.setQueryData(['key', 2], 2)
|
|
464
|
+
const query1 = queryCache.find(['key', 1])!
|
|
465
|
+
|
|
466
|
+
const result = queryClient.getQueriesData({
|
|
467
|
+
predicate: (query) => query === query1,
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
expect(result).toEqual([[['key', 1], 1]])
|
|
471
|
+
})
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
describe('fetchQuery', () => {
|
|
475
|
+
test('should not type-error with strict query key', async () => {
|
|
476
|
+
type StrictData = 'data'
|
|
477
|
+
type StrictQueryKey = ['strict', ...ReturnType<typeof queryKey>]
|
|
478
|
+
const key: StrictQueryKey = ['strict', ...queryKey()]
|
|
479
|
+
|
|
480
|
+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () =>
|
|
481
|
+
Promise.resolve('data')
|
|
482
|
+
|
|
483
|
+
await expect(
|
|
484
|
+
queryClient.fetchQuery<StrictData, any, StrictData, StrictQueryKey>(
|
|
485
|
+
key,
|
|
486
|
+
fetchFn,
|
|
487
|
+
),
|
|
488
|
+
).resolves.toEqual('data')
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
// https://github.com/tannerlinsley/react-query/issues/652
|
|
492
|
+
test('should not retry by default', async () => {
|
|
493
|
+
const key = queryKey()
|
|
494
|
+
|
|
495
|
+
await expect(
|
|
496
|
+
queryClient.fetchQuery(key, async (): Promise<unknown> => {
|
|
497
|
+
throw new Error('error')
|
|
498
|
+
}),
|
|
499
|
+
).rejects.toEqual(new Error('error'))
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
test('should return the cached data on cache hit', async () => {
|
|
503
|
+
const key = queryKey()
|
|
504
|
+
|
|
505
|
+
const fetchFn = () => Promise.resolve('data')
|
|
506
|
+
const first = await queryClient.fetchQuery(key, fetchFn)
|
|
507
|
+
const second = await queryClient.fetchQuery(key, fetchFn)
|
|
508
|
+
|
|
509
|
+
expect(second).toBe(first)
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
test('should be able to fetch when cache time is set to 0 and then be removed', async () => {
|
|
513
|
+
const key1 = queryKey()
|
|
514
|
+
const result = await queryClient.fetchQuery(
|
|
515
|
+
key1,
|
|
516
|
+
async () => {
|
|
517
|
+
await sleep(10)
|
|
518
|
+
return 1
|
|
519
|
+
},
|
|
520
|
+
{ cacheTime: 0 },
|
|
521
|
+
)
|
|
522
|
+
expect(result).toEqual(1)
|
|
523
|
+
await waitFor(() =>
|
|
524
|
+
expect(queryClient.getQueryData(key1)).toEqual(undefined),
|
|
525
|
+
)
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
test('should keep a query in cache if cache time is Infinity', async () => {
|
|
529
|
+
const key1 = queryKey()
|
|
530
|
+
const result = await queryClient.fetchQuery(
|
|
531
|
+
key1,
|
|
532
|
+
async () => {
|
|
533
|
+
await sleep(10)
|
|
534
|
+
return 1
|
|
535
|
+
},
|
|
536
|
+
{ cacheTime: Infinity },
|
|
537
|
+
)
|
|
538
|
+
const result2 = queryClient.getQueryData(key1)
|
|
539
|
+
expect(result).toEqual(1)
|
|
540
|
+
expect(result2).toEqual(1)
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
test('should not force fetch', async () => {
|
|
544
|
+
const key = queryKey()
|
|
545
|
+
|
|
546
|
+
queryClient.setQueryData(key, 'og')
|
|
547
|
+
const fetchFn = () => Promise.resolve('new')
|
|
548
|
+
const first = await queryClient.fetchQuery(key, fetchFn, {
|
|
549
|
+
initialData: 'initial',
|
|
550
|
+
staleTime: 100,
|
|
551
|
+
})
|
|
552
|
+
expect(first).toBe('og')
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
test('should only fetch if the data is older then the given stale time', async () => {
|
|
556
|
+
const key = queryKey()
|
|
557
|
+
|
|
558
|
+
let count = 0
|
|
559
|
+
const fetchFn = () => ++count
|
|
560
|
+
|
|
561
|
+
queryClient.setQueryData(key, count)
|
|
562
|
+
const first = await queryClient.fetchQuery(key, fetchFn, {
|
|
563
|
+
staleTime: 100,
|
|
564
|
+
})
|
|
565
|
+
await sleep(11)
|
|
566
|
+
const second = await queryClient.fetchQuery(key, fetchFn, {
|
|
567
|
+
staleTime: 10,
|
|
568
|
+
})
|
|
569
|
+
const third = await queryClient.fetchQuery(key, fetchFn, {
|
|
570
|
+
staleTime: 10,
|
|
571
|
+
})
|
|
572
|
+
await sleep(11)
|
|
573
|
+
const fourth = await queryClient.fetchQuery(key, fetchFn, {
|
|
574
|
+
staleTime: 10,
|
|
575
|
+
})
|
|
576
|
+
expect(first).toBe(0)
|
|
577
|
+
expect(second).toBe(1)
|
|
578
|
+
expect(third).toBe(1)
|
|
579
|
+
expect(fourth).toBe(2)
|
|
580
|
+
})
|
|
581
|
+
})
|
|
582
|
+
|
|
583
|
+
describe('fetchInfiniteQuery', () => {
|
|
584
|
+
test('should not type-error with strict query key', async () => {
|
|
585
|
+
type StrictData = string
|
|
586
|
+
type StrictQueryKey = ['strict', ...ReturnType<typeof queryKey>]
|
|
587
|
+
const key: StrictQueryKey = ['strict', ...queryKey()]
|
|
588
|
+
|
|
589
|
+
const data = {
|
|
590
|
+
pages: ['data'],
|
|
591
|
+
pageParams: [undefined],
|
|
592
|
+
} as const
|
|
593
|
+
|
|
594
|
+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () =>
|
|
595
|
+
Promise.resolve(data.pages[0])
|
|
596
|
+
|
|
597
|
+
await expect(
|
|
598
|
+
queryClient.fetchInfiniteQuery<
|
|
599
|
+
StrictData,
|
|
600
|
+
any,
|
|
601
|
+
StrictData,
|
|
602
|
+
StrictQueryKey
|
|
603
|
+
>(key, fetchFn),
|
|
604
|
+
).resolves.toEqual(data)
|
|
605
|
+
})
|
|
606
|
+
|
|
607
|
+
test('should return infinite query data', async () => {
|
|
608
|
+
const key = queryKey()
|
|
609
|
+
const result = await queryClient.fetchInfiniteQuery(
|
|
610
|
+
key,
|
|
611
|
+
({ pageParam = 10 }) => Number(pageParam),
|
|
612
|
+
)
|
|
613
|
+
const result2 = queryClient.getQueryData(key)
|
|
614
|
+
|
|
615
|
+
const expected = {
|
|
616
|
+
pages: [10],
|
|
617
|
+
pageParams: [undefined],
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
expect(result).toEqual(expected)
|
|
621
|
+
expect(result2).toEqual(expected)
|
|
622
|
+
})
|
|
623
|
+
})
|
|
624
|
+
|
|
625
|
+
describe('prefetchInfiniteQuery', () => {
|
|
626
|
+
test('should not type-error with strict query key', async () => {
|
|
627
|
+
type StrictData = 'data'
|
|
628
|
+
type StrictQueryKey = ['strict', ...ReturnType<typeof queryKey>]
|
|
629
|
+
const key: StrictQueryKey = ['strict', ...queryKey()]
|
|
630
|
+
|
|
631
|
+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () =>
|
|
632
|
+
Promise.resolve('data')
|
|
633
|
+
|
|
634
|
+
await queryClient.prefetchInfiniteQuery<
|
|
635
|
+
StrictData,
|
|
636
|
+
any,
|
|
637
|
+
StrictData,
|
|
638
|
+
StrictQueryKey
|
|
639
|
+
>(key, fetchFn)
|
|
640
|
+
|
|
641
|
+
const result = queryClient.getQueryData(key)
|
|
642
|
+
|
|
643
|
+
expect(result).toEqual({
|
|
644
|
+
pages: ['data'],
|
|
645
|
+
pageParams: [undefined],
|
|
646
|
+
})
|
|
647
|
+
})
|
|
648
|
+
|
|
649
|
+
test('should return infinite query data', async () => {
|
|
650
|
+
const key = queryKey()
|
|
651
|
+
|
|
652
|
+
await queryClient.prefetchInfiniteQuery(key, ({ pageParam = 10 }) =>
|
|
653
|
+
Number(pageParam),
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
const result = queryClient.getQueryData(key)
|
|
657
|
+
|
|
658
|
+
expect(result).toEqual({
|
|
659
|
+
pages: [10],
|
|
660
|
+
pageParams: [undefined],
|
|
661
|
+
})
|
|
662
|
+
})
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
describe('prefetchQuery', () => {
|
|
666
|
+
test('should not type-error with strict query key', async () => {
|
|
667
|
+
type StrictData = 'data'
|
|
668
|
+
type StrictQueryKey = ['strict', ...ReturnType<typeof queryKey>]
|
|
669
|
+
const key: StrictQueryKey = ['strict', ...queryKey()]
|
|
670
|
+
|
|
671
|
+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () =>
|
|
672
|
+
Promise.resolve('data')
|
|
673
|
+
|
|
674
|
+
await queryClient.prefetchQuery<
|
|
675
|
+
StrictData,
|
|
676
|
+
any,
|
|
677
|
+
StrictData,
|
|
678
|
+
StrictQueryKey
|
|
679
|
+
>(key, fetchFn)
|
|
680
|
+
|
|
681
|
+
const result = queryClient.getQueryData(key)
|
|
682
|
+
|
|
683
|
+
expect(result).toEqual('data')
|
|
684
|
+
})
|
|
685
|
+
|
|
686
|
+
test('should return undefined when an error is thrown', async () => {
|
|
687
|
+
const key = queryKey()
|
|
688
|
+
|
|
689
|
+
const result = await queryClient.prefetchQuery(
|
|
690
|
+
key,
|
|
691
|
+
async (): Promise<unknown> => {
|
|
692
|
+
throw new Error('error')
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
retry: false,
|
|
696
|
+
},
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
expect(result).toBeUndefined()
|
|
700
|
+
expect(mockLogger.error).toHaveBeenCalled()
|
|
701
|
+
})
|
|
702
|
+
|
|
703
|
+
test('should be garbage collected after cacheTime if unused', async () => {
|
|
704
|
+
const key = queryKey()
|
|
705
|
+
|
|
706
|
+
await queryClient.prefetchQuery(
|
|
707
|
+
key,
|
|
708
|
+
async () => {
|
|
709
|
+
return 'data'
|
|
710
|
+
},
|
|
711
|
+
{ cacheTime: 10 },
|
|
712
|
+
)
|
|
713
|
+
expect(queryCache.find(key)).toBeDefined()
|
|
714
|
+
await sleep(15)
|
|
715
|
+
expect(queryCache.find(key)).not.toBeDefined()
|
|
716
|
+
})
|
|
717
|
+
})
|
|
718
|
+
|
|
719
|
+
describe('removeQueries', () => {
|
|
720
|
+
test('should not crash when exact is provided', async () => {
|
|
721
|
+
const key = queryKey()
|
|
722
|
+
|
|
723
|
+
const fetchFn = () => Promise.resolve('data')
|
|
724
|
+
|
|
725
|
+
// check the query was added to the cache
|
|
726
|
+
await queryClient.prefetchQuery(key, fetchFn)
|
|
727
|
+
expect(queryCache.find(key)).toBeTruthy()
|
|
728
|
+
|
|
729
|
+
// check the error doesn't occur
|
|
730
|
+
expect(() =>
|
|
731
|
+
queryClient.removeQueries({ queryKey: key, exact: true }),
|
|
732
|
+
).not.toThrow()
|
|
733
|
+
|
|
734
|
+
// check query was successful removed
|
|
735
|
+
expect(queryCache.find(key)).toBeFalsy()
|
|
736
|
+
})
|
|
737
|
+
})
|
|
738
|
+
|
|
739
|
+
describe('cancelQueries', () => {
|
|
740
|
+
test('should revert queries to their previous state', async () => {
|
|
741
|
+
const key1 = queryKey()
|
|
742
|
+
const key2 = queryKey()
|
|
743
|
+
const key3 = queryKey()
|
|
744
|
+
await queryClient.fetchQuery(key1, async () => {
|
|
745
|
+
return 'data'
|
|
746
|
+
})
|
|
747
|
+
try {
|
|
748
|
+
await queryClient.fetchQuery(key2, async () => {
|
|
749
|
+
return Promise.reject<unknown>('err')
|
|
750
|
+
})
|
|
751
|
+
} catch {}
|
|
752
|
+
queryClient.fetchQuery(key1, async () => {
|
|
753
|
+
await sleep(1000)
|
|
754
|
+
return 'data2'
|
|
755
|
+
})
|
|
756
|
+
try {
|
|
757
|
+
queryClient.fetchQuery(key2, async () => {
|
|
758
|
+
await sleep(1000)
|
|
759
|
+
return Promise.reject<unknown>('err2')
|
|
760
|
+
})
|
|
761
|
+
} catch {}
|
|
762
|
+
queryClient.fetchQuery(key3, async () => {
|
|
763
|
+
await sleep(1000)
|
|
764
|
+
return 'data3'
|
|
765
|
+
})
|
|
766
|
+
await sleep(10)
|
|
767
|
+
await queryClient.cancelQueries()
|
|
768
|
+
const state1 = queryClient.getQueryState(key1)
|
|
769
|
+
const state2 = queryClient.getQueryState(key2)
|
|
770
|
+
const state3 = queryClient.getQueryState(key3)
|
|
771
|
+
expect(state1).toMatchObject({
|
|
772
|
+
data: 'data',
|
|
773
|
+
status: 'success',
|
|
774
|
+
})
|
|
775
|
+
expect(state2).toMatchObject({
|
|
776
|
+
data: undefined,
|
|
777
|
+
error: 'err',
|
|
778
|
+
status: 'error',
|
|
779
|
+
})
|
|
780
|
+
expect(state3).toMatchObject({
|
|
781
|
+
data: undefined,
|
|
782
|
+
status: 'loading',
|
|
783
|
+
fetchStatus: 'idle',
|
|
784
|
+
})
|
|
785
|
+
})
|
|
786
|
+
|
|
787
|
+
test('should not revert if revert option is set to false', async () => {
|
|
788
|
+
const key1 = queryKey()
|
|
789
|
+
await queryClient.fetchQuery(key1, async () => {
|
|
790
|
+
return 'data'
|
|
791
|
+
})
|
|
792
|
+
queryClient.fetchQuery(key1, async () => {
|
|
793
|
+
await sleep(1000)
|
|
794
|
+
return 'data2'
|
|
795
|
+
})
|
|
796
|
+
await sleep(10)
|
|
797
|
+
await queryClient.cancelQueries(key1, {}, { revert: false })
|
|
798
|
+
const state1 = queryClient.getQueryState(key1)
|
|
799
|
+
expect(state1).toMatchObject({
|
|
800
|
+
status: 'error',
|
|
801
|
+
})
|
|
802
|
+
})
|
|
803
|
+
})
|
|
804
|
+
|
|
805
|
+
describe('refetchQueries', () => {
|
|
806
|
+
test('should not refetch if all observers are disabled', async () => {
|
|
807
|
+
const key = queryKey()
|
|
808
|
+
const queryFn = jest.fn<string, unknown[]>().mockReturnValue('data')
|
|
809
|
+
await queryClient.fetchQuery(key, queryFn)
|
|
810
|
+
const observer1 = new QueryObserver(queryClient, {
|
|
811
|
+
queryKey: key,
|
|
812
|
+
queryFn,
|
|
813
|
+
enabled: false,
|
|
814
|
+
})
|
|
815
|
+
observer1.subscribe(() => undefined)
|
|
816
|
+
await queryClient.refetchQueries()
|
|
817
|
+
observer1.destroy()
|
|
818
|
+
expect(queryFn).toHaveBeenCalledTimes(1)
|
|
819
|
+
})
|
|
820
|
+
test('should refetch if at least one observer is enabled', async () => {
|
|
821
|
+
const key = queryKey()
|
|
822
|
+
const queryFn = jest.fn<string, unknown[]>().mockReturnValue('data')
|
|
823
|
+
await queryClient.fetchQuery(key, queryFn)
|
|
824
|
+
const observer1 = new QueryObserver(queryClient, {
|
|
825
|
+
queryKey: key,
|
|
826
|
+
queryFn,
|
|
827
|
+
enabled: false,
|
|
828
|
+
})
|
|
829
|
+
const observer2 = new QueryObserver(queryClient, {
|
|
830
|
+
queryKey: key,
|
|
831
|
+
queryFn,
|
|
832
|
+
refetchOnMount: false,
|
|
833
|
+
})
|
|
834
|
+
observer1.subscribe(() => undefined)
|
|
835
|
+
observer2.subscribe(() => undefined)
|
|
836
|
+
await queryClient.refetchQueries()
|
|
837
|
+
observer1.destroy()
|
|
838
|
+
observer2.destroy()
|
|
839
|
+
expect(queryFn).toHaveBeenCalledTimes(2)
|
|
840
|
+
})
|
|
841
|
+
test('should refetch all queries when no arguments are given', async () => {
|
|
842
|
+
const key1 = queryKey()
|
|
843
|
+
const key2 = queryKey()
|
|
844
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
845
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
846
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
847
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
848
|
+
const observer1 = new QueryObserver(queryClient, {
|
|
849
|
+
queryKey: key1,
|
|
850
|
+
staleTime: Infinity,
|
|
851
|
+
initialData: 'initial',
|
|
852
|
+
})
|
|
853
|
+
const observer2 = new QueryObserver(queryClient, {
|
|
854
|
+
queryKey: key1,
|
|
855
|
+
staleTime: Infinity,
|
|
856
|
+
initialData: 'initial',
|
|
857
|
+
})
|
|
858
|
+
observer1.subscribe(() => undefined)
|
|
859
|
+
observer2.subscribe(() => undefined)
|
|
860
|
+
await queryClient.refetchQueries()
|
|
861
|
+
observer1.destroy()
|
|
862
|
+
observer2.destroy()
|
|
863
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
864
|
+
expect(queryFn2).toHaveBeenCalledTimes(2)
|
|
865
|
+
})
|
|
866
|
+
|
|
867
|
+
test('should be able to refetch all fresh queries', async () => {
|
|
868
|
+
const key1 = queryKey()
|
|
869
|
+
const key2 = queryKey()
|
|
870
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
871
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
872
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
873
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
874
|
+
const observer = new QueryObserver(queryClient, {
|
|
875
|
+
queryKey: key1,
|
|
876
|
+
queryFn: queryFn1,
|
|
877
|
+
staleTime: Infinity,
|
|
878
|
+
})
|
|
879
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
880
|
+
await queryClient.refetchQueries({ type: 'active', stale: false })
|
|
881
|
+
unsubscribe()
|
|
882
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
883
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
884
|
+
})
|
|
885
|
+
|
|
886
|
+
test('should be able to refetch all stale queries', async () => {
|
|
887
|
+
const key1 = queryKey()
|
|
888
|
+
const key2 = queryKey()
|
|
889
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
890
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
891
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
892
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
893
|
+
const observer = new QueryObserver(queryClient, {
|
|
894
|
+
queryKey: key1,
|
|
895
|
+
queryFn: queryFn1,
|
|
896
|
+
})
|
|
897
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
898
|
+
queryClient.invalidateQueries(key1)
|
|
899
|
+
await queryClient.refetchQueries({ stale: true })
|
|
900
|
+
unsubscribe()
|
|
901
|
+
// fetchQuery, observer mount, invalidation (cancels observer mount) and refetch
|
|
902
|
+
expect(queryFn1).toHaveBeenCalledTimes(4)
|
|
903
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
904
|
+
})
|
|
905
|
+
|
|
906
|
+
test('should be able to refetch all stale and active queries', async () => {
|
|
907
|
+
const key1 = queryKey()
|
|
908
|
+
const key2 = queryKey()
|
|
909
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
910
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
911
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
912
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
913
|
+
queryClient.invalidateQueries(key1)
|
|
914
|
+
const observer = new QueryObserver(queryClient, {
|
|
915
|
+
queryKey: key1,
|
|
916
|
+
queryFn: queryFn1,
|
|
917
|
+
})
|
|
918
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
919
|
+
await queryClient.refetchQueries(
|
|
920
|
+
{ type: 'active', stale: true },
|
|
921
|
+
{ cancelRefetch: false },
|
|
922
|
+
)
|
|
923
|
+
unsubscribe()
|
|
924
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
925
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
926
|
+
})
|
|
927
|
+
|
|
928
|
+
test('should be able to refetch all active and inactive queries', async () => {
|
|
929
|
+
const key1 = queryKey()
|
|
930
|
+
const key2 = queryKey()
|
|
931
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
932
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
933
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
934
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
935
|
+
const observer = new QueryObserver(queryClient, {
|
|
936
|
+
queryKey: key1,
|
|
937
|
+
queryFn: queryFn1,
|
|
938
|
+
staleTime: Infinity,
|
|
939
|
+
})
|
|
940
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
941
|
+
await queryClient.refetchQueries()
|
|
942
|
+
unsubscribe()
|
|
943
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
944
|
+
expect(queryFn2).toHaveBeenCalledTimes(2)
|
|
945
|
+
})
|
|
946
|
+
|
|
947
|
+
test('should be able to refetch all active and inactive queries', async () => {
|
|
948
|
+
const key1 = queryKey()
|
|
949
|
+
const key2 = queryKey()
|
|
950
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
951
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
952
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
953
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
954
|
+
const observer = new QueryObserver(queryClient, {
|
|
955
|
+
queryKey: key1,
|
|
956
|
+
queryFn: queryFn1,
|
|
957
|
+
staleTime: Infinity,
|
|
958
|
+
})
|
|
959
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
960
|
+
await queryClient.refetchQueries({ type: 'all' })
|
|
961
|
+
unsubscribe()
|
|
962
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
963
|
+
expect(queryFn2).toHaveBeenCalledTimes(2)
|
|
964
|
+
})
|
|
965
|
+
|
|
966
|
+
test('should be able to refetch only active queries', async () => {
|
|
967
|
+
const key1 = queryKey()
|
|
968
|
+
const key2 = queryKey()
|
|
969
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
970
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
971
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
972
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
973
|
+
const observer = new QueryObserver(queryClient, {
|
|
974
|
+
queryKey: key1,
|
|
975
|
+
queryFn: queryFn1,
|
|
976
|
+
staleTime: Infinity,
|
|
977
|
+
})
|
|
978
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
979
|
+
await queryClient.refetchQueries({ type: 'active' })
|
|
980
|
+
unsubscribe()
|
|
981
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
982
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
983
|
+
})
|
|
984
|
+
|
|
985
|
+
test('should be able to refetch only inactive queries', async () => {
|
|
986
|
+
const key1 = queryKey()
|
|
987
|
+
const key2 = queryKey()
|
|
988
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
989
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
990
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
991
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
992
|
+
const observer = new QueryObserver(queryClient, {
|
|
993
|
+
queryKey: key1,
|
|
994
|
+
queryFn: queryFn1,
|
|
995
|
+
staleTime: Infinity,
|
|
996
|
+
})
|
|
997
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
998
|
+
await queryClient.refetchQueries({ type: 'inactive' })
|
|
999
|
+
unsubscribe()
|
|
1000
|
+
expect(queryFn1).toHaveBeenCalledTimes(1)
|
|
1001
|
+
expect(queryFn2).toHaveBeenCalledTimes(2)
|
|
1002
|
+
})
|
|
1003
|
+
|
|
1004
|
+
test('should throw an error if throwOnError option is set to true', async () => {
|
|
1005
|
+
const key1 = queryKey()
|
|
1006
|
+
const queryFnError = () => Promise.reject<unknown>('error')
|
|
1007
|
+
try {
|
|
1008
|
+
await queryClient.fetchQuery({
|
|
1009
|
+
queryKey: key1,
|
|
1010
|
+
queryFn: queryFnError,
|
|
1011
|
+
retry: false,
|
|
1012
|
+
})
|
|
1013
|
+
} catch {}
|
|
1014
|
+
let error: any
|
|
1015
|
+
try {
|
|
1016
|
+
await queryClient.refetchQueries(
|
|
1017
|
+
{ queryKey: key1 },
|
|
1018
|
+
{ throwOnError: true },
|
|
1019
|
+
)
|
|
1020
|
+
} catch (err) {
|
|
1021
|
+
error = err
|
|
1022
|
+
}
|
|
1023
|
+
expect(error).toEqual('error')
|
|
1024
|
+
})
|
|
1025
|
+
})
|
|
1026
|
+
|
|
1027
|
+
describe('invalidateQueries', () => {
|
|
1028
|
+
test('should refetch active queries by default', async () => {
|
|
1029
|
+
const key1 = queryKey()
|
|
1030
|
+
const key2 = queryKey()
|
|
1031
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
1032
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
1033
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
1034
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
1035
|
+
const observer = new QueryObserver(queryClient, {
|
|
1036
|
+
queryKey: key1,
|
|
1037
|
+
queryFn: queryFn1,
|
|
1038
|
+
staleTime: Infinity,
|
|
1039
|
+
})
|
|
1040
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
1041
|
+
queryClient.invalidateQueries(key1)
|
|
1042
|
+
unsubscribe()
|
|
1043
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
1044
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
1045
|
+
})
|
|
1046
|
+
|
|
1047
|
+
test('should not refetch inactive queries by default', async () => {
|
|
1048
|
+
const key1 = queryKey()
|
|
1049
|
+
const key2 = queryKey()
|
|
1050
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
1051
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
1052
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
1053
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
1054
|
+
const observer = new QueryObserver(queryClient, {
|
|
1055
|
+
queryKey: key1,
|
|
1056
|
+
enabled: false,
|
|
1057
|
+
staleTime: Infinity,
|
|
1058
|
+
})
|
|
1059
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
1060
|
+
queryClient.invalidateQueries(key1)
|
|
1061
|
+
unsubscribe()
|
|
1062
|
+
expect(queryFn1).toHaveBeenCalledTimes(1)
|
|
1063
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
1064
|
+
})
|
|
1065
|
+
|
|
1066
|
+
test('should not refetch active queries when "refetch" is "none"', async () => {
|
|
1067
|
+
const key1 = queryKey()
|
|
1068
|
+
const key2 = queryKey()
|
|
1069
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
1070
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
1071
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
1072
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
1073
|
+
const observer = new QueryObserver(queryClient, {
|
|
1074
|
+
queryKey: key1,
|
|
1075
|
+
queryFn: queryFn1,
|
|
1076
|
+
staleTime: Infinity,
|
|
1077
|
+
})
|
|
1078
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
1079
|
+
queryClient.invalidateQueries(key1, {
|
|
1080
|
+
refetchType: 'none',
|
|
1081
|
+
})
|
|
1082
|
+
unsubscribe()
|
|
1083
|
+
expect(queryFn1).toHaveBeenCalledTimes(1)
|
|
1084
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
1085
|
+
})
|
|
1086
|
+
|
|
1087
|
+
test('should refetch inactive queries when "refetch" is "inactive"', async () => {
|
|
1088
|
+
const key1 = queryKey()
|
|
1089
|
+
const key2 = queryKey()
|
|
1090
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
1091
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
1092
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
1093
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
1094
|
+
const observer = new QueryObserver(queryClient, {
|
|
1095
|
+
queryKey: key1,
|
|
1096
|
+
queryFn: queryFn1,
|
|
1097
|
+
staleTime: Infinity,
|
|
1098
|
+
refetchOnMount: false,
|
|
1099
|
+
})
|
|
1100
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
1101
|
+
unsubscribe()
|
|
1102
|
+
|
|
1103
|
+
await queryClient.invalidateQueries(key1, {
|
|
1104
|
+
refetchType: 'inactive',
|
|
1105
|
+
})
|
|
1106
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
1107
|
+
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
1108
|
+
})
|
|
1109
|
+
|
|
1110
|
+
test('should refetch active and inactive queries when "refetch" is "all"', async () => {
|
|
1111
|
+
const key1 = queryKey()
|
|
1112
|
+
const key2 = queryKey()
|
|
1113
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
1114
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
1115
|
+
await queryClient.fetchQuery(key1, queryFn1)
|
|
1116
|
+
await queryClient.fetchQuery(key2, queryFn2)
|
|
1117
|
+
const observer = new QueryObserver(queryClient, {
|
|
1118
|
+
queryKey: key1,
|
|
1119
|
+
queryFn: queryFn1,
|
|
1120
|
+
staleTime: Infinity,
|
|
1121
|
+
})
|
|
1122
|
+
const unsubscribe = observer.subscribe(() => undefined)
|
|
1123
|
+
queryClient.invalidateQueries({
|
|
1124
|
+
refetchType: 'all',
|
|
1125
|
+
})
|
|
1126
|
+
unsubscribe()
|
|
1127
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
1128
|
+
expect(queryFn2).toHaveBeenCalledTimes(2)
|
|
1129
|
+
})
|
|
1130
|
+
|
|
1131
|
+
test('should cancel ongoing fetches if cancelRefetch option is set (default value)', async () => {
|
|
1132
|
+
const key = queryKey()
|
|
1133
|
+
const abortFn = jest.fn()
|
|
1134
|
+
let fetchCount = 0
|
|
1135
|
+
const observer = new QueryObserver(queryClient, {
|
|
1136
|
+
queryKey: key,
|
|
1137
|
+
queryFn: ({ signal }) => {
|
|
1138
|
+
return new Promise((resolve) => {
|
|
1139
|
+
fetchCount++
|
|
1140
|
+
setTimeout(() => resolve(5), 10)
|
|
1141
|
+
if (signal) {
|
|
1142
|
+
signal.addEventListener('abort', abortFn)
|
|
1143
|
+
}
|
|
1144
|
+
})
|
|
1145
|
+
},
|
|
1146
|
+
initialData: 1,
|
|
1147
|
+
})
|
|
1148
|
+
observer.subscribe(() => undefined)
|
|
1149
|
+
|
|
1150
|
+
await queryClient.refetchQueries()
|
|
1151
|
+
observer.destroy()
|
|
1152
|
+
if (typeof AbortSignal === 'function') {
|
|
1153
|
+
expect(abortFn).toHaveBeenCalledTimes(1)
|
|
1154
|
+
}
|
|
1155
|
+
expect(fetchCount).toBe(2)
|
|
1156
|
+
})
|
|
1157
|
+
|
|
1158
|
+
test('should not cancel ongoing fetches if cancelRefetch option is set to false', async () => {
|
|
1159
|
+
const key = queryKey()
|
|
1160
|
+
const abortFn = jest.fn()
|
|
1161
|
+
let fetchCount = 0
|
|
1162
|
+
const observer = new QueryObserver(queryClient, {
|
|
1163
|
+
queryKey: key,
|
|
1164
|
+
queryFn: ({ signal }) => {
|
|
1165
|
+
return new Promise((resolve) => {
|
|
1166
|
+
fetchCount++
|
|
1167
|
+
setTimeout(() => resolve(5), 10)
|
|
1168
|
+
if (signal) {
|
|
1169
|
+
signal.addEventListener('abort', abortFn)
|
|
1170
|
+
}
|
|
1171
|
+
})
|
|
1172
|
+
},
|
|
1173
|
+
initialData: 1,
|
|
1174
|
+
})
|
|
1175
|
+
observer.subscribe(() => undefined)
|
|
1176
|
+
|
|
1177
|
+
await queryClient.refetchQueries(undefined, { cancelRefetch: false })
|
|
1178
|
+
observer.destroy()
|
|
1179
|
+
if (typeof AbortSignal === 'function') {
|
|
1180
|
+
expect(abortFn).toHaveBeenCalledTimes(0)
|
|
1181
|
+
}
|
|
1182
|
+
expect(fetchCount).toBe(1)
|
|
1183
|
+
})
|
|
1184
|
+
})
|
|
1185
|
+
|
|
1186
|
+
describe('resetQueries', () => {
|
|
1187
|
+
test('should notify listeners when a query is reset', async () => {
|
|
1188
|
+
const key = queryKey()
|
|
1189
|
+
|
|
1190
|
+
const callback = jest.fn()
|
|
1191
|
+
|
|
1192
|
+
await queryClient.prefetchQuery(key, () => 'data')
|
|
1193
|
+
|
|
1194
|
+
queryCache.subscribe(callback)
|
|
1195
|
+
|
|
1196
|
+
queryClient.resetQueries(key)
|
|
1197
|
+
|
|
1198
|
+
expect(callback).toHaveBeenCalled()
|
|
1199
|
+
})
|
|
1200
|
+
|
|
1201
|
+
test('should reset query', async () => {
|
|
1202
|
+
const key = queryKey()
|
|
1203
|
+
|
|
1204
|
+
await queryClient.prefetchQuery(key, () => 'data')
|
|
1205
|
+
|
|
1206
|
+
let state = queryClient.getQueryState(key)
|
|
1207
|
+
expect(state?.data).toEqual('data')
|
|
1208
|
+
expect(state?.status).toEqual('success')
|
|
1209
|
+
|
|
1210
|
+
queryClient.resetQueries(key)
|
|
1211
|
+
|
|
1212
|
+
state = queryClient.getQueryState(key)
|
|
1213
|
+
|
|
1214
|
+
expect(state).toBeTruthy()
|
|
1215
|
+
expect(state?.data).toBeUndefined()
|
|
1216
|
+
expect(state?.status).toEqual('loading')
|
|
1217
|
+
expect(state?.fetchStatus).toEqual('idle')
|
|
1218
|
+
})
|
|
1219
|
+
|
|
1220
|
+
test('should reset query data to initial data if set', async () => {
|
|
1221
|
+
const key = queryKey()
|
|
1222
|
+
|
|
1223
|
+
await queryClient.prefetchQuery(key, () => 'data', {
|
|
1224
|
+
initialData: 'initial',
|
|
1225
|
+
})
|
|
1226
|
+
|
|
1227
|
+
let state = queryClient.getQueryState(key)
|
|
1228
|
+
expect(state?.data).toEqual('data')
|
|
1229
|
+
|
|
1230
|
+
queryClient.resetQueries(key)
|
|
1231
|
+
|
|
1232
|
+
state = queryClient.getQueryState(key)
|
|
1233
|
+
|
|
1234
|
+
expect(state).toBeTruthy()
|
|
1235
|
+
expect(state?.data).toEqual('initial')
|
|
1236
|
+
})
|
|
1237
|
+
|
|
1238
|
+
test('should refetch all active queries', async () => {
|
|
1239
|
+
const key1 = queryKey()
|
|
1240
|
+
const key2 = queryKey()
|
|
1241
|
+
const queryFn1 = jest.fn<string, unknown[]>().mockReturnValue('data1')
|
|
1242
|
+
const queryFn2 = jest.fn<string, unknown[]>().mockReturnValue('data2')
|
|
1243
|
+
const observer1 = new QueryObserver(queryClient, {
|
|
1244
|
+
queryKey: key1,
|
|
1245
|
+
queryFn: queryFn1,
|
|
1246
|
+
enabled: true,
|
|
1247
|
+
})
|
|
1248
|
+
const observer2 = new QueryObserver(queryClient, {
|
|
1249
|
+
queryKey: key2,
|
|
1250
|
+
queryFn: queryFn2,
|
|
1251
|
+
enabled: false,
|
|
1252
|
+
})
|
|
1253
|
+
observer1.subscribe(() => undefined)
|
|
1254
|
+
observer2.subscribe(() => undefined)
|
|
1255
|
+
await queryClient.resetQueries()
|
|
1256
|
+
observer2.destroy()
|
|
1257
|
+
observer1.destroy()
|
|
1258
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
1259
|
+
expect(queryFn2).toHaveBeenCalledTimes(0)
|
|
1260
|
+
})
|
|
1261
|
+
})
|
|
1262
|
+
|
|
1263
|
+
describe('refetch only certain pages of an infinite query', () => {
|
|
1264
|
+
test('refetchQueries', async () => {
|
|
1265
|
+
const key = queryKey()
|
|
1266
|
+
let multiplier = 1
|
|
1267
|
+
const observer = new InfiniteQueryObserver<number>(queryClient, {
|
|
1268
|
+
queryKey: key,
|
|
1269
|
+
queryFn: ({ pageParam = 10 }) => Number(pageParam) * multiplier,
|
|
1270
|
+
getNextPageParam: (lastPage) => lastPage + 1,
|
|
1271
|
+
})
|
|
1272
|
+
|
|
1273
|
+
await observer.fetchNextPage()
|
|
1274
|
+
await observer.fetchNextPage()
|
|
1275
|
+
|
|
1276
|
+
expect(queryClient.getQueryData(key)).toMatchObject({
|
|
1277
|
+
pages: [10, 11],
|
|
1278
|
+
})
|
|
1279
|
+
|
|
1280
|
+
multiplier = 2
|
|
1281
|
+
|
|
1282
|
+
await queryClient.refetchQueries({
|
|
1283
|
+
queryKey: key,
|
|
1284
|
+
refetchPage: (_, index) => index === 0,
|
|
1285
|
+
})
|
|
1286
|
+
|
|
1287
|
+
expect(queryClient.getQueryData(key)).toMatchObject({
|
|
1288
|
+
pages: [20, 11],
|
|
1289
|
+
})
|
|
1290
|
+
})
|
|
1291
|
+
test('invalidateQueries', async () => {
|
|
1292
|
+
const key = queryKey()
|
|
1293
|
+
let multiplier = 1
|
|
1294
|
+
const observer = new InfiniteQueryObserver<number>(queryClient, {
|
|
1295
|
+
queryKey: key,
|
|
1296
|
+
queryFn: ({ pageParam = 10 }) => Number(pageParam) * multiplier,
|
|
1297
|
+
getNextPageParam: (lastPage) => lastPage + 1,
|
|
1298
|
+
})
|
|
1299
|
+
|
|
1300
|
+
await observer.fetchNextPage()
|
|
1301
|
+
await observer.fetchNextPage()
|
|
1302
|
+
|
|
1303
|
+
expect(queryClient.getQueryData(key)).toMatchObject({
|
|
1304
|
+
pages: [10, 11],
|
|
1305
|
+
})
|
|
1306
|
+
|
|
1307
|
+
multiplier = 2
|
|
1308
|
+
|
|
1309
|
+
await queryClient.invalidateQueries({
|
|
1310
|
+
queryKey: key,
|
|
1311
|
+
refetchType: 'all',
|
|
1312
|
+
refetchPage: (page, _, allPages) => {
|
|
1313
|
+
return page === allPages[0]
|
|
1314
|
+
},
|
|
1315
|
+
})
|
|
1316
|
+
|
|
1317
|
+
expect(queryClient.getQueryData(key)).toMatchObject({
|
|
1318
|
+
pages: [20, 11],
|
|
1319
|
+
})
|
|
1320
|
+
})
|
|
1321
|
+
|
|
1322
|
+
test('resetQueries', async () => {
|
|
1323
|
+
const key = queryKey()
|
|
1324
|
+
let multiplier = 1
|
|
1325
|
+
new InfiniteQueryObserver<number>(queryClient, {
|
|
1326
|
+
queryKey: key,
|
|
1327
|
+
queryFn: ({ pageParam = 10 }) => Number(pageParam) * multiplier,
|
|
1328
|
+
getNextPageParam: (lastPage) => lastPage + 1,
|
|
1329
|
+
initialData: () => ({
|
|
1330
|
+
pages: [10, 11],
|
|
1331
|
+
pageParams: [10, 11],
|
|
1332
|
+
}),
|
|
1333
|
+
})
|
|
1334
|
+
|
|
1335
|
+
expect(queryClient.getQueryData(key)).toMatchObject({
|
|
1336
|
+
pages: [10, 11],
|
|
1337
|
+
})
|
|
1338
|
+
|
|
1339
|
+
multiplier = 2
|
|
1340
|
+
|
|
1341
|
+
await queryClient.resetQueries({
|
|
1342
|
+
queryKey: key,
|
|
1343
|
+
type: 'inactive',
|
|
1344
|
+
refetchPage: (page, _, allPages) => {
|
|
1345
|
+
return page === allPages[0]
|
|
1346
|
+
},
|
|
1347
|
+
})
|
|
1348
|
+
|
|
1349
|
+
expect(queryClient.getQueryData(key)).toMatchObject({
|
|
1350
|
+
pages: [20, 11],
|
|
1351
|
+
})
|
|
1352
|
+
})
|
|
1353
|
+
})
|
|
1354
|
+
|
|
1355
|
+
describe('focusManager and onlineManager', () => {
|
|
1356
|
+
test('should notify queryCache and mutationCache if focused', async () => {
|
|
1357
|
+
const testClient = createQueryClient()
|
|
1358
|
+
testClient.mount()
|
|
1359
|
+
|
|
1360
|
+
const queryCacheOnFocusSpy = jest.spyOn(
|
|
1361
|
+
testClient.getQueryCache(),
|
|
1362
|
+
'onFocus',
|
|
1363
|
+
)
|
|
1364
|
+
const queryCacheOnOnlineSpy = jest.spyOn(
|
|
1365
|
+
testClient.getQueryCache(),
|
|
1366
|
+
'onOnline',
|
|
1367
|
+
)
|
|
1368
|
+
const mutationCacheResumePausedMutationsSpy = jest.spyOn(
|
|
1369
|
+
testClient.getMutationCache(),
|
|
1370
|
+
'resumePausedMutations',
|
|
1371
|
+
)
|
|
1372
|
+
|
|
1373
|
+
focusManager.setFocused(false)
|
|
1374
|
+
expect(queryCacheOnFocusSpy).not.toHaveBeenCalled()
|
|
1375
|
+
expect(mutationCacheResumePausedMutationsSpy).not.toHaveBeenCalled()
|
|
1376
|
+
|
|
1377
|
+
focusManager.setFocused(true)
|
|
1378
|
+
expect(queryCacheOnFocusSpy).toHaveBeenCalledTimes(1)
|
|
1379
|
+
expect(mutationCacheResumePausedMutationsSpy).toHaveBeenCalledTimes(1)
|
|
1380
|
+
|
|
1381
|
+
expect(queryCacheOnOnlineSpy).not.toHaveBeenCalled()
|
|
1382
|
+
|
|
1383
|
+
queryCacheOnFocusSpy.mockRestore()
|
|
1384
|
+
mutationCacheResumePausedMutationsSpy.mockRestore()
|
|
1385
|
+
queryCacheOnOnlineSpy.mockRestore()
|
|
1386
|
+
focusManager.setFocused(undefined)
|
|
1387
|
+
})
|
|
1388
|
+
|
|
1389
|
+
test('should notify queryCache and mutationCache if online', async () => {
|
|
1390
|
+
const testClient = createQueryClient()
|
|
1391
|
+
testClient.mount()
|
|
1392
|
+
|
|
1393
|
+
const queryCacheOnFocusSpy = jest.spyOn(
|
|
1394
|
+
testClient.getQueryCache(),
|
|
1395
|
+
'onFocus',
|
|
1396
|
+
)
|
|
1397
|
+
const queryCacheOnOnlineSpy = jest.spyOn(
|
|
1398
|
+
testClient.getQueryCache(),
|
|
1399
|
+
'onOnline',
|
|
1400
|
+
)
|
|
1401
|
+
const mutationCacheResumePausedMutationsSpy = jest.spyOn(
|
|
1402
|
+
testClient.getMutationCache(),
|
|
1403
|
+
'resumePausedMutations',
|
|
1404
|
+
)
|
|
1405
|
+
|
|
1406
|
+
onlineManager.setOnline(false)
|
|
1407
|
+
expect(queryCacheOnOnlineSpy).not.toHaveBeenCalled()
|
|
1408
|
+
expect(mutationCacheResumePausedMutationsSpy).not.toHaveBeenCalled()
|
|
1409
|
+
|
|
1410
|
+
onlineManager.setOnline(true)
|
|
1411
|
+
expect(queryCacheOnOnlineSpy).toHaveBeenCalledTimes(1)
|
|
1412
|
+
expect(mutationCacheResumePausedMutationsSpy).toHaveBeenCalledTimes(1)
|
|
1413
|
+
|
|
1414
|
+
expect(queryCacheOnFocusSpy).not.toHaveBeenCalled()
|
|
1415
|
+
|
|
1416
|
+
queryCacheOnFocusSpy.mockRestore()
|
|
1417
|
+
queryCacheOnOnlineSpy.mockRestore()
|
|
1418
|
+
mutationCacheResumePausedMutationsSpy.mockRestore()
|
|
1419
|
+
onlineManager.setOnline(undefined)
|
|
1420
|
+
})
|
|
1421
|
+
})
|
|
1422
|
+
|
|
1423
|
+
describe('setMutationDefaults', () => {
|
|
1424
|
+
test('should update existing mutation defaults', () => {
|
|
1425
|
+
const key = queryKey()
|
|
1426
|
+
const mutationOptions1 = { mutationFn: async () => 'data' }
|
|
1427
|
+
const mutationOptions2 = { retry: false }
|
|
1428
|
+
queryClient.setMutationDefaults(key, mutationOptions1)
|
|
1429
|
+
queryClient.setMutationDefaults(key, mutationOptions2)
|
|
1430
|
+
expect(queryClient.getMutationDefaults(key)).toMatchObject(
|
|
1431
|
+
mutationOptions2,
|
|
1432
|
+
)
|
|
1433
|
+
})
|
|
1434
|
+
})
|
|
1435
|
+
})
|