@tanstack/react-query-persist-client 5.59.18 → 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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-query-persist-client",
|
|
3
|
-
"version": "5.59.
|
|
3
|
+
"version": "5.59.20",
|
|
4
4
|
"description": "React bindings to work with persisters in TanStack/react-query",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,20 +34,21 @@
|
|
|
34
34
|
"sideEffects": false,
|
|
35
35
|
"files": [
|
|
36
36
|
"build",
|
|
37
|
-
"src"
|
|
37
|
+
"src",
|
|
38
|
+
"!src/__tests__"
|
|
38
39
|
],
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@tanstack/query-persist-client-core": "5.59.
|
|
41
|
+
"@tanstack/query-persist-client-core": "5.59.20"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/react": "npm:types-react@rc",
|
|
44
45
|
"@vitejs/plugin-react": "^4.3.1",
|
|
45
46
|
"react": "19.0.0-rc-4c2e457c7c-20240522",
|
|
46
|
-
"@tanstack/react-query": "5.59.
|
|
47
|
+
"@tanstack/react-query": "5.59.20"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
50
|
"react": "^18 || ^19",
|
|
50
|
-
"@tanstack/react-query": "^5.59.
|
|
51
|
+
"@tanstack/react-query": "^5.59.20"
|
|
51
52
|
},
|
|
52
53
|
"scripts": {}
|
|
53
54
|
}
|
|
@@ -1,768 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test, vi } from 'vitest'
|
|
2
|
-
import * as React from 'react'
|
|
3
|
-
import { fireEvent, render, waitFor } from '@testing-library/react'
|
|
4
|
-
import { QueryClient, useQueries, useQuery } from '@tanstack/react-query'
|
|
5
|
-
import { persistQueryClientSave } from '@tanstack/query-persist-client-core'
|
|
6
|
-
|
|
7
|
-
import { PersistQueryClientProvider } from '../PersistQueryClientProvider'
|
|
8
|
-
import { createQueryClient, queryKey, sleep } from './utils'
|
|
9
|
-
import type {
|
|
10
|
-
PersistedClient,
|
|
11
|
-
Persister,
|
|
12
|
-
} from '@tanstack/query-persist-client-core'
|
|
13
|
-
import type {
|
|
14
|
-
DefinedUseQueryResult,
|
|
15
|
-
UseQueryResult,
|
|
16
|
-
} from '@tanstack/react-query'
|
|
17
|
-
|
|
18
|
-
const createMockPersister = (): Persister => {
|
|
19
|
-
let storedState: PersistedClient | undefined
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
async persistClient(persistClient: PersistedClient) {
|
|
23
|
-
storedState = persistClient
|
|
24
|
-
},
|
|
25
|
-
async restoreClient() {
|
|
26
|
-
await sleep(10)
|
|
27
|
-
return storedState
|
|
28
|
-
},
|
|
29
|
-
removeClient() {
|
|
30
|
-
storedState = undefined
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const createMockErrorPersister = (
|
|
36
|
-
removeClient: Persister['removeClient'],
|
|
37
|
-
): [Error, Persister] => {
|
|
38
|
-
const error = new Error('restore failed')
|
|
39
|
-
return [
|
|
40
|
-
error,
|
|
41
|
-
{
|
|
42
|
-
async persistClient() {
|
|
43
|
-
// noop
|
|
44
|
-
},
|
|
45
|
-
async restoreClient() {
|
|
46
|
-
await sleep(10)
|
|
47
|
-
throw error
|
|
48
|
-
},
|
|
49
|
-
removeClient,
|
|
50
|
-
},
|
|
51
|
-
]
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
describe('PersistQueryClientProvider', () => {
|
|
55
|
-
test('restores cache from persister', async () => {
|
|
56
|
-
const key = queryKey()
|
|
57
|
-
const states: Array<UseQueryResult<string>> = []
|
|
58
|
-
|
|
59
|
-
const queryClient = createQueryClient()
|
|
60
|
-
await queryClient.prefetchQuery({
|
|
61
|
-
queryKey: key,
|
|
62
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
const persister = createMockPersister()
|
|
66
|
-
|
|
67
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
68
|
-
|
|
69
|
-
queryClient.clear()
|
|
70
|
-
|
|
71
|
-
function Page() {
|
|
72
|
-
const state = useQuery({
|
|
73
|
-
queryKey: key,
|
|
74
|
-
queryFn: async () => {
|
|
75
|
-
await sleep(10)
|
|
76
|
-
return 'fetched'
|
|
77
|
-
},
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
states.push(state)
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<div>
|
|
84
|
-
<h1>{state.data}</h1>
|
|
85
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
86
|
-
</div>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const rendered = render(
|
|
91
|
-
<PersistQueryClientProvider
|
|
92
|
-
client={queryClient}
|
|
93
|
-
persistOptions={{ persister }}
|
|
94
|
-
>
|
|
95
|
-
<Page />
|
|
96
|
-
</PersistQueryClientProvider>,
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
await waitFor(() => rendered.getByText('fetchStatus: idle'))
|
|
100
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
101
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
102
|
-
|
|
103
|
-
expect(states).toHaveLength(4)
|
|
104
|
-
|
|
105
|
-
expect(states[0]).toMatchObject({
|
|
106
|
-
status: 'pending',
|
|
107
|
-
fetchStatus: 'idle',
|
|
108
|
-
data: undefined,
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
expect(states[1]).toMatchObject({
|
|
112
|
-
status: 'success',
|
|
113
|
-
fetchStatus: 'fetching',
|
|
114
|
-
data: 'hydrated',
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
expect(states[2]).toMatchObject({
|
|
118
|
-
status: 'success',
|
|
119
|
-
fetchStatus: 'fetching',
|
|
120
|
-
data: 'hydrated',
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
expect(states[3]).toMatchObject({
|
|
124
|
-
status: 'success',
|
|
125
|
-
fetchStatus: 'idle',
|
|
126
|
-
data: 'fetched',
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
test('should subscribe correctly in StrictMode', async () => {
|
|
131
|
-
const key = queryKey()
|
|
132
|
-
|
|
133
|
-
const queryClient = createQueryClient()
|
|
134
|
-
await queryClient.prefetchQuery({
|
|
135
|
-
queryKey: key,
|
|
136
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
const persister = createMockPersister()
|
|
140
|
-
|
|
141
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
142
|
-
|
|
143
|
-
queryClient.clear()
|
|
144
|
-
|
|
145
|
-
function Page() {
|
|
146
|
-
const state = useQuery({
|
|
147
|
-
queryKey: key,
|
|
148
|
-
queryFn: async () => {
|
|
149
|
-
await sleep(10)
|
|
150
|
-
return 'fetched'
|
|
151
|
-
},
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
return (
|
|
155
|
-
<div>
|
|
156
|
-
<h1>{state.data}</h1>
|
|
157
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
158
|
-
<button
|
|
159
|
-
onClick={() => {
|
|
160
|
-
queryClient.setQueryData(key, 'updated')
|
|
161
|
-
}}
|
|
162
|
-
>
|
|
163
|
-
update
|
|
164
|
-
</button>
|
|
165
|
-
</div>
|
|
166
|
-
)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const rendered = render(
|
|
170
|
-
<React.StrictMode>
|
|
171
|
-
<PersistQueryClientProvider
|
|
172
|
-
client={queryClient}
|
|
173
|
-
persistOptions={{ persister }}
|
|
174
|
-
>
|
|
175
|
-
<Page />
|
|
176
|
-
</PersistQueryClientProvider>
|
|
177
|
-
,
|
|
178
|
-
</React.StrictMode>,
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
await waitFor(() => rendered.getByText('fetchStatus: idle'))
|
|
182
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
183
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
184
|
-
|
|
185
|
-
fireEvent.click(rendered.getByRole('button', { name: /update/i }))
|
|
186
|
-
|
|
187
|
-
await waitFor(() => rendered.getByText('updated'))
|
|
188
|
-
|
|
189
|
-
const state = await persister.restoreClient()
|
|
190
|
-
|
|
191
|
-
expect(state?.clientState.queries[0]?.state.data).toBe('updated')
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
test('should also put useQueries into idle state', async () => {
|
|
195
|
-
const key = queryKey()
|
|
196
|
-
const states: Array<UseQueryResult> = []
|
|
197
|
-
|
|
198
|
-
const queryClient = createQueryClient()
|
|
199
|
-
await queryClient.prefetchQuery({
|
|
200
|
-
queryKey: key,
|
|
201
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
const persister = createMockPersister()
|
|
205
|
-
|
|
206
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
207
|
-
|
|
208
|
-
queryClient.clear()
|
|
209
|
-
|
|
210
|
-
function Page() {
|
|
211
|
-
const [state] = useQueries({
|
|
212
|
-
queries: [
|
|
213
|
-
{
|
|
214
|
-
queryKey: key,
|
|
215
|
-
queryFn: async (): Promise<string> => {
|
|
216
|
-
await sleep(10)
|
|
217
|
-
return 'fetched'
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
],
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
states.push(state)
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<div>
|
|
227
|
-
<h1>{state.data}</h1>
|
|
228
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
229
|
-
</div>
|
|
230
|
-
)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const rendered = render(
|
|
234
|
-
<PersistQueryClientProvider
|
|
235
|
-
client={queryClient}
|
|
236
|
-
persistOptions={{ persister }}
|
|
237
|
-
>
|
|
238
|
-
<Page />
|
|
239
|
-
</PersistQueryClientProvider>,
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
await waitFor(() => rendered.getByText('fetchStatus: idle'))
|
|
243
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
244
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
245
|
-
|
|
246
|
-
expect(states).toHaveLength(4)
|
|
247
|
-
|
|
248
|
-
expect(states[0]).toMatchObject({
|
|
249
|
-
status: 'pending',
|
|
250
|
-
fetchStatus: 'idle',
|
|
251
|
-
data: undefined,
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
expect(states[1]).toMatchObject({
|
|
255
|
-
status: 'success',
|
|
256
|
-
fetchStatus: 'fetching',
|
|
257
|
-
data: 'hydrated',
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
expect(states[2]).toMatchObject({
|
|
261
|
-
status: 'success',
|
|
262
|
-
fetchStatus: 'fetching',
|
|
263
|
-
data: 'hydrated',
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
expect(states[3]).toMatchObject({
|
|
267
|
-
status: 'success',
|
|
268
|
-
fetchStatus: 'idle',
|
|
269
|
-
data: 'fetched',
|
|
270
|
-
})
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
test('should show initialData while restoring', async () => {
|
|
274
|
-
const key = queryKey()
|
|
275
|
-
const states: Array<DefinedUseQueryResult<string>> = []
|
|
276
|
-
|
|
277
|
-
const queryClient = createQueryClient()
|
|
278
|
-
await queryClient.prefetchQuery({
|
|
279
|
-
queryKey: key,
|
|
280
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
const persister = createMockPersister()
|
|
284
|
-
|
|
285
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
286
|
-
|
|
287
|
-
queryClient.clear()
|
|
288
|
-
|
|
289
|
-
function Page() {
|
|
290
|
-
const state = useQuery({
|
|
291
|
-
queryKey: key,
|
|
292
|
-
queryFn: async () => {
|
|
293
|
-
await sleep(10)
|
|
294
|
-
return 'fetched'
|
|
295
|
-
},
|
|
296
|
-
|
|
297
|
-
initialData: 'initial',
|
|
298
|
-
// make sure that initial data is older than the hydration data
|
|
299
|
-
// otherwise initialData would be newer and takes precedence
|
|
300
|
-
initialDataUpdatedAt: 1,
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
states.push(state)
|
|
304
|
-
|
|
305
|
-
return (
|
|
306
|
-
<div>
|
|
307
|
-
<h1>{state.data}</h1>
|
|
308
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
309
|
-
</div>
|
|
310
|
-
)
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const rendered = render(
|
|
314
|
-
<PersistQueryClientProvider
|
|
315
|
-
client={queryClient}
|
|
316
|
-
persistOptions={{ persister }}
|
|
317
|
-
>
|
|
318
|
-
<Page />
|
|
319
|
-
</PersistQueryClientProvider>,
|
|
320
|
-
)
|
|
321
|
-
|
|
322
|
-
await waitFor(() => rendered.getByText('initial'))
|
|
323
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
324
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
325
|
-
|
|
326
|
-
expect(states).toHaveLength(4)
|
|
327
|
-
|
|
328
|
-
expect(states[0]).toMatchObject({
|
|
329
|
-
status: 'success',
|
|
330
|
-
fetchStatus: 'idle',
|
|
331
|
-
data: 'initial',
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
expect(states[1]).toMatchObject({
|
|
335
|
-
status: 'success',
|
|
336
|
-
fetchStatus: 'fetching',
|
|
337
|
-
data: 'hydrated',
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
expect(states[2]).toMatchObject({
|
|
341
|
-
status: 'success',
|
|
342
|
-
fetchStatus: 'fetching',
|
|
343
|
-
data: 'hydrated',
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
expect(states[3]).toMatchObject({
|
|
347
|
-
status: 'success',
|
|
348
|
-
fetchStatus: 'idle',
|
|
349
|
-
data: 'fetched',
|
|
350
|
-
})
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
test('should not refetch after restoring when data is fresh', async () => {
|
|
354
|
-
const key = queryKey()
|
|
355
|
-
const states: Array<UseQueryResult<string>> = []
|
|
356
|
-
|
|
357
|
-
const queryClient = createQueryClient()
|
|
358
|
-
await queryClient.prefetchQuery({
|
|
359
|
-
queryKey: key,
|
|
360
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
const persister = createMockPersister()
|
|
364
|
-
|
|
365
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
366
|
-
|
|
367
|
-
queryClient.clear()
|
|
368
|
-
|
|
369
|
-
let fetched = false
|
|
370
|
-
|
|
371
|
-
function Page() {
|
|
372
|
-
const state = useQuery({
|
|
373
|
-
queryKey: key,
|
|
374
|
-
queryFn: async () => {
|
|
375
|
-
fetched = true
|
|
376
|
-
await sleep(10)
|
|
377
|
-
return 'fetched'
|
|
378
|
-
},
|
|
379
|
-
|
|
380
|
-
staleTime: Infinity,
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
states.push(state)
|
|
384
|
-
|
|
385
|
-
return (
|
|
386
|
-
<div>
|
|
387
|
-
<h1>data: {state.data ?? 'null'}</h1>
|
|
388
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
389
|
-
</div>
|
|
390
|
-
)
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const rendered = render(
|
|
394
|
-
<PersistQueryClientProvider
|
|
395
|
-
client={queryClient}
|
|
396
|
-
persistOptions={{ persister }}
|
|
397
|
-
>
|
|
398
|
-
<Page />
|
|
399
|
-
</PersistQueryClientProvider>,
|
|
400
|
-
)
|
|
401
|
-
|
|
402
|
-
await waitFor(() => rendered.getByText('data: null'))
|
|
403
|
-
await waitFor(() => rendered.getByText('data: hydrated'))
|
|
404
|
-
|
|
405
|
-
expect(states).toHaveLength(2)
|
|
406
|
-
|
|
407
|
-
expect(fetched).toBe(false)
|
|
408
|
-
|
|
409
|
-
expect(states[0]).toMatchObject({
|
|
410
|
-
status: 'pending',
|
|
411
|
-
fetchStatus: 'idle',
|
|
412
|
-
data: undefined,
|
|
413
|
-
})
|
|
414
|
-
|
|
415
|
-
expect(states[1]).toMatchObject({
|
|
416
|
-
status: 'success',
|
|
417
|
-
fetchStatus: 'idle',
|
|
418
|
-
data: 'hydrated',
|
|
419
|
-
})
|
|
420
|
-
})
|
|
421
|
-
|
|
422
|
-
test('should call onSuccess after successful restoring', async () => {
|
|
423
|
-
const key = queryKey()
|
|
424
|
-
|
|
425
|
-
const queryClient = createQueryClient()
|
|
426
|
-
await queryClient.prefetchQuery({
|
|
427
|
-
queryKey: key,
|
|
428
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
const persister = createMockPersister()
|
|
432
|
-
|
|
433
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
434
|
-
|
|
435
|
-
queryClient.clear()
|
|
436
|
-
|
|
437
|
-
function Page() {
|
|
438
|
-
const state = useQuery({
|
|
439
|
-
queryKey: key,
|
|
440
|
-
queryFn: async () => {
|
|
441
|
-
await sleep(10)
|
|
442
|
-
return 'fetched'
|
|
443
|
-
},
|
|
444
|
-
})
|
|
445
|
-
|
|
446
|
-
return (
|
|
447
|
-
<div>
|
|
448
|
-
<h1>{state.data}</h1>
|
|
449
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
450
|
-
</div>
|
|
451
|
-
)
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const onSuccess = vi.fn()
|
|
455
|
-
|
|
456
|
-
const rendered = render(
|
|
457
|
-
<PersistQueryClientProvider
|
|
458
|
-
client={queryClient}
|
|
459
|
-
persistOptions={{ persister }}
|
|
460
|
-
onSuccess={onSuccess}
|
|
461
|
-
>
|
|
462
|
-
<Page />
|
|
463
|
-
</PersistQueryClientProvider>,
|
|
464
|
-
)
|
|
465
|
-
expect(onSuccess).toHaveBeenCalledTimes(0)
|
|
466
|
-
|
|
467
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
468
|
-
expect(onSuccess).toHaveBeenCalledTimes(1)
|
|
469
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
test('should await onSuccess after successful restoring', async () => {
|
|
473
|
-
const key = queryKey()
|
|
474
|
-
|
|
475
|
-
const queryClient = createQueryClient()
|
|
476
|
-
await queryClient.prefetchQuery({
|
|
477
|
-
queryKey: key,
|
|
478
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
479
|
-
})
|
|
480
|
-
|
|
481
|
-
const persister = createMockPersister()
|
|
482
|
-
|
|
483
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
484
|
-
|
|
485
|
-
queryClient.clear()
|
|
486
|
-
|
|
487
|
-
const states: Array<string> = []
|
|
488
|
-
|
|
489
|
-
function Page() {
|
|
490
|
-
const { data, fetchStatus } = useQuery({
|
|
491
|
-
queryKey: key,
|
|
492
|
-
queryFn: async () => {
|
|
493
|
-
states.push('fetching')
|
|
494
|
-
await sleep(10)
|
|
495
|
-
states.push('fetched')
|
|
496
|
-
return 'fetched'
|
|
497
|
-
},
|
|
498
|
-
})
|
|
499
|
-
|
|
500
|
-
return (
|
|
501
|
-
<div>
|
|
502
|
-
<h1>{data}</h1>
|
|
503
|
-
<h2>fetchStatus: {fetchStatus}</h2>
|
|
504
|
-
</div>
|
|
505
|
-
)
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const rendered = render(
|
|
509
|
-
<PersistQueryClientProvider
|
|
510
|
-
client={queryClient}
|
|
511
|
-
persistOptions={{ persister }}
|
|
512
|
-
onSuccess={async () => {
|
|
513
|
-
states.push('onSuccess')
|
|
514
|
-
await sleep(20)
|
|
515
|
-
states.push('onSuccess done')
|
|
516
|
-
}}
|
|
517
|
-
>
|
|
518
|
-
<Page />
|
|
519
|
-
</PersistQueryClientProvider>,
|
|
520
|
-
)
|
|
521
|
-
|
|
522
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
523
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
524
|
-
expect(states).toEqual([
|
|
525
|
-
'onSuccess',
|
|
526
|
-
'onSuccess done',
|
|
527
|
-
'fetching',
|
|
528
|
-
'fetched',
|
|
529
|
-
])
|
|
530
|
-
})
|
|
531
|
-
|
|
532
|
-
test('should remove cache after non-successful restoring', async () => {
|
|
533
|
-
const key = queryKey()
|
|
534
|
-
const consoleMock = vi.spyOn(console, 'error')
|
|
535
|
-
const consoleWarn = vi
|
|
536
|
-
.spyOn(console, 'warn')
|
|
537
|
-
.mockImplementation(() => undefined)
|
|
538
|
-
consoleMock.mockImplementation(() => undefined)
|
|
539
|
-
|
|
540
|
-
const queryClient = createQueryClient()
|
|
541
|
-
const removeClient = vi.fn()
|
|
542
|
-
|
|
543
|
-
const [error, persister] = createMockErrorPersister(removeClient)
|
|
544
|
-
|
|
545
|
-
function Page() {
|
|
546
|
-
const state = useQuery({
|
|
547
|
-
queryKey: key,
|
|
548
|
-
queryFn: async () => {
|
|
549
|
-
await sleep(10)
|
|
550
|
-
return 'fetched'
|
|
551
|
-
},
|
|
552
|
-
})
|
|
553
|
-
|
|
554
|
-
return (
|
|
555
|
-
<div>
|
|
556
|
-
<h1>{state.data}</h1>
|
|
557
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
558
|
-
</div>
|
|
559
|
-
)
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
const rendered = render(
|
|
563
|
-
<PersistQueryClientProvider
|
|
564
|
-
client={queryClient}
|
|
565
|
-
persistOptions={{ persister }}
|
|
566
|
-
>
|
|
567
|
-
<Page />
|
|
568
|
-
</PersistQueryClientProvider>,
|
|
569
|
-
)
|
|
570
|
-
|
|
571
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
572
|
-
expect(removeClient).toHaveBeenCalledTimes(1)
|
|
573
|
-
expect(consoleMock).toHaveBeenCalledTimes(1)
|
|
574
|
-
expect(consoleMock).toHaveBeenNthCalledWith(1, error)
|
|
575
|
-
consoleMock.mockRestore()
|
|
576
|
-
consoleWarn.mockRestore()
|
|
577
|
-
})
|
|
578
|
-
|
|
579
|
-
test('should be able to persist into multiple clients', async () => {
|
|
580
|
-
const key = queryKey()
|
|
581
|
-
const states: Array<UseQueryResult> = []
|
|
582
|
-
|
|
583
|
-
const queryClient = createQueryClient()
|
|
584
|
-
await queryClient.prefetchQuery({
|
|
585
|
-
queryKey: key,
|
|
586
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
587
|
-
})
|
|
588
|
-
|
|
589
|
-
const persister = createMockPersister()
|
|
590
|
-
|
|
591
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
592
|
-
|
|
593
|
-
queryClient.clear()
|
|
594
|
-
|
|
595
|
-
const onSuccess = vi.fn()
|
|
596
|
-
|
|
597
|
-
const queryFn1 = vi.fn().mockImplementation(async () => {
|
|
598
|
-
await sleep(10)
|
|
599
|
-
return 'queryFn1'
|
|
600
|
-
})
|
|
601
|
-
const queryFn2 = vi.fn().mockImplementation(async () => {
|
|
602
|
-
await sleep(10)
|
|
603
|
-
return 'queryFn2'
|
|
604
|
-
})
|
|
605
|
-
|
|
606
|
-
function App() {
|
|
607
|
-
const [client, setClient] = React.useState(
|
|
608
|
-
() =>
|
|
609
|
-
new QueryClient({
|
|
610
|
-
defaultOptions: {
|
|
611
|
-
queries: {
|
|
612
|
-
queryFn: queryFn1,
|
|
613
|
-
},
|
|
614
|
-
},
|
|
615
|
-
}),
|
|
616
|
-
)
|
|
617
|
-
|
|
618
|
-
React.useEffect(() => {
|
|
619
|
-
setClient(
|
|
620
|
-
new QueryClient({
|
|
621
|
-
defaultOptions: {
|
|
622
|
-
queries: {
|
|
623
|
-
queryFn: queryFn2,
|
|
624
|
-
},
|
|
625
|
-
},
|
|
626
|
-
}),
|
|
627
|
-
)
|
|
628
|
-
}, [])
|
|
629
|
-
|
|
630
|
-
return (
|
|
631
|
-
<PersistQueryClientProvider
|
|
632
|
-
client={client}
|
|
633
|
-
persistOptions={{ persister }}
|
|
634
|
-
onSuccess={onSuccess}
|
|
635
|
-
>
|
|
636
|
-
<Page />
|
|
637
|
-
</PersistQueryClientProvider>
|
|
638
|
-
)
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
function Page() {
|
|
642
|
-
const state = useQuery({ queryKey: key })
|
|
643
|
-
|
|
644
|
-
states.push(state)
|
|
645
|
-
|
|
646
|
-
return (
|
|
647
|
-
<div>
|
|
648
|
-
<h1>{String(state.data)}</h1>
|
|
649
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
650
|
-
</div>
|
|
651
|
-
)
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
const rendered = render(<App />)
|
|
655
|
-
|
|
656
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
657
|
-
await waitFor(() => rendered.getByText('queryFn2'))
|
|
658
|
-
|
|
659
|
-
expect(queryFn1).toHaveBeenCalledTimes(0)
|
|
660
|
-
expect(queryFn2).toHaveBeenCalledTimes(1)
|
|
661
|
-
expect(onSuccess).toHaveBeenCalledTimes(1)
|
|
662
|
-
|
|
663
|
-
expect(states).toHaveLength(5)
|
|
664
|
-
|
|
665
|
-
expect(states[0]).toMatchObject({
|
|
666
|
-
status: 'pending',
|
|
667
|
-
fetchStatus: 'idle',
|
|
668
|
-
data: undefined,
|
|
669
|
-
})
|
|
670
|
-
|
|
671
|
-
expect(states[1]).toMatchObject({
|
|
672
|
-
status: 'pending',
|
|
673
|
-
fetchStatus: 'idle',
|
|
674
|
-
data: undefined,
|
|
675
|
-
})
|
|
676
|
-
|
|
677
|
-
expect(states[2]).toMatchObject({
|
|
678
|
-
status: 'success',
|
|
679
|
-
fetchStatus: 'fetching',
|
|
680
|
-
data: 'hydrated',
|
|
681
|
-
})
|
|
682
|
-
|
|
683
|
-
expect(states[3]).toMatchObject({
|
|
684
|
-
status: 'success',
|
|
685
|
-
fetchStatus: 'fetching',
|
|
686
|
-
data: 'hydrated',
|
|
687
|
-
})
|
|
688
|
-
|
|
689
|
-
expect(states[4]).toMatchObject({
|
|
690
|
-
status: 'success',
|
|
691
|
-
fetchStatus: 'idle',
|
|
692
|
-
data: 'queryFn2',
|
|
693
|
-
})
|
|
694
|
-
})
|
|
695
|
-
|
|
696
|
-
test('should only restore once in StrictMode', async () => {
|
|
697
|
-
let restoreCount = 0
|
|
698
|
-
const createPersister = (): Persister => {
|
|
699
|
-
let storedState: PersistedClient | undefined
|
|
700
|
-
|
|
701
|
-
return {
|
|
702
|
-
async persistClient(persistClient) {
|
|
703
|
-
storedState = persistClient
|
|
704
|
-
},
|
|
705
|
-
async restoreClient() {
|
|
706
|
-
restoreCount++
|
|
707
|
-
await sleep(10)
|
|
708
|
-
return storedState
|
|
709
|
-
},
|
|
710
|
-
removeClient() {
|
|
711
|
-
storedState = undefined
|
|
712
|
-
},
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
const key = queryKey()
|
|
717
|
-
|
|
718
|
-
const queryClient = createQueryClient()
|
|
719
|
-
await queryClient.prefetchQuery({
|
|
720
|
-
queryKey: key,
|
|
721
|
-
queryFn: () => Promise.resolve('hydrated'),
|
|
722
|
-
})
|
|
723
|
-
|
|
724
|
-
const persister = createPersister()
|
|
725
|
-
|
|
726
|
-
const onSuccess = vi.fn()
|
|
727
|
-
|
|
728
|
-
await persistQueryClientSave({ queryClient, persister })
|
|
729
|
-
|
|
730
|
-
queryClient.clear()
|
|
731
|
-
|
|
732
|
-
function Page() {
|
|
733
|
-
const state = useQuery({
|
|
734
|
-
queryKey: key,
|
|
735
|
-
queryFn: async () => {
|
|
736
|
-
await sleep(10)
|
|
737
|
-
return 'fetched'
|
|
738
|
-
},
|
|
739
|
-
})
|
|
740
|
-
|
|
741
|
-
return (
|
|
742
|
-
<div>
|
|
743
|
-
<h1>{state.data}</h1>
|
|
744
|
-
<h2>fetchStatus: {state.fetchStatus}</h2>
|
|
745
|
-
</div>
|
|
746
|
-
)
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
const rendered = render(
|
|
750
|
-
<React.StrictMode>
|
|
751
|
-
<PersistQueryClientProvider
|
|
752
|
-
client={queryClient}
|
|
753
|
-
persistOptions={{ persister }}
|
|
754
|
-
onSuccess={onSuccess}
|
|
755
|
-
>
|
|
756
|
-
<Page />
|
|
757
|
-
</PersistQueryClientProvider>
|
|
758
|
-
</React.StrictMode>,
|
|
759
|
-
)
|
|
760
|
-
|
|
761
|
-
await waitFor(() => rendered.getByText('fetchStatus: idle'))
|
|
762
|
-
await waitFor(() => rendered.getByText('hydrated'))
|
|
763
|
-
await waitFor(() => rendered.getByText('fetched'))
|
|
764
|
-
|
|
765
|
-
expect(onSuccess).toHaveBeenCalledTimes(1)
|
|
766
|
-
expect(restoreCount).toBe(1)
|
|
767
|
-
})
|
|
768
|
-
})
|
package/src/__tests__/utils.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { QueryClient } from '@tanstack/react-query'
|
|
2
|
-
import type { QueryClientConfig } from '@tanstack/react-query'
|
|
3
|
-
|
|
4
|
-
export function createQueryClient(config?: QueryClientConfig): QueryClient {
|
|
5
|
-
return new QueryClient(config)
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
let queryKeyCount = 0
|
|
9
|
-
export function queryKey(): Array<string> {
|
|
10
|
-
queryKeyCount++
|
|
11
|
-
return [`query_${queryKeyCount}`]
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function sleep(timeout: number): Promise<void> {
|
|
15
|
-
return new Promise((resolve, _reject) => {
|
|
16
|
-
setTimeout(resolve, timeout)
|
|
17
|
-
})
|
|
18
|
-
}
|