@tanstack/solid-query 5.0.0-alpha.2 → 5.0.0-alpha.21
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/index.js +73 -34
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.js +75 -37
- package/build/esm/index.js.map +1 -1
- package/build/source/QueryClient.js +6 -0
- package/build/source/__tests__/QueryClientProvider.test.jsx +2 -1
- package/build/source/__tests__/createInfiniteQuery.test.jsx +67 -20
- package/build/source/__tests__/createMutation.test.jsx +19 -18
- package/build/source/__tests__/createQueries.test.jsx +4 -91
- package/build/source/__tests__/createQuery.test.jsx +62 -271
- package/build/source/__tests__/suspense.test.jsx +3 -64
- package/build/source/__tests__/useIsFetching.test.jsx +2 -4
- package/build/source/__tests__/useIsMutating.test.jsx +25 -28
- package/build/source/__tests__/utils.jsx +4 -3
- package/build/source/createBaseQuery.js +45 -19
- package/build/source/createQueries.js +5 -5
- package/build/source/index.js +1 -0
- package/build/source/useIsFetching.js +5 -5
- package/build/source/useIsMutating.js +5 -5
- package/build/types/QueryClient.d.ts +29 -0
- package/build/types/QueryClientProvider.d.ts +1 -1
- package/build/types/__tests__/utils.d.ts +3 -4
- package/build/types/createBaseQuery.d.ts +3 -2
- package/build/types/createInfiniteQuery.d.ts +4 -2
- package/build/types/createMutation.d.ts +4 -2
- package/build/types/createQueries.d.ts +5 -4
- package/build/types/createQuery.d.ts +2 -1
- package/build/types/index.d.ts +2 -0
- package/build/types/types.d.ts +2 -1
- package/build/types/useIsFetching.d.ts +3 -7
- package/build/types/useIsMutating.d.ts +3 -7
- package/build/umd/index.js +1 -1
- package/build/umd/index.js.map +1 -1
- package/package.json +5 -5
- package/src/QueryClient.ts +84 -0
- package/src/QueryClientProvider.tsx +1 -1
- package/src/__tests__/QueryClientProvider.test.tsx +2 -1
- package/src/__tests__/createInfiniteQuery.test.tsx +95 -34
- package/src/__tests__/createMutation.test.tsx +19 -18
- package/src/__tests__/createQueries.test.tsx +4 -97
- package/src/__tests__/createQuery.test.tsx +78 -344
- package/src/__tests__/suspense.test.tsx +3 -85
- package/src/__tests__/useIsFetching.test.tsx +2 -4
- package/src/__tests__/useIsMutating.test.tsx +32 -40
- package/src/__tests__/utils.tsx +4 -3
- package/src/createBaseQuery.ts +70 -25
- package/src/createInfiniteQuery.ts +3 -2
- package/src/createMutation.ts +4 -2
- package/src/createQueries.ts +9 -8
- package/src/createQuery.ts +4 -2
- package/src/index.ts +7 -0
- package/src/types.ts +4 -2
- package/src/useIsFetching.ts +10 -13
- package/src/useIsMutating.ts +10 -11
|
@@ -33,6 +33,9 @@ import {
|
|
|
33
33
|
setActTimeout,
|
|
34
34
|
sleep,
|
|
35
35
|
} from './utils'
|
|
36
|
+
import { vi } from 'vitest'
|
|
37
|
+
import type { Mock } from 'vitest'
|
|
38
|
+
import { reconcile } from 'solid-js/store'
|
|
36
39
|
|
|
37
40
|
describe('createQuery', () => {
|
|
38
41
|
const queryCache = new QueryCache()
|
|
@@ -77,21 +80,17 @@ describe('createQuery', () => {
|
|
|
77
80
|
createQuery(() => ({
|
|
78
81
|
queryKey: [key],
|
|
79
82
|
queryFn: async () => true,
|
|
80
|
-
onSuccess: (data) => expectType<boolean>(data),
|
|
81
|
-
onSettled: (data) => expectType<boolean | undefined>(data),
|
|
82
83
|
}))
|
|
83
84
|
|
|
84
85
|
// it should be possible to specify a union type as result type
|
|
85
86
|
const unionTypeSync = createQuery(() => ({
|
|
86
87
|
queryKey: key,
|
|
87
88
|
queryFn: () => (Math.random() > 0.5 ? 'a' : 'b'),
|
|
88
|
-
onSuccess: (data) => expectType<'a' | 'b'>(data),
|
|
89
89
|
}))
|
|
90
90
|
expectType<'a' | 'b' | undefined>(unionTypeSync.data)
|
|
91
91
|
const unionTypeAsync = createQuery<'a' | 'b'>(() => ({
|
|
92
92
|
queryKey: key,
|
|
93
93
|
queryFn: () => Promise.resolve(Math.random() > 0.5 ? 'a' : 'b'),
|
|
94
|
-
onSuccess: (data) => expectType<'a' | 'b'>(data),
|
|
95
94
|
}))
|
|
96
95
|
expectType<'a' | 'b' | undefined>(unionTypeAsync.data)
|
|
97
96
|
|
|
@@ -488,241 +487,6 @@ describe('createQuery', () => {
|
|
|
488
487
|
})
|
|
489
488
|
})
|
|
490
489
|
|
|
491
|
-
it('should call onSuccess after a query has been fetched', async () => {
|
|
492
|
-
const key = queryKey()
|
|
493
|
-
const states: CreateQueryResult<string>[] = []
|
|
494
|
-
const onSuccess = jest.fn()
|
|
495
|
-
|
|
496
|
-
function Page() {
|
|
497
|
-
const state = createQuery(() => ({
|
|
498
|
-
queryKey: key,
|
|
499
|
-
queryFn: async () => {
|
|
500
|
-
await sleep(10)
|
|
501
|
-
return 'data'
|
|
502
|
-
},
|
|
503
|
-
onSuccess,
|
|
504
|
-
}))
|
|
505
|
-
createRenderEffect(() => {
|
|
506
|
-
states.push({ ...state })
|
|
507
|
-
})
|
|
508
|
-
return <div>data: {state.data}</div>
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
render(() => (
|
|
512
|
-
<QueryClientProvider client={queryClient}>
|
|
513
|
-
<Page />
|
|
514
|
-
</QueryClientProvider>
|
|
515
|
-
))
|
|
516
|
-
|
|
517
|
-
await screen.findByText('data: data')
|
|
518
|
-
expect(states.length).toBe(2)
|
|
519
|
-
expect(onSuccess).toHaveBeenCalledTimes(1)
|
|
520
|
-
expect(onSuccess).toHaveBeenCalledWith('data')
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
it('should call onSuccess after a disabled query has been fetched', async () => {
|
|
524
|
-
const key = queryKey()
|
|
525
|
-
const states: CreateQueryResult<string>[] = []
|
|
526
|
-
const onSuccess = jest.fn()
|
|
527
|
-
|
|
528
|
-
function Page() {
|
|
529
|
-
const state = createQuery(() => ({
|
|
530
|
-
queryKey: key,
|
|
531
|
-
queryFn: () => 'data',
|
|
532
|
-
enabled: false,
|
|
533
|
-
onSuccess,
|
|
534
|
-
}))
|
|
535
|
-
|
|
536
|
-
createRenderEffect(() => {
|
|
537
|
-
states.push({ ...state })
|
|
538
|
-
})
|
|
539
|
-
|
|
540
|
-
createEffect(() => {
|
|
541
|
-
const refetch = state.refetch
|
|
542
|
-
setActTimeout(() => {
|
|
543
|
-
refetch()
|
|
544
|
-
}, 10)
|
|
545
|
-
})
|
|
546
|
-
|
|
547
|
-
return null
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
render(() => (
|
|
551
|
-
<QueryClientProvider client={queryClient}>
|
|
552
|
-
<Page />
|
|
553
|
-
</QueryClientProvider>
|
|
554
|
-
))
|
|
555
|
-
|
|
556
|
-
await sleep(50)
|
|
557
|
-
expect(onSuccess).toHaveBeenCalledTimes(1)
|
|
558
|
-
expect(onSuccess).toHaveBeenCalledWith('data')
|
|
559
|
-
})
|
|
560
|
-
|
|
561
|
-
it('should not call onSuccess if a component has unmounted', async () => {
|
|
562
|
-
const key = queryKey()
|
|
563
|
-
const states: CreateQueryResult<string>[] = []
|
|
564
|
-
const onSuccess = jest.fn()
|
|
565
|
-
|
|
566
|
-
function Page() {
|
|
567
|
-
const [show, setShow] = createSignal(true)
|
|
568
|
-
|
|
569
|
-
createEffect(() => {
|
|
570
|
-
setShow(false)
|
|
571
|
-
})
|
|
572
|
-
return <>{show() && <Component />}</>
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
function Component() {
|
|
576
|
-
const state = createQuery(() => ({
|
|
577
|
-
queryKey: key,
|
|
578
|
-
queryFn: async () => {
|
|
579
|
-
await sleep(10)
|
|
580
|
-
return 'data'
|
|
581
|
-
},
|
|
582
|
-
onSuccess,
|
|
583
|
-
}))
|
|
584
|
-
createRenderEffect(() => {
|
|
585
|
-
states.push({ ...state })
|
|
586
|
-
})
|
|
587
|
-
return null
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
render(() => (
|
|
591
|
-
<QueryClientProvider client={queryClient}>
|
|
592
|
-
<Page />
|
|
593
|
-
</QueryClientProvider>
|
|
594
|
-
))
|
|
595
|
-
|
|
596
|
-
await sleep(50)
|
|
597
|
-
expect(states.length).toBe(1)
|
|
598
|
-
expect(onSuccess).toHaveBeenCalledTimes(0)
|
|
599
|
-
})
|
|
600
|
-
|
|
601
|
-
it('should call onError after a query has been fetched with an error', async () => {
|
|
602
|
-
const key = queryKey()
|
|
603
|
-
const states: CreateQueryResult<unknown>[] = []
|
|
604
|
-
const onError = jest.fn()
|
|
605
|
-
|
|
606
|
-
function Page() {
|
|
607
|
-
const state = createQuery(() => ({
|
|
608
|
-
queryKey: key,
|
|
609
|
-
queryFn: () => Promise.reject(new Error('error')),
|
|
610
|
-
retry: false,
|
|
611
|
-
onError,
|
|
612
|
-
}))
|
|
613
|
-
|
|
614
|
-
createRenderEffect(() => {
|
|
615
|
-
states.push({ ...state })
|
|
616
|
-
})
|
|
617
|
-
|
|
618
|
-
return null
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
render(() => (
|
|
622
|
-
<QueryClientProvider client={queryClient}>
|
|
623
|
-
<Page />
|
|
624
|
-
</QueryClientProvider>
|
|
625
|
-
))
|
|
626
|
-
|
|
627
|
-
await sleep(10)
|
|
628
|
-
expect(states.length).toBe(2)
|
|
629
|
-
expect(onError).toHaveBeenCalledTimes(1)
|
|
630
|
-
expect(onError).toHaveBeenCalledWith(new Error('error'))
|
|
631
|
-
})
|
|
632
|
-
|
|
633
|
-
it('should not call onError when receiving a CancelledError', async () => {
|
|
634
|
-
const key = queryKey()
|
|
635
|
-
const onError = jest.fn()
|
|
636
|
-
|
|
637
|
-
function Page() {
|
|
638
|
-
const state = createQuery(() => ({
|
|
639
|
-
queryKey: key,
|
|
640
|
-
queryFn: async () => {
|
|
641
|
-
await sleep(10)
|
|
642
|
-
return 23
|
|
643
|
-
},
|
|
644
|
-
onError,
|
|
645
|
-
}))
|
|
646
|
-
return (
|
|
647
|
-
<span>
|
|
648
|
-
status: {state.status}, fetchStatus: {state.fetchStatus}
|
|
649
|
-
</span>
|
|
650
|
-
)
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
render(() => (
|
|
654
|
-
<QueryClientProvider client={queryClient}>
|
|
655
|
-
<Page />
|
|
656
|
-
</QueryClientProvider>
|
|
657
|
-
))
|
|
658
|
-
|
|
659
|
-
await sleep(5)
|
|
660
|
-
await queryClient.cancelQueries({ queryKey: key })
|
|
661
|
-
// query cancellation will reset the query to it's initial state
|
|
662
|
-
await waitFor(() => screen.getByText('status: pending, fetchStatus: idle'))
|
|
663
|
-
expect(onError).not.toHaveBeenCalled()
|
|
664
|
-
})
|
|
665
|
-
|
|
666
|
-
it('should call onSettled after a query has been fetched', async () => {
|
|
667
|
-
const key = queryKey()
|
|
668
|
-
const states: CreateQueryResult<string>[] = []
|
|
669
|
-
const onSettled = jest.fn()
|
|
670
|
-
|
|
671
|
-
function Page() {
|
|
672
|
-
const state = createQuery(() => ({
|
|
673
|
-
queryKey: key,
|
|
674
|
-
queryFn: () => 'data',
|
|
675
|
-
onSettled,
|
|
676
|
-
}))
|
|
677
|
-
|
|
678
|
-
createRenderEffect(() => {
|
|
679
|
-
states.push({ ...state })
|
|
680
|
-
})
|
|
681
|
-
return null
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
render(() => (
|
|
685
|
-
<QueryClientProvider client={queryClient}>
|
|
686
|
-
<Page />
|
|
687
|
-
</QueryClientProvider>
|
|
688
|
-
))
|
|
689
|
-
|
|
690
|
-
await sleep(10)
|
|
691
|
-
expect(states.length).toBe(2)
|
|
692
|
-
expect(onSettled).toHaveBeenCalledTimes(1)
|
|
693
|
-
expect(onSettled).toHaveBeenCalledWith('data', null)
|
|
694
|
-
})
|
|
695
|
-
|
|
696
|
-
it('should call onSettled after a query has been fetched with an error', async () => {
|
|
697
|
-
const key = queryKey()
|
|
698
|
-
const states: CreateQueryResult<string>[] = []
|
|
699
|
-
const onSettled = jest.fn()
|
|
700
|
-
|
|
701
|
-
function Page() {
|
|
702
|
-
const state = createQuery(() => ({
|
|
703
|
-
queryKey: key,
|
|
704
|
-
queryFn: () => Promise.reject<unknown>('error'),
|
|
705
|
-
retry: false,
|
|
706
|
-
onSettled,
|
|
707
|
-
}))
|
|
708
|
-
createRenderEffect(() => {
|
|
709
|
-
states.push({ ...state })
|
|
710
|
-
})
|
|
711
|
-
return null
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
render(() => (
|
|
715
|
-
<QueryClientProvider client={queryClient}>
|
|
716
|
-
<Page />
|
|
717
|
-
</QueryClientProvider>
|
|
718
|
-
))
|
|
719
|
-
|
|
720
|
-
await sleep(10)
|
|
721
|
-
expect(states.length).toBe(2)
|
|
722
|
-
expect(onSettled).toHaveBeenCalledTimes(1)
|
|
723
|
-
expect(onSettled).toHaveBeenCalledWith(undefined, 'error')
|
|
724
|
-
})
|
|
725
|
-
|
|
726
490
|
it('should not cancel an ongoing fetch when refetch is called with cancelRefetch=false if we have data already', async () => {
|
|
727
491
|
const key = queryKey()
|
|
728
492
|
let fetchCount = 0
|
|
@@ -1280,7 +1044,6 @@ describe('createQuery', () => {
|
|
|
1280
1044
|
count++
|
|
1281
1045
|
return count === 1 ? result1 : result2
|
|
1282
1046
|
},
|
|
1283
|
-
notifyOnChangeProps: 'all',
|
|
1284
1047
|
}))
|
|
1285
1048
|
|
|
1286
1049
|
createRenderEffect(() => {
|
|
@@ -1320,9 +1083,8 @@ describe('createQuery', () => {
|
|
|
1320
1083
|
|
|
1321
1084
|
expect(todos).toEqual(result1)
|
|
1322
1085
|
expect(newTodos).toEqual(result2)
|
|
1323
|
-
expect(newTodos).not.toBe(todos)
|
|
1324
1086
|
expect(newTodo1).toBe(todo1)
|
|
1325
|
-
expect(newTodo2).
|
|
1087
|
+
expect(newTodo2).toBe(todo2)
|
|
1326
1088
|
|
|
1327
1089
|
return null
|
|
1328
1090
|
})
|
|
@@ -2273,56 +2035,6 @@ describe('createQuery', () => {
|
|
|
2273
2035
|
expect(renders).toBe(1)
|
|
2274
2036
|
})
|
|
2275
2037
|
|
|
2276
|
-
it('should batch re-renders including hook callbacks', async () => {
|
|
2277
|
-
const key = queryKey()
|
|
2278
|
-
|
|
2279
|
-
let renders = 0
|
|
2280
|
-
let callbackCount = 0
|
|
2281
|
-
|
|
2282
|
-
const queryFn = async () => {
|
|
2283
|
-
await sleep(10)
|
|
2284
|
-
return 'data'
|
|
2285
|
-
}
|
|
2286
|
-
|
|
2287
|
-
function Page() {
|
|
2288
|
-
const [count, setCount] = createSignal(0)
|
|
2289
|
-
createQuery(() => ({
|
|
2290
|
-
queryKey: key,
|
|
2291
|
-
queryFn,
|
|
2292
|
-
onSuccess: () => {
|
|
2293
|
-
setCount((x) => x + 1)
|
|
2294
|
-
},
|
|
2295
|
-
}))
|
|
2296
|
-
createQuery(() => ({
|
|
2297
|
-
queryKey: key,
|
|
2298
|
-
queryFn,
|
|
2299
|
-
onSuccess: () => {
|
|
2300
|
-
setCount((x) => x + 1)
|
|
2301
|
-
},
|
|
2302
|
-
}))
|
|
2303
|
-
|
|
2304
|
-
createEffect(() => {
|
|
2305
|
-
renders++
|
|
2306
|
-
callbackCount = count()
|
|
2307
|
-
})
|
|
2308
|
-
|
|
2309
|
-
return <div>count: {count()}</div>
|
|
2310
|
-
}
|
|
2311
|
-
|
|
2312
|
-
render(() => (
|
|
2313
|
-
<QueryClientProvider client={queryClient}>
|
|
2314
|
-
<Page />
|
|
2315
|
-
</QueryClientProvider>
|
|
2316
|
-
))
|
|
2317
|
-
|
|
2318
|
-
await waitFor(() => screen.getByText('count: 2'))
|
|
2319
|
-
|
|
2320
|
-
// Should be 3 instead of 5
|
|
2321
|
-
expect(renders).toBe(3)
|
|
2322
|
-
// Both callbacks should have been executed
|
|
2323
|
-
expect(callbackCount).toBe(2)
|
|
2324
|
-
})
|
|
2325
|
-
|
|
2326
2038
|
it('should render latest data even if react has discarded certain renders', async () => {
|
|
2327
2039
|
const key = queryKey()
|
|
2328
2040
|
|
|
@@ -2452,7 +2164,7 @@ describe('createQuery', () => {
|
|
|
2452
2164
|
|
|
2453
2165
|
it('should not refetch query on focus when `enabled` is set to `false`', async () => {
|
|
2454
2166
|
const key = queryKey()
|
|
2455
|
-
const queryFn =
|
|
2167
|
+
const queryFn = vi.fn<unknown[], string>().mockReturnValue('data')
|
|
2456
2168
|
|
|
2457
2169
|
function Page() {
|
|
2458
2170
|
const { data = 'default' } = createQuery(() => ({
|
|
@@ -3255,7 +2967,7 @@ describe('createQuery', () => {
|
|
|
3255
2967
|
|
|
3256
2968
|
it('should keep initial data when the query key changes', async () => {
|
|
3257
2969
|
const key = queryKey()
|
|
3258
|
-
const states: DefinedCreateQueryResult<{ count: number }
|
|
2970
|
+
const states: Partial<DefinedCreateQueryResult<{ count: number }>>[] = []
|
|
3259
2971
|
|
|
3260
2972
|
function Page() {
|
|
3261
2973
|
const [count, setCount] = createSignal(0)
|
|
@@ -3264,6 +2976,7 @@ describe('createQuery', () => {
|
|
|
3264
2976
|
queryFn: () => ({ count: 10 }),
|
|
3265
2977
|
staleTime: Infinity,
|
|
3266
2978
|
initialData: () => ({ count: count() }),
|
|
2979
|
+
reconcile: false,
|
|
3267
2980
|
}))
|
|
3268
2981
|
createRenderEffect(() => {
|
|
3269
2982
|
states.push({ ...state })
|
|
@@ -3296,7 +3009,7 @@ describe('createQuery', () => {
|
|
|
3296
3009
|
it('should retry specified number of times', async () => {
|
|
3297
3010
|
const key = queryKey()
|
|
3298
3011
|
|
|
3299
|
-
const queryFn =
|
|
3012
|
+
const queryFn = vi.fn<unknown[], unknown>()
|
|
3300
3013
|
queryFn.mockImplementation(() => {
|
|
3301
3014
|
return Promise.reject(new Error('Error test Barrett'))
|
|
3302
3015
|
})
|
|
@@ -3337,7 +3050,7 @@ describe('createQuery', () => {
|
|
|
3337
3050
|
it('should not retry if retry function `false`', async () => {
|
|
3338
3051
|
const key = queryKey()
|
|
3339
3052
|
|
|
3340
|
-
const queryFn =
|
|
3053
|
+
const queryFn = vi.fn<unknown[], unknown>()
|
|
3341
3054
|
|
|
3342
3055
|
queryFn.mockImplementationOnce(() => {
|
|
3343
3056
|
return Promise.reject(new Error('Error test Tanner'))
|
|
@@ -3385,7 +3098,7 @@ describe('createQuery', () => {
|
|
|
3385
3098
|
|
|
3386
3099
|
type DelayError = { delay: number }
|
|
3387
3100
|
|
|
3388
|
-
const queryFn =
|
|
3101
|
+
const queryFn = vi.fn<unknown[], unknown>()
|
|
3389
3102
|
queryFn.mockImplementation(() => {
|
|
3390
3103
|
return Promise.reject({ delay: 50 })
|
|
3391
3104
|
})
|
|
@@ -3596,10 +3309,10 @@ describe('createQuery', () => {
|
|
|
3596
3309
|
const key = queryKey()
|
|
3597
3310
|
const states: CreateQueryResult<string>[] = []
|
|
3598
3311
|
|
|
3599
|
-
const queryFn =
|
|
3312
|
+
const queryFn = vi.fn<unknown[], string>()
|
|
3600
3313
|
queryFn.mockImplementation(() => 'data')
|
|
3601
3314
|
|
|
3602
|
-
const prefetchQueryFn =
|
|
3315
|
+
const prefetchQueryFn = vi.fn<unknown[], string>()
|
|
3603
3316
|
prefetchQueryFn.mockImplementation(() => 'not yet...')
|
|
3604
3317
|
|
|
3605
3318
|
await queryClient.prefetchQuery({
|
|
@@ -3633,10 +3346,10 @@ describe('createQuery', () => {
|
|
|
3633
3346
|
it('should not refetch if not stale after a prefetch', async () => {
|
|
3634
3347
|
const key = queryKey()
|
|
3635
3348
|
|
|
3636
|
-
const queryFn =
|
|
3349
|
+
const queryFn = vi.fn<unknown[], string>()
|
|
3637
3350
|
queryFn.mockImplementation(() => 'data')
|
|
3638
3351
|
|
|
3639
|
-
const prefetchQueryFn =
|
|
3352
|
+
const prefetchQueryFn = vi.fn<unknown[], Promise<string>>()
|
|
3640
3353
|
prefetchQueryFn.mockImplementation(async () => {
|
|
3641
3354
|
await sleep(10)
|
|
3642
3355
|
return 'not yet...'
|
|
@@ -3909,7 +3622,7 @@ describe('createQuery', () => {
|
|
|
3909
3622
|
|
|
3910
3623
|
it('it should support enabled:false in query object syntax', async () => {
|
|
3911
3624
|
const key = queryKey()
|
|
3912
|
-
const queryFn =
|
|
3625
|
+
const queryFn = vi.fn<unknown[], string>()
|
|
3913
3626
|
queryFn.mockImplementation(() => 'data')
|
|
3914
3627
|
|
|
3915
3628
|
function Page() {
|
|
@@ -3981,7 +3694,7 @@ describe('createQuery', () => {
|
|
|
3981
3694
|
))
|
|
3982
3695
|
|
|
3983
3696
|
await waitFor(() => screen.getByText('fetched data'))
|
|
3984
|
-
const setTimeoutSpy =
|
|
3697
|
+
const setTimeoutSpy = vi.spyOn(window, 'setTimeout')
|
|
3985
3698
|
|
|
3986
3699
|
result.unmount()
|
|
3987
3700
|
|
|
@@ -4007,7 +3720,7 @@ describe('createQuery', () => {
|
|
|
4007
3720
|
))
|
|
4008
3721
|
|
|
4009
3722
|
await waitFor(() => screen.getByText('fetched data'))
|
|
4010
|
-
const setTimeoutSpy =
|
|
3723
|
+
const setTimeoutSpy = vi.spyOn(window, 'setTimeout')
|
|
4011
3724
|
|
|
4012
3725
|
result.unmount()
|
|
4013
3726
|
|
|
@@ -4019,8 +3732,8 @@ describe('createQuery', () => {
|
|
|
4019
3732
|
|
|
4020
3733
|
it('should not cause memo churn when data does not change', async () => {
|
|
4021
3734
|
const key = queryKey()
|
|
4022
|
-
const queryFn =
|
|
4023
|
-
const memoFn =
|
|
3735
|
+
const queryFn = vi.fn<unknown[], string>().mockReturnValue('data')
|
|
3736
|
+
const memoFn = vi.fn()
|
|
4024
3737
|
|
|
4025
3738
|
function Page() {
|
|
4026
3739
|
const result = createQuery(() => ({
|
|
@@ -4255,7 +3968,7 @@ describe('createQuery', () => {
|
|
|
4255
3968
|
it('should refetch if any query instance becomes enabled', async () => {
|
|
4256
3969
|
const key = queryKey()
|
|
4257
3970
|
|
|
4258
|
-
const queryFn =
|
|
3971
|
+
const queryFn = vi.fn<unknown[], string>().mockReturnValue('data')
|
|
4259
3972
|
|
|
4260
3973
|
function Disabled() {
|
|
4261
3974
|
createQuery(() => ({ queryKey: key, queryFn, enabled: false }))
|
|
@@ -4608,13 +4321,68 @@ describe('createQuery', () => {
|
|
|
4608
4321
|
expect(states).toHaveLength(1)
|
|
4609
4322
|
})
|
|
4610
4323
|
|
|
4324
|
+
it('The reconcile fn callback should correctly maintain referential equality', async () => {
|
|
4325
|
+
const key1 = queryKey()
|
|
4326
|
+
const states: Array<Array<number>> = []
|
|
4327
|
+
|
|
4328
|
+
function Page() {
|
|
4329
|
+
const [forceValue, setForceValue] = createSignal(1)
|
|
4330
|
+
|
|
4331
|
+
const state = createQuery(() => ({
|
|
4332
|
+
queryKey: key1,
|
|
4333
|
+
queryFn: async () => {
|
|
4334
|
+
await sleep(10)
|
|
4335
|
+
return [1, 2]
|
|
4336
|
+
},
|
|
4337
|
+
select: (res) => res.map((x) => x + 1),
|
|
4338
|
+
reconcile(oldData, newData) {
|
|
4339
|
+
return reconcile(newData)(oldData)
|
|
4340
|
+
},
|
|
4341
|
+
}))
|
|
4342
|
+
|
|
4343
|
+
createEffect(() => {
|
|
4344
|
+
if (state.data) {
|
|
4345
|
+
states.push(state.data)
|
|
4346
|
+
}
|
|
4347
|
+
})
|
|
4348
|
+
|
|
4349
|
+
const forceUpdate = () => {
|
|
4350
|
+
setForceValue((prev) => prev + 1)
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4353
|
+
return (
|
|
4354
|
+
<div>
|
|
4355
|
+
<h2>Data: {JSON.stringify(state.data)}</h2>
|
|
4356
|
+
<h2>forceValue: {forceValue}</h2>
|
|
4357
|
+
<button onClick={forceUpdate}>forceUpdate</button>
|
|
4358
|
+
</div>
|
|
4359
|
+
)
|
|
4360
|
+
}
|
|
4361
|
+
|
|
4362
|
+
render(() => (
|
|
4363
|
+
<QueryClientProvider client={queryClient}>
|
|
4364
|
+
<Page />
|
|
4365
|
+
</QueryClientProvider>
|
|
4366
|
+
))
|
|
4367
|
+
await waitFor(() => screen.getByText('Data: [2,3]'))
|
|
4368
|
+
expect(states).toHaveLength(1)
|
|
4369
|
+
|
|
4370
|
+
fireEvent.click(screen.getByRole('button', { name: /forceUpdate/i }))
|
|
4371
|
+
|
|
4372
|
+
await waitFor(() => screen.getByText('forceValue: 2'))
|
|
4373
|
+
await waitFor(() => screen.getByText('Data: [2,3]'))
|
|
4374
|
+
|
|
4375
|
+
// effect should not be triggered again due to structural sharing
|
|
4376
|
+
expect(states).toHaveLength(1)
|
|
4377
|
+
})
|
|
4378
|
+
|
|
4611
4379
|
it('should cancel the query function when there are no more subscriptions', async () => {
|
|
4612
4380
|
const key = queryKey()
|
|
4613
|
-
let cancelFn:
|
|
4381
|
+
let cancelFn: Mock = vi.fn()
|
|
4614
4382
|
|
|
4615
4383
|
const queryFn = ({ signal }: { signal?: AbortSignal }) => {
|
|
4616
4384
|
const promise = new Promise<string>((resolve, reject) => {
|
|
4617
|
-
cancelFn =
|
|
4385
|
+
cancelFn = vi.fn(() => reject('Cancelled'))
|
|
4618
4386
|
signal?.addEventListener('abort', cancelFn)
|
|
4619
4387
|
sleep(20).then(() => resolve('OK'))
|
|
4620
4388
|
})
|
|
@@ -4958,7 +4726,7 @@ describe('createQuery', () => {
|
|
|
4958
4726
|
})
|
|
4959
4727
|
|
|
4960
4728
|
it('should refetch when changed enabled to true in error state', async () => {
|
|
4961
|
-
const queryFn =
|
|
4729
|
+
const queryFn = vi.fn<unknown[], unknown>()
|
|
4962
4730
|
queryFn.mockImplementation(async () => {
|
|
4963
4731
|
await sleep(10)
|
|
4964
4732
|
return Promise.reject(new Error('Suspense Error Bingo'))
|
|
@@ -6050,40 +5818,6 @@ describe('createQuery', () => {
|
|
|
6050
5818
|
})
|
|
6051
5819
|
})
|
|
6052
5820
|
|
|
6053
|
-
it('setQueryData - should not call onSuccess callback of active observers', async () => {
|
|
6054
|
-
const key = queryKey()
|
|
6055
|
-
const onSuccess = jest.fn()
|
|
6056
|
-
|
|
6057
|
-
function Page() {
|
|
6058
|
-
const state = createQuery(() => ({
|
|
6059
|
-
queryKey: key,
|
|
6060
|
-
queryFn: () => 'data',
|
|
6061
|
-
onSuccess,
|
|
6062
|
-
}))
|
|
6063
|
-
return (
|
|
6064
|
-
<div>
|
|
6065
|
-
<div>data: {state.data}</div>
|
|
6066
|
-
<button onClick={() => queryClient.setQueryData(key, 'newData')}>
|
|
6067
|
-
setQueryData
|
|
6068
|
-
</button>
|
|
6069
|
-
</div>
|
|
6070
|
-
)
|
|
6071
|
-
}
|
|
6072
|
-
|
|
6073
|
-
render(() => (
|
|
6074
|
-
<QueryClientProvider client={queryClient}>
|
|
6075
|
-
<Page />
|
|
6076
|
-
</QueryClientProvider>
|
|
6077
|
-
))
|
|
6078
|
-
|
|
6079
|
-
await waitFor(() => screen.getByText('data: data'))
|
|
6080
|
-
fireEvent.click(screen.getByRole('button', { name: /setQueryData/i }))
|
|
6081
|
-
await waitFor(() => screen.getByText('data: newData'))
|
|
6082
|
-
|
|
6083
|
-
expect(onSuccess).toHaveBeenCalledTimes(1)
|
|
6084
|
-
expect(onSuccess).toHaveBeenCalledWith('data')
|
|
6085
|
-
})
|
|
6086
|
-
|
|
6087
5821
|
it('setQueryData - should respect updatedAt', async () => {
|
|
6088
5822
|
const key = queryKey()
|
|
6089
5823
|
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
QueryClientProvider,
|
|
21
21
|
} from '..'
|
|
22
22
|
import { createQueryClient, queryKey, sleep } from './utils'
|
|
23
|
+
import { vi } from 'vitest'
|
|
23
24
|
|
|
24
25
|
describe("useQuery's in Suspense mode", () => {
|
|
25
26
|
const queryCache = new QueryCache()
|
|
@@ -142,7 +143,7 @@ describe("useQuery's in Suspense mode", () => {
|
|
|
142
143
|
it('should not call the queryFn twice when used in Suspense mode', async () => {
|
|
143
144
|
const key = queryKey()
|
|
144
145
|
|
|
145
|
-
const queryFn =
|
|
146
|
+
const queryFn = vi.fn<unknown[], string>()
|
|
146
147
|
queryFn.mockImplementation(() => {
|
|
147
148
|
sleep(10)
|
|
148
149
|
return 'data'
|
|
@@ -216,89 +217,6 @@ describe("useQuery's in Suspense mode", () => {
|
|
|
216
217
|
expect(queryCache.find({ queryKey: key })?.getObserversCount()).toBe(0)
|
|
217
218
|
})
|
|
218
219
|
|
|
219
|
-
it('should call onSuccess on the first successful call', async () => {
|
|
220
|
-
const key = queryKey()
|
|
221
|
-
|
|
222
|
-
const successFn = jest.fn()
|
|
223
|
-
|
|
224
|
-
function Page() {
|
|
225
|
-
createQuery(() => ({
|
|
226
|
-
queryKey: [key],
|
|
227
|
-
queryFn: async () => {
|
|
228
|
-
await sleep(10)
|
|
229
|
-
return key
|
|
230
|
-
},
|
|
231
|
-
|
|
232
|
-
suspense: true,
|
|
233
|
-
select: () => 'selected',
|
|
234
|
-
onSuccess: successFn,
|
|
235
|
-
}))
|
|
236
|
-
|
|
237
|
-
return <>rendered</>
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
render(() => (
|
|
241
|
-
<QueryClientProvider client={queryClient}>
|
|
242
|
-
<Suspense fallback="loading">
|
|
243
|
-
<Page />
|
|
244
|
-
</Suspense>
|
|
245
|
-
</QueryClientProvider>
|
|
246
|
-
))
|
|
247
|
-
|
|
248
|
-
await waitFor(() => screen.getByText('rendered'))
|
|
249
|
-
|
|
250
|
-
await waitFor(() => expect(successFn).toHaveBeenCalledTimes(1))
|
|
251
|
-
await waitFor(() => expect(successFn).toHaveBeenCalledWith('selected'))
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('should call every onSuccess handler within a suspense boundary', async () => {
|
|
255
|
-
const key = queryKey()
|
|
256
|
-
|
|
257
|
-
const successFn1 = jest.fn()
|
|
258
|
-
const successFn2 = jest.fn()
|
|
259
|
-
|
|
260
|
-
function FirstComponent() {
|
|
261
|
-
createQuery(() => ({
|
|
262
|
-
queryKey: key,
|
|
263
|
-
queryFn: () => {
|
|
264
|
-
sleep(10)
|
|
265
|
-
return 'data'
|
|
266
|
-
},
|
|
267
|
-
onSuccess: successFn1,
|
|
268
|
-
}))
|
|
269
|
-
|
|
270
|
-
return <span>first</span>
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
function SecondComponent() {
|
|
274
|
-
createQuery(() => ({
|
|
275
|
-
queryKey: key,
|
|
276
|
-
queryFn: () => {
|
|
277
|
-
sleep(10)
|
|
278
|
-
return 'data'
|
|
279
|
-
},
|
|
280
|
-
onSuccess: successFn2,
|
|
281
|
-
}))
|
|
282
|
-
|
|
283
|
-
return <span>second</span>
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
render(() => (
|
|
287
|
-
<QueryClientProvider client={queryClient}>
|
|
288
|
-
<Suspense fallback="loading">
|
|
289
|
-
<FirstComponent />
|
|
290
|
-
<SecondComponent />
|
|
291
|
-
</Suspense>
|
|
292
|
-
,
|
|
293
|
-
</QueryClientProvider>
|
|
294
|
-
))
|
|
295
|
-
|
|
296
|
-
await waitFor(() => screen.getByText('second'))
|
|
297
|
-
|
|
298
|
-
await waitFor(() => expect(successFn1).toHaveBeenCalledTimes(1))
|
|
299
|
-
await waitFor(() => expect(successFn2).toHaveBeenCalledTimes(1))
|
|
300
|
-
})
|
|
301
|
-
|
|
302
220
|
// https://github.com/tannerlinsley/react-query/issues/468
|
|
303
221
|
it('should reset error state if new component instances are mounted', async () => {
|
|
304
222
|
const key = queryKey()
|
|
@@ -733,7 +651,7 @@ describe("useQuery's in Suspense mode", () => {
|
|
|
733
651
|
it('should not call the queryFn when not enabled', async () => {
|
|
734
652
|
const key = queryKey()
|
|
735
653
|
|
|
736
|
-
const queryFn =
|
|
654
|
+
const queryFn = vi.fn<unknown[], Promise<string>>()
|
|
737
655
|
queryFn.mockImplementation(async () => {
|
|
738
656
|
await sleep(10)
|
|
739
657
|
return '23'
|