@tanstack/solid-query-persist-client 5.59.16 → 5.59.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/solid-query-persist-client",
3
- "version": "5.59.16",
3
+ "version": "5.59.20",
4
4
  "description": "Solid.js bindings to work with persisters in TanStack/solid-query",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
@@ -41,20 +41,21 @@
41
41
  "sideEffects": false,
42
42
  "files": [
43
43
  "build",
44
- "src"
44
+ "src",
45
+ "!src/__tests__"
45
46
  ],
46
47
  "dependencies": {
47
- "@tanstack/query-persist-client-core": "5.59.16"
48
+ "@tanstack/query-persist-client-core": "5.59.20"
48
49
  },
49
50
  "devDependencies": {
50
51
  "solid-js": "^1.8.19",
51
52
  "tsup-preset-solid": "^2.2.0",
52
53
  "vite-plugin-solid": "^2.10.2",
53
- "@tanstack/solid-query": "5.59.16"
54
+ "@tanstack/solid-query": "5.59.20"
54
55
  },
55
56
  "peerDependencies": {
56
57
  "solid-js": "^1.6.0",
57
- "@tanstack/solid-query": "^5.59.16"
58
+ "@tanstack/solid-query": "^5.59.20"
58
59
  },
59
60
  "scripts": {}
60
61
  }
@@ -1,580 +0,0 @@
1
- import { describe, expect, test, vi } from 'vitest'
2
- import { render, screen, waitFor } from '@solidjs/testing-library'
3
- import { QueryClient, createQueries, createQuery } from '@tanstack/solid-query'
4
- import { persistQueryClientSave } from '@tanstack/query-persist-client-core'
5
- import { createEffect, createSignal, onMount } from 'solid-js'
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
-
14
- const createMockPersister = (): Persister => {
15
- let storedState: PersistedClient | undefined
16
-
17
- return {
18
- async persistClient(persistClient: PersistedClient) {
19
- storedState = persistClient
20
- },
21
- async restoreClient() {
22
- await sleep(10)
23
- return storedState
24
- },
25
- removeClient() {
26
- storedState = undefined
27
- },
28
- }
29
- }
30
-
31
- const createMockErrorPersister = (
32
- removeClient: Persister['removeClient'],
33
- ): [Error, Persister] => {
34
- const error = new Error('restore failed')
35
- return [
36
- error,
37
- {
38
- async persistClient() {
39
- // noop
40
- },
41
- async restoreClient() {
42
- await sleep(10)
43
- throw error
44
- },
45
- removeClient,
46
- },
47
- ]
48
- }
49
-
50
- describe('PersistQueryClientProvider', () => {
51
- test('restores cache from persister', async () => {
52
- const key = queryKey()
53
- const states: Array<{
54
- status: string
55
- fetchStatus: string
56
- data: string | undefined
57
- }> = []
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 = createQuery(() => ({
73
- queryKey: key,
74
- queryFn: async () => {
75
- await sleep(10)
76
- return 'fetched'
77
- },
78
- }))
79
- createEffect(() =>
80
- states.push({
81
- status: state.status,
82
- fetchStatus: state.fetchStatus,
83
- data: state.data,
84
- }),
85
- )
86
-
87
- return (
88
- <div>
89
- <h1>{state.data}</h1>
90
- <h2>fetchStatus: {state.fetchStatus}</h2>
91
- </div>
92
- )
93
- }
94
-
95
- render(() => (
96
- <PersistQueryClientProvider
97
- client={queryClient}
98
- persistOptions={{ persister }}
99
- >
100
- <Page />
101
- </PersistQueryClientProvider>
102
- ))
103
-
104
- await waitFor(() => screen.getByText('fetchStatus: idle'))
105
- await waitFor(() => screen.getByText('hydrated'))
106
- await waitFor(() => screen.getByText('fetched'))
107
-
108
- expect(states).toHaveLength(3)
109
-
110
- expect(states[0]).toMatchObject({
111
- status: 'pending',
112
- fetchStatus: 'idle',
113
- data: undefined,
114
- })
115
-
116
- expect(states[1]).toMatchObject({
117
- status: 'success',
118
- fetchStatus: 'fetching',
119
- data: 'hydrated',
120
- })
121
-
122
- expect(states[2]).toMatchObject({
123
- status: 'success',
124
- fetchStatus: 'idle',
125
- data: 'fetched',
126
- })
127
- })
128
-
129
- test('should also put useQueries into idle state', async () => {
130
- const key = queryKey()
131
- const states: Array<{
132
- status: string
133
- fetchStatus: string
134
- data: string | undefined
135
- }> = []
136
-
137
- const queryClient = createQueryClient()
138
- await queryClient.prefetchQuery({
139
- queryKey: key,
140
- queryFn: () => Promise.resolve('hydrated'),
141
- })
142
-
143
- const persister = createMockPersister()
144
-
145
- await persistQueryClientSave({ queryClient, persister })
146
-
147
- queryClient.clear()
148
-
149
- function Page() {
150
- const [state] = createQueries(() => ({
151
- queries: [
152
- {
153
- queryKey: key,
154
- queryFn: async (): Promise<string> => {
155
- await sleep(10)
156
- return 'fetched'
157
- },
158
- },
159
- ] as const,
160
- }))
161
-
162
- createEffect(() =>
163
- states.push({
164
- status: state.status,
165
- fetchStatus: state.fetchStatus,
166
- data: state.data,
167
- }),
168
- )
169
-
170
- return (
171
- <div>
172
- <h1>{state.data}</h1>
173
- <h2>fetchStatus: {state.fetchStatus}</h2>
174
- </div>
175
- )
176
- }
177
-
178
- render(() => (
179
- <PersistQueryClientProvider
180
- client={queryClient}
181
- persistOptions={{ persister }}
182
- >
183
- <Page />
184
- </PersistQueryClientProvider>
185
- ))
186
-
187
- await waitFor(() => screen.getByText('fetchStatus: idle'))
188
- await waitFor(() => screen.getByText('hydrated'))
189
- await waitFor(() => screen.getByText('fetched'))
190
-
191
- expect(states).toHaveLength(3)
192
-
193
- expect(states[0]).toMatchObject({
194
- status: 'pending',
195
- fetchStatus: 'idle',
196
- data: undefined,
197
- })
198
-
199
- expect(states[1]).toMatchObject({
200
- status: 'success',
201
- fetchStatus: 'fetching',
202
- data: 'hydrated',
203
- })
204
-
205
- expect(states[2]).toMatchObject({
206
- status: 'success',
207
- fetchStatus: 'idle',
208
- data: 'fetched',
209
- })
210
- })
211
-
212
- test('should show initialData while restoring', async () => {
213
- const key = queryKey()
214
- const states: Array<{
215
- status: string
216
- fetchStatus: string
217
- data: string | undefined
218
- }> = []
219
-
220
- const queryClient = createQueryClient()
221
- await queryClient.prefetchQuery({
222
- queryKey: key,
223
- queryFn: () => Promise.resolve('hydrated'),
224
- })
225
-
226
- const persister = createMockPersister()
227
-
228
- await persistQueryClientSave({ queryClient, persister })
229
-
230
- queryClient.clear()
231
-
232
- function Page() {
233
- const state = createQuery(() => ({
234
- queryKey: key,
235
- queryFn: async () => {
236
- await sleep(10)
237
- return 'fetched'
238
- },
239
- initialData: 'initial',
240
- // make sure that initial data is older than the hydration data
241
- // otherwise initialData would be newer and takes precedence
242
- initialDataUpdatedAt: 1,
243
- }))
244
-
245
- createEffect(() =>
246
- states.push({
247
- status: state.status,
248
- fetchStatus: state.fetchStatus,
249
- data: state.data,
250
- }),
251
- )
252
-
253
- return (
254
- <div>
255
- <h1>{state.data}</h1>
256
- <h2>fetchStatus: {state.fetchStatus}</h2>
257
- </div>
258
- )
259
- }
260
-
261
- render(() => (
262
- <PersistQueryClientProvider
263
- client={queryClient}
264
- persistOptions={{ persister }}
265
- >
266
- <Page />
267
- </PersistQueryClientProvider>
268
- ))
269
-
270
- await waitFor(() => screen.getByText('initial'))
271
- await waitFor(() => screen.getByText('hydrated'))
272
- await waitFor(() => screen.getByText('fetched'))
273
-
274
- expect(states).toHaveLength(3)
275
-
276
- expect(states[0]).toMatchObject({
277
- status: 'success',
278
- fetchStatus: 'idle',
279
- data: 'initial',
280
- })
281
-
282
- expect(states[1]).toMatchObject({
283
- status: 'success',
284
- fetchStatus: 'fetching',
285
- data: 'hydrated',
286
- })
287
-
288
- expect(states[2]).toMatchObject({
289
- status: 'success',
290
- fetchStatus: 'idle',
291
- data: 'fetched',
292
- })
293
- })
294
-
295
- test('should not refetch after restoring when data is fresh', async () => {
296
- const key = queryKey()
297
- const states: Array<{
298
- status: string
299
- fetchStatus: string
300
- data: string | undefined
301
- }> = []
302
-
303
- const queryClient = createQueryClient()
304
- await queryClient.prefetchQuery({
305
- queryKey: key,
306
- queryFn: () => Promise.resolve('hydrated'),
307
- })
308
-
309
- const persister = createMockPersister()
310
-
311
- await persistQueryClientSave({ queryClient, persister })
312
-
313
- queryClient.clear()
314
-
315
- let fetched = false
316
-
317
- function Page() {
318
- const state = createQuery(() => ({
319
- queryKey: key,
320
- queryFn: async () => {
321
- fetched = true
322
- await sleep(10)
323
- return 'fetched'
324
- },
325
- staleTime: Infinity,
326
- }))
327
-
328
- createEffect(() =>
329
- states.push({
330
- status: state.status,
331
- fetchStatus: state.fetchStatus,
332
- data: state.data,
333
- }),
334
- )
335
-
336
- return (
337
- <div>
338
- <h1>data: {state.data ?? 'null'}</h1>
339
- <h2>fetchStatus: {state.fetchStatus}</h2>
340
- </div>
341
- )
342
- }
343
-
344
- render(() => (
345
- <PersistQueryClientProvider
346
- client={queryClient}
347
- persistOptions={{ persister }}
348
- >
349
- <Page />
350
- </PersistQueryClientProvider>
351
- ))
352
-
353
- await waitFor(() => screen.getByText('data: null'))
354
- await waitFor(() => screen.getByText('data: hydrated'))
355
-
356
- expect(states).toHaveLength(2)
357
-
358
- expect(fetched).toBe(false)
359
-
360
- expect(states[0]).toMatchObject({
361
- status: 'pending',
362
- fetchStatus: 'idle',
363
- data: undefined,
364
- })
365
-
366
- expect(states[1]).toMatchObject({
367
- status: 'success',
368
- fetchStatus: 'idle',
369
- data: 'hydrated',
370
- })
371
- })
372
-
373
- test('should call onSuccess after successful restoring', async () => {
374
- const key = queryKey()
375
-
376
- const queryClient = createQueryClient()
377
- await queryClient.prefetchQuery({
378
- queryKey: key,
379
- queryFn: () => Promise.resolve('hydrated'),
380
- })
381
-
382
- const persister = createMockPersister()
383
-
384
- await persistQueryClientSave({ queryClient, persister })
385
-
386
- queryClient.clear()
387
-
388
- function Page() {
389
- const state = createQuery(() => ({
390
- queryKey: key,
391
- queryFn: async () => {
392
- await sleep(10)
393
- return 'fetched'
394
- },
395
- }))
396
-
397
- return (
398
- <div>
399
- <h1>{state.data}</h1>
400
- <h2>fetchStatus: {state.fetchStatus}</h2>
401
- </div>
402
- )
403
- }
404
-
405
- const onSuccess = vi.fn()
406
-
407
- render(() => (
408
- <PersistQueryClientProvider
409
- client={queryClient}
410
- persistOptions={{ persister }}
411
- onSuccess={onSuccess}
412
- >
413
- <Page />
414
- </PersistQueryClientProvider>
415
- ))
416
- expect(onSuccess).toHaveBeenCalledTimes(0)
417
-
418
- await waitFor(() => screen.getByText('hydrated'))
419
- expect(onSuccess).toHaveBeenCalledTimes(1)
420
- await waitFor(() => screen.getByText('fetched'))
421
- })
422
-
423
- test('should remove cache after non-successful restoring', async () => {
424
- const key = queryKey()
425
-
426
- const onErrorMock = vi
427
- .spyOn(console, 'error')
428
- .mockImplementation(() => undefined)
429
- const queryClient = createQueryClient()
430
- const removeClient = vi.fn()
431
-
432
- const [error, persister] = createMockErrorPersister(removeClient)
433
-
434
- function Page() {
435
- const state = createQuery(() => ({
436
- queryKey: key,
437
- queryFn: async () => {
438
- await sleep(10)
439
- return 'fetched'
440
- },
441
- }))
442
-
443
- return (
444
- <div>
445
- <h1>{state.data}</h1>
446
- <h2>fetchStatus: {state.fetchStatus}</h2>
447
- </div>
448
- )
449
- }
450
-
451
- render(() => (
452
- <PersistQueryClientProvider
453
- client={queryClient}
454
- persistOptions={{ persister }}
455
- >
456
- <Page />
457
- </PersistQueryClientProvider>
458
- ))
459
-
460
- await waitFor(() => screen.getByText('fetched'))
461
- expect(removeClient).toHaveBeenCalledTimes(1)
462
- expect(onErrorMock).toHaveBeenCalledTimes(1)
463
- expect(onErrorMock).toHaveBeenNthCalledWith(1, error)
464
- onErrorMock.mockRestore()
465
- })
466
-
467
- test('should be able to persist into multiple clients', async () => {
468
- const key = queryKey()
469
- const states: Array<{
470
- status: string
471
- fetchStatus: string
472
- data: string | undefined
473
- }> = []
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 onSuccess = vi.fn()
488
-
489
- const queryFn1 = vi.fn().mockImplementation(async () => {
490
- await sleep(10)
491
- return 'queryFn1'
492
- })
493
- const queryFn2 = vi.fn().mockImplementation(async () => {
494
- await sleep(10)
495
- return 'queryFn2'
496
- })
497
-
498
- function App() {
499
- const [client, setClient] = createSignal(
500
- new QueryClient({
501
- defaultOptions: {
502
- queries: {
503
- queryFn: queryFn1,
504
- },
505
- },
506
- }),
507
- )
508
-
509
- onMount(() => {
510
- setClient(
511
- new QueryClient({
512
- defaultOptions: {
513
- queries: {
514
- queryFn: queryFn2,
515
- },
516
- },
517
- }),
518
- )
519
- })
520
-
521
- return (
522
- <PersistQueryClientProvider
523
- client={client()}
524
- persistOptions={{ persister }}
525
- onSuccess={onSuccess}
526
- >
527
- <Page />
528
- </PersistQueryClientProvider>
529
- )
530
- }
531
-
532
- function Page() {
533
- const state = createQuery(() => ({ queryKey: key }))
534
-
535
- createEffect(() =>
536
- states.push({
537
- status: state.status,
538
- fetchStatus: state.fetchStatus,
539
- data: state.data as string | undefined,
540
- }),
541
- )
542
-
543
- return (
544
- <div>
545
- <h1>{String(state.data)}</h1>
546
- <h2>fetchStatus: {state.fetchStatus}</h2>
547
- </div>
548
- )
549
- }
550
-
551
- render(() => <App />)
552
-
553
- await waitFor(() => screen.getByText('hydrated'))
554
- await waitFor(() => screen.getByText('queryFn2'))
555
-
556
- expect(queryFn1).toHaveBeenCalledTimes(0)
557
- expect(queryFn2).toHaveBeenCalledTimes(1)
558
- expect(onSuccess).toHaveBeenCalledTimes(1)
559
-
560
- expect(states).toHaveLength(3)
561
-
562
- expect(states[0]).toMatchObject({
563
- status: 'pending',
564
- fetchStatus: 'idle',
565
- data: undefined,
566
- })
567
-
568
- expect(states[1]).toMatchObject({
569
- status: 'success',
570
- fetchStatus: 'fetching',
571
- data: 'hydrated',
572
- })
573
-
574
- expect(states[2]).toMatchObject({
575
- status: 'success',
576
- fetchStatus: 'idle',
577
- data: 'queryFn2',
578
- })
579
- })
580
- })
@@ -1,18 +0,0 @@
1
- import { QueryClient } from '@tanstack/solid-query'
2
- import type { QueryClientConfig } from '@tanstack/solid-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
- }