@tanstack/react-query 5.0.0-alpha.4 → 5.0.0-alpha.42

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.
Files changed (207) hide show
  1. package/build/codemods/__testfixtures__/default-import.input.tsx +94 -0
  2. package/build/codemods/__testfixtures__/default-import.output.tsx +96 -0
  3. package/build/codemods/__testfixtures__/named-import.input.tsx +96 -0
  4. package/build/codemods/__testfixtures__/named-import.output.tsx +98 -0
  5. package/build/codemods/__testfixtures__/namespaced-import.input.tsx +86 -0
  6. package/build/codemods/__testfixtures__/namespaced-import.output.tsx +88 -0
  7. package/build/codemods/__testfixtures__/parameter-is-identifier.input.tsx +49 -0
  8. package/build/codemods/__testfixtures__/parameter-is-identifier.output.tsx +49 -0
  9. package/build/codemods/__testfixtures__/parameter-is-object-expression.input.tsx +128 -0
  10. package/build/codemods/__testfixtures__/parameter-is-object-expression.output.tsx +175 -0
  11. package/build/codemods/__testfixtures__/replace-import-specifier.input.tsx +10 -0
  12. package/build/codemods/__testfixtures__/replace-import-specifier.output.tsx +10 -0
  13. package/build/codemods/__testfixtures__/type-arguments.input.tsx +25 -0
  14. package/build/codemods/__testfixtures__/type-arguments.output.tsx +31 -0
  15. package/build/codemods/__tests__/key-transformation.test.js +32 -0
  16. package/build/codemods/__tests__/replace-import-specifier.test.js +12 -0
  17. package/build/codemods/remove-overloads/__testfixtures__/default-import.input.tsx +199 -0
  18. package/build/codemods/remove-overloads/__testfixtures__/default-import.output.tsx +484 -0
  19. package/build/codemods/remove-overloads/__tests__/remove-overloads.test.js +6 -0
  20. package/build/codemods/remove-overloads/remove-overloads.js +59 -0
  21. package/build/codemods/remove-overloads/transformers/filter-aware-usage-transformer.js +153 -0
  22. package/build/codemods/remove-overloads/transformers/query-fn-aware-usage-transformer.js +188 -0
  23. package/build/codemods/remove-overloads/utils/index.js +124 -0
  24. package/build/codemods/remove-overloads/utils/unknown-usage-error.js +26 -0
  25. package/build/codemods/src/utils/index.js +205 -0
  26. package/build/codemods/src/v4/key-transformation.js +138 -0
  27. package/build/codemods/src/v4/replace-import-specifier.js +25 -0
  28. package/build/codemods/transformers/query-cache-transformer.js +116 -0
  29. package/build/codemods/transformers/query-client-transformer.js +48 -0
  30. package/build/codemods/transformers/use-query-like-transformer.js +32 -0
  31. package/build/codemods/utils/replacers/key-replacer.js +164 -0
  32. package/build/lib/HydrationBoundary.d.ts +1 -0
  33. package/build/lib/HydrationBoundary.d.ts.map +1 -0
  34. package/build/lib/HydrationBoundary.esm.js +1 -0
  35. package/build/lib/HydrationBoundary.esm.js.map +1 -1
  36. package/build/lib/HydrationBoundary.js +1 -0
  37. package/build/lib/HydrationBoundary.js.map +1 -1
  38. package/build/lib/HydrationBoundary.mjs +1 -0
  39. package/build/lib/HydrationBoundary.mjs.map +1 -1
  40. package/build/lib/QueryClientProvider.d.ts +2 -1
  41. package/build/lib/QueryClientProvider.d.ts.map +1 -0
  42. package/build/lib/QueryClientProvider.esm.js +1 -0
  43. package/build/lib/QueryClientProvider.esm.js.map +1 -1
  44. package/build/lib/QueryClientProvider.js +1 -0
  45. package/build/lib/QueryClientProvider.js.map +1 -1
  46. package/build/lib/QueryClientProvider.mjs +1 -0
  47. package/build/lib/QueryClientProvider.mjs.map +1 -1
  48. package/build/lib/QueryErrorResetBoundary.d.ts +2 -1
  49. package/build/lib/QueryErrorResetBoundary.d.ts.map +1 -0
  50. package/build/lib/QueryErrorResetBoundary.esm.js +1 -0
  51. package/build/lib/QueryErrorResetBoundary.esm.js.map +1 -1
  52. package/build/lib/QueryErrorResetBoundary.js +1 -0
  53. package/build/lib/QueryErrorResetBoundary.js.map +1 -1
  54. package/build/lib/QueryErrorResetBoundary.mjs +1 -0
  55. package/build/lib/QueryErrorResetBoundary.mjs.map +1 -1
  56. package/build/lib/__tests__/HydrationBoundary.test.d.ts +1 -0
  57. package/build/lib/__tests__/HydrationBoundary.test.d.ts.map +1 -0
  58. package/build/lib/__tests__/QueryClientProvider.test.d.ts +1 -0
  59. package/build/lib/__tests__/QueryClientProvider.test.d.ts.map +1 -0
  60. package/build/lib/__tests__/QueryResetErrorBoundary.test.d.ts +1 -0
  61. package/build/lib/__tests__/QueryResetErrorBoundary.test.d.ts.map +1 -0
  62. package/build/lib/__tests__/ssr-hydration.test.d.ts +1 -0
  63. package/build/lib/__tests__/ssr-hydration.test.d.ts.map +1 -0
  64. package/build/lib/__tests__/ssr.test.d.ts +1 -3
  65. package/build/lib/__tests__/ssr.test.d.ts.map +1 -0
  66. package/build/lib/__tests__/suspense.test.d.ts +1 -0
  67. package/build/lib/__tests__/suspense.test.d.ts.map +1 -0
  68. package/build/lib/__tests__/useInfiniteQuery.test.d.ts +1 -0
  69. package/build/lib/__tests__/useInfiniteQuery.test.d.ts.map +1 -0
  70. package/build/lib/__tests__/useInfiniteQuery.type.test.d.ts +1 -0
  71. package/build/lib/__tests__/useInfiniteQuery.type.test.d.ts.map +1 -0
  72. package/build/lib/__tests__/useIsFetching.test.d.ts +1 -0
  73. package/build/lib/__tests__/useIsFetching.test.d.ts.map +1 -0
  74. package/build/lib/__tests__/useMutation.test.d.ts +1 -0
  75. package/build/lib/__tests__/useMutation.test.d.ts.map +1 -0
  76. package/build/lib/__tests__/useMutationState.test.d.ts +1 -0
  77. package/build/lib/__tests__/useMutationState.test.d.ts.map +1 -0
  78. package/build/lib/__tests__/useQueries.test.d.ts +1 -0
  79. package/build/lib/__tests__/useQueries.test.d.ts.map +1 -0
  80. package/build/lib/__tests__/useQuery.test.d.ts +1 -0
  81. package/build/lib/__tests__/useQuery.test.d.ts.map +1 -0
  82. package/build/lib/__tests__/useQuery.types.test.d.ts +1 -0
  83. package/build/lib/__tests__/useQuery.types.test.d.ts.map +1 -0
  84. package/build/lib/__tests__/utils.d.ts +6 -6
  85. package/build/lib/__tests__/utils.d.ts.map +1 -0
  86. package/build/lib/errorBoundaryUtils.d.ts +4 -3
  87. package/build/lib/errorBoundaryUtils.d.ts.map +1 -0
  88. package/build/lib/errorBoundaryUtils.esm.js +4 -3
  89. package/build/lib/errorBoundaryUtils.esm.js.map +1 -1
  90. package/build/lib/errorBoundaryUtils.js +4 -3
  91. package/build/lib/errorBoundaryUtils.js.map +1 -1
  92. package/build/lib/errorBoundaryUtils.mjs +4 -3
  93. package/build/lib/errorBoundaryUtils.mjs.map +1 -1
  94. package/build/lib/index.d.ts +2 -1
  95. package/build/lib/index.d.ts.map +1 -0
  96. package/build/lib/index.esm.js +1 -1
  97. package/build/lib/index.js +1 -0
  98. package/build/lib/index.js.map +1 -1
  99. package/build/lib/index.mjs +1 -1
  100. package/build/lib/isRestoring.d.ts +1 -0
  101. package/build/lib/isRestoring.d.ts.map +1 -0
  102. package/build/lib/isRestoring.esm.js +1 -0
  103. package/build/lib/isRestoring.esm.js.map +1 -1
  104. package/build/lib/isRestoring.js +1 -0
  105. package/build/lib/isRestoring.js.map +1 -1
  106. package/build/lib/isRestoring.mjs +1 -0
  107. package/build/lib/isRestoring.mjs.map +1 -1
  108. package/build/lib/suspense.d.ts +3 -5
  109. package/build/lib/suspense.d.ts.map +1 -0
  110. package/build/lib/suspense.esm.js +2 -9
  111. package/build/lib/suspense.esm.js.map +1 -1
  112. package/build/lib/suspense.js +2 -9
  113. package/build/lib/suspense.js.map +1 -1
  114. package/build/lib/suspense.mjs +1 -8
  115. package/build/lib/suspense.mjs.map +1 -1
  116. package/build/lib/types.d.ts +11 -10
  117. package/build/lib/types.d.ts.map +1 -0
  118. package/build/lib/useBaseQuery.d.ts +1 -0
  119. package/build/lib/useBaseQuery.d.ts.map +1 -0
  120. package/build/lib/useBaseQuery.esm.js +2 -12
  121. package/build/lib/useBaseQuery.esm.js.map +1 -1
  122. package/build/lib/useBaseQuery.js +2 -12
  123. package/build/lib/useBaseQuery.js.map +1 -1
  124. package/build/lib/useBaseQuery.mjs +2 -12
  125. package/build/lib/useBaseQuery.mjs.map +1 -1
  126. package/build/lib/useInfiniteQuery.d.ts +1 -0
  127. package/build/lib/useInfiniteQuery.d.ts.map +1 -0
  128. package/build/lib/useInfiniteQuery.esm.js +1 -0
  129. package/build/lib/useInfiniteQuery.esm.js.map +1 -1
  130. package/build/lib/useInfiniteQuery.js +1 -0
  131. package/build/lib/useInfiniteQuery.js.map +1 -1
  132. package/build/lib/useInfiniteQuery.mjs +1 -0
  133. package/build/lib/useInfiniteQuery.mjs.map +1 -1
  134. package/build/lib/useIsFetching.d.ts +1 -0
  135. package/build/lib/useIsFetching.d.ts.map +1 -0
  136. package/build/lib/useIsFetching.esm.js +1 -0
  137. package/build/lib/useIsFetching.esm.js.map +1 -1
  138. package/build/lib/useIsFetching.js +1 -0
  139. package/build/lib/useIsFetching.js.map +1 -1
  140. package/build/lib/useIsFetching.mjs +1 -0
  141. package/build/lib/useIsFetching.mjs.map +1 -1
  142. package/build/lib/useMutation.d.ts +1 -0
  143. package/build/lib/useMutation.d.ts.map +1 -0
  144. package/build/lib/useMutation.esm.js +2 -1
  145. package/build/lib/useMutation.esm.js.map +1 -1
  146. package/build/lib/useMutation.js +2 -1
  147. package/build/lib/useMutation.js.map +1 -1
  148. package/build/lib/useMutation.mjs +2 -1
  149. package/build/lib/useMutation.mjs.map +1 -1
  150. package/build/lib/useMutationState.d.ts +4 -3
  151. package/build/lib/useMutationState.d.ts.map +1 -0
  152. package/build/lib/useMutationState.esm.js +1 -0
  153. package/build/lib/useMutationState.esm.js.map +1 -1
  154. package/build/lib/useMutationState.js +1 -0
  155. package/build/lib/useMutationState.js.map +1 -1
  156. package/build/lib/useMutationState.mjs +1 -0
  157. package/build/lib/useMutationState.mjs.map +1 -1
  158. package/build/lib/useQueries.d.ts +10 -8
  159. package/build/lib/useQueries.d.ts.map +1 -0
  160. package/build/lib/useQueries.esm.js +39 -27
  161. package/build/lib/useQueries.esm.js.map +1 -1
  162. package/build/lib/useQueries.js +39 -27
  163. package/build/lib/useQueries.js.map +1 -1
  164. package/build/lib/useQueries.mjs +31 -22
  165. package/build/lib/useQueries.mjs.map +1 -1
  166. package/build/lib/useQuery.d.ts +5 -2
  167. package/build/lib/useQuery.d.ts.map +1 -0
  168. package/build/lib/useQuery.esm.js +6 -1
  169. package/build/lib/useQuery.esm.js.map +1 -1
  170. package/build/lib/useQuery.js +6 -0
  171. package/build/lib/useQuery.js.map +1 -1
  172. package/build/lib/useQuery.mjs +6 -1
  173. package/build/lib/useQuery.mjs.map +1 -1
  174. package/build/lib/utils.d.ts +1 -0
  175. package/build/lib/utils.d.ts.map +1 -0
  176. package/build/lib/utils.esm.js.map +1 -1
  177. package/build/lib/utils.js.map +1 -1
  178. package/build/lib/utils.mjs.map +1 -1
  179. package/build/umd/index.development.js +191 -187
  180. package/build/umd/index.development.js.map +1 -1
  181. package/build/umd/index.production.js +1 -1
  182. package/build/umd/index.production.js.map +1 -1
  183. package/package.json +13 -6
  184. package/src/__tests__/HydrationBoundary.test.tsx +4 -3
  185. package/src/__tests__/QueryClientProvider.test.tsx +2 -1
  186. package/src/__tests__/QueryResetErrorBoundary.test.tsx +753 -620
  187. package/src/__tests__/ssr-hydration.test.tsx +11 -10
  188. package/src/__tests__/ssr.test.tsx +4 -7
  189. package/src/__tests__/suspense.test.tsx +17 -98
  190. package/src/__tests__/useInfiniteQuery.test.tsx +18 -16
  191. package/src/__tests__/useInfiniteQuery.type.test.tsx +94 -13
  192. package/src/__tests__/useMutation.test.tsx +25 -24
  193. package/src/__tests__/useMutationState.test.tsx +24 -58
  194. package/src/__tests__/useQueries.test.tsx +217 -154
  195. package/src/__tests__/useQuery.test.tsx +234 -365
  196. package/src/__tests__/useQuery.types.test.tsx +21 -1
  197. package/src/__tests__/utils.tsx +3 -2
  198. package/src/errorBoundaryUtils.ts +6 -5
  199. package/src/index.ts +1 -1
  200. package/src/suspense.ts +9 -15
  201. package/src/useBaseQuery.ts +2 -20
  202. package/src/useInfiniteQuery.ts +1 -0
  203. package/src/useIsFetching.ts +1 -0
  204. package/src/useMutation.ts +2 -1
  205. package/src/useMutationState.ts +4 -3
  206. package/src/useQueries.ts +44 -26
  207. package/src/useQuery.ts +23 -0
@@ -21,6 +21,8 @@ import type {
21
21
  } from '..'
22
22
  import { QueryCache, useQuery, keepPreviousData } from '..'
23
23
  import { ErrorBoundary } from 'react-error-boundary'
24
+ import { vi } from 'vitest'
25
+ import type { Mock } from 'vitest'
24
26
 
25
27
  describe('useQuery', () => {
26
28
  const queryCache = new QueryCache()
@@ -62,23 +64,17 @@ describe('useQuery', () => {
62
64
  useQuery({
63
65
  queryKey: [key],
64
66
  queryFn: async () => true,
65
- onSuccess: (data) => expectType<boolean>(data),
66
- onSettled: (data) => expectType<boolean | undefined>(data),
67
67
  })
68
68
 
69
69
  // it should be possible to specify a union type as result type
70
70
  const unionTypeSync = useQuery({
71
71
  queryKey: key,
72
72
  queryFn: () => (Math.random() > 0.5 ? 'a' : 'b'),
73
-
74
- onSuccess: (data) => expectType<'a' | 'b'>(data),
75
73
  })
76
74
  expectType<'a' | 'b' | undefined>(unionTypeSync.data)
77
75
  const unionTypeAsync = useQuery<'a' | 'b'>({
78
76
  queryKey: key,
79
77
  queryFn: () => Promise.resolve(Math.random() > 0.5 ? 'a' : 'b'),
80
-
81
- onSuccess: (data) => expectType<'a' | 'b'>(data),
82
78
  })
83
79
  expectType<'a' | 'b' | undefined>(unionTypeAsync.data)
84
80
 
@@ -448,255 +444,6 @@ describe('useQuery', () => {
448
444
  })
449
445
  })
450
446
 
451
- it('should call onSuccess after a query has been fetched', async () => {
452
- const key = queryKey()
453
- const states: UseQueryResult<string>[] = []
454
- const onSuccess = jest.fn()
455
-
456
- function Page() {
457
- const state = useQuery({
458
- queryKey: key,
459
- queryFn: async () => {
460
- await sleep(10)
461
- return 'data'
462
- },
463
- onSuccess,
464
- })
465
- states.push(state)
466
- return <div>data: {state.data}</div>
467
- }
468
-
469
- const rendered = renderWithClient(queryClient, <Page />)
470
-
471
- await rendered.findByText('data: data')
472
- expect(states.length).toBe(2)
473
- expect(onSuccess).toHaveBeenCalledTimes(1)
474
- expect(onSuccess).toHaveBeenCalledWith('data')
475
- })
476
-
477
- it('should call onSuccess after a query has been refetched', async () => {
478
- const key = queryKey()
479
- const states: UseQueryResult<string>[] = []
480
- const onSuccess = jest.fn()
481
- let count = 0
482
-
483
- function Page() {
484
- const state = useQuery({
485
- queryKey: key,
486
- queryFn: async () => {
487
- count++
488
- await sleep(10)
489
- return 'data' + count
490
- },
491
- onSuccess,
492
- })
493
-
494
- states.push(state)
495
-
496
- return (
497
- <div>
498
- <div>data: {state.data}</div>
499
- <button onClick={() => state.refetch()}>refetch</button>
500
- </div>
501
- )
502
- }
503
-
504
- const rendered = renderWithClient(queryClient, <Page />)
505
-
506
- await rendered.findByText('data: data1')
507
- fireEvent.click(rendered.getByRole('button', { name: /refetch/i }))
508
- await rendered.findByText('data: data2')
509
-
510
- expect(states.length).toBe(3) //pending, success, success after refetch
511
- expect(count).toBe(2)
512
- expect(onSuccess).toHaveBeenCalledTimes(2)
513
- })
514
-
515
- it('should call onSuccess after a disabled query has been fetched', async () => {
516
- const key = queryKey()
517
- const states: UseQueryResult<string>[] = []
518
- const onSuccess = jest.fn()
519
-
520
- function Page() {
521
- const state = useQuery({
522
- queryKey: key,
523
- queryFn: () => 'data',
524
- enabled: false,
525
- onSuccess,
526
- })
527
-
528
- states.push(state)
529
-
530
- return (
531
- <div>
532
- <div>isSuccess: {state.isSuccess ? 'true' : 'false'}</div>
533
- <button onClick={() => state.refetch()}>refetch</button>
534
- </div>
535
- )
536
- }
537
-
538
- const rendered = renderWithClient(queryClient, <Page />)
539
-
540
- await waitFor(() => {
541
- rendered.getByText('isSuccess: false')
542
- })
543
-
544
- fireEvent.click(rendered.getByRole('button', { name: 'refetch' }))
545
-
546
- await waitFor(() => {
547
- rendered.getByText('isSuccess: true')
548
- })
549
-
550
- expect(onSuccess).toHaveBeenCalledTimes(1)
551
- expect(onSuccess).toHaveBeenCalledWith('data')
552
- })
553
-
554
- it('should not call onSuccess if a component has unmounted', async () => {
555
- const key = queryKey()
556
- const states: UseQueryResult<string>[] = []
557
- const onSuccess = jest.fn()
558
-
559
- function Page() {
560
- const [show, setShow] = React.useState(true)
561
-
562
- React.useEffect(() => {
563
- setShow(false)
564
- }, [setShow])
565
-
566
- return show ? <Component /> : null
567
- }
568
-
569
- function Component() {
570
- const state = useQuery({
571
- queryKey: key,
572
- queryFn: async () => {
573
- await sleep(10)
574
- return 'data'
575
- },
576
- onSuccess,
577
- })
578
- states.push(state)
579
- return null
580
- }
581
-
582
- renderWithClient(queryClient, <Page />)
583
-
584
- await sleep(50)
585
- expect(states.length).toBe(1)
586
- expect(onSuccess).toHaveBeenCalledTimes(0)
587
- })
588
-
589
- it('should call onError after a query has been fetched with an error', async () => {
590
- const key = queryKey()
591
- const states: UseQueryResult<unknown>[] = []
592
- const onError = jest.fn()
593
-
594
- function Page() {
595
- const state = useQuery<unknown>({
596
- queryKey: key,
597
- queryFn: () => Promise.reject(new Error('error')),
598
- retry: false,
599
- onError,
600
- })
601
- states.push(state)
602
- return null
603
- }
604
-
605
- renderWithClient(queryClient, <Page />)
606
-
607
- await sleep(10)
608
- expect(states.length).toBe(2)
609
- expect(onError).toHaveBeenCalledTimes(1)
610
- expect(onError).toHaveBeenCalledWith(new Error('error'))
611
- })
612
-
613
- it('should not call onError when receiving a CancelledError', async () => {
614
- const key = queryKey()
615
- const onError = jest.fn()
616
-
617
- function Page() {
618
- const { status, fetchStatus } = useQuery({
619
- queryKey: key,
620
- queryFn: async () => {
621
- await sleep(10)
622
- return 23
623
- },
624
-
625
- onError,
626
- })
627
- return (
628
- <span>
629
- status: {status}, fetchStatus: {fetchStatus}
630
- </span>
631
- )
632
- }
633
-
634
- const rendered = renderWithClient(queryClient, <Page />)
635
-
636
- rendered.getByText('status: pending, fetchStatus: fetching')
637
-
638
- await queryClient.cancelQueries({ queryKey: key })
639
- // query cancellation will reset the query to it's initial state
640
- await waitFor(() =>
641
- rendered.getByText('status: pending, fetchStatus: idle'),
642
- )
643
- expect(onError).not.toHaveBeenCalled()
644
- })
645
-
646
- it('should call onSettled after a query has been fetched', async () => {
647
- const key = queryKey()
648
- const states: UseQueryResult<string>[] = []
649
- const onSettled = jest.fn()
650
-
651
- function Page() {
652
- const state = useQuery({
653
- queryKey: key,
654
- queryFn: () => 'data',
655
- onSettled,
656
- })
657
- states.push(state)
658
-
659
- return <div>data: {state.data}</div>
660
- }
661
-
662
- const rendered = renderWithClient(queryClient, <Page />)
663
-
664
- await waitFor(() => {
665
- rendered.getByText('data: data')
666
- })
667
-
668
- expect(states.length).toBe(2)
669
- expect(onSettled).toHaveBeenCalledTimes(1)
670
- expect(onSettled).toHaveBeenCalledWith('data', null)
671
- })
672
-
673
- it('should call onSettled after a query has been fetched with an error', async () => {
674
- const key = queryKey()
675
- const onSettled = jest.fn()
676
- const error = new Error('error')
677
-
678
- function Page() {
679
- const state = useQuery({
680
- queryKey: key,
681
- queryFn: async () => {
682
- await sleep(10)
683
- return Promise.reject(error)
684
- },
685
- retry: false,
686
- onSettled,
687
- })
688
- return <div>status: {state.status}</div>
689
- }
690
-
691
- const rendered = renderWithClient(queryClient, <Page />)
692
-
693
- await waitFor(() => {
694
- rendered.getByText('status: error')
695
- })
696
- expect(onSettled).toHaveBeenCalledTimes(1)
697
- expect(onSettled).toHaveBeenCalledWith(undefined, error)
698
- })
699
-
700
447
  it('should not cancel an ongoing fetch when refetch is called with cancelRefetch=false if we have data already', async () => {
701
448
  const key = queryKey()
702
449
  let fetchCount = 0
@@ -1726,6 +1473,213 @@ describe('useQuery', () => {
1726
1473
  })
1727
1474
  })
1728
1475
 
1476
+ it('should keep the previous data when placeholderData is set and select fn transform is used', async () => {
1477
+ const key = queryKey()
1478
+ const states: UseQueryResult<number>[] = []
1479
+
1480
+ function Page() {
1481
+ const [count, setCount] = React.useState(0)
1482
+
1483
+ const state = useQuery({
1484
+ queryKey: [key, count],
1485
+ queryFn: async () => {
1486
+ await sleep(10)
1487
+ return {
1488
+ count,
1489
+ }
1490
+ },
1491
+ select(data) {
1492
+ return data.count
1493
+ },
1494
+ placeholderData: keepPreviousData,
1495
+ })
1496
+
1497
+ states.push(state)
1498
+
1499
+ return (
1500
+ <div>
1501
+ <div>data: {state.data}</div>
1502
+ <button onClick={() => setCount(1)}>setCount</button>
1503
+ </div>
1504
+ )
1505
+ }
1506
+
1507
+ const rendered = renderWithClient(queryClient, <Page />)
1508
+
1509
+ await waitFor(() => rendered.getByText('data: 0'))
1510
+
1511
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1512
+
1513
+ await waitFor(() => rendered.getByText('data: 1'))
1514
+
1515
+ // Initial
1516
+ expect(states[0]).toMatchObject({
1517
+ data: undefined,
1518
+ isFetching: true,
1519
+ isSuccess: false,
1520
+ isPlaceholderData: false,
1521
+ })
1522
+ // Fetched
1523
+ expect(states[1]).toMatchObject({
1524
+ data: 0,
1525
+ isFetching: false,
1526
+ isSuccess: true,
1527
+ isPlaceholderData: false,
1528
+ })
1529
+ // Set state
1530
+ expect(states[2]).toMatchObject({
1531
+ data: 0,
1532
+ isFetching: true,
1533
+ isSuccess: true,
1534
+ isPlaceholderData: true,
1535
+ })
1536
+ // New data
1537
+ expect(states[3]).toMatchObject({
1538
+ data: 1,
1539
+ isFetching: false,
1540
+ isSuccess: true,
1541
+ isPlaceholderData: false,
1542
+ })
1543
+ })
1544
+
1545
+ it('should keep the previous queryKey (from prevQuery) between multiple pending queries when placeholderData is set and select fn transform is used', async () => {
1546
+ const keys: Array<readonly unknown[] | null> = []
1547
+ const key = queryKey()
1548
+ const states: UseQueryResult<number>[] = []
1549
+
1550
+ function Page() {
1551
+ const [count, setCount] = React.useState(0)
1552
+
1553
+ const state = useQuery({
1554
+ queryKey: [key, count],
1555
+ queryFn: async () => {
1556
+ await sleep(10)
1557
+ return {
1558
+ count,
1559
+ }
1560
+ },
1561
+ select(data) {
1562
+ return data.count
1563
+ },
1564
+ placeholderData: (prevData, prevQuery) => {
1565
+ if (prevQuery) {
1566
+ keys.push(prevQuery.queryKey)
1567
+ }
1568
+ return prevData
1569
+ },
1570
+ })
1571
+
1572
+ states.push(state)
1573
+
1574
+ return (
1575
+ <div>
1576
+ <div>data: {state.data}</div>
1577
+ <button onClick={() => setCount((prev) => prev + 1)}>setCount</button>
1578
+ </div>
1579
+ )
1580
+ }
1581
+
1582
+ const rendered = renderWithClient(queryClient, <Page />)
1583
+
1584
+ await waitFor(() => rendered.getByText('data: 0'))
1585
+
1586
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1587
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1588
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1589
+
1590
+ await waitFor(() => rendered.getByText('data: 3'))
1591
+
1592
+ const allPreviousKeysAreTheFirstQueryKey = keys.every(
1593
+ (k) => JSON.stringify(k) === JSON.stringify([key, 0]),
1594
+ )
1595
+
1596
+ expect(allPreviousKeysAreTheFirstQueryKey).toBe(true)
1597
+ })
1598
+
1599
+ it('should show placeholderData between multiple pending queries when select fn transform is used', async () => {
1600
+ const key = queryKey()
1601
+ const states: UseQueryResult<number>[] = []
1602
+
1603
+ function Page() {
1604
+ const [count, setCount] = React.useState(0)
1605
+
1606
+ const state = useQuery({
1607
+ queryKey: [key, count],
1608
+ queryFn: async () => {
1609
+ await sleep(10)
1610
+ return {
1611
+ count,
1612
+ }
1613
+ },
1614
+ select(data) {
1615
+ return data.count
1616
+ },
1617
+ placeholderData: keepPreviousData,
1618
+ })
1619
+
1620
+ states.push(state)
1621
+
1622
+ return (
1623
+ <div>
1624
+ <div>data: {state.data}</div>
1625
+ <button onClick={() => setCount((prev) => prev + 1)}>setCount</button>
1626
+ </div>
1627
+ )
1628
+ }
1629
+
1630
+ const rendered = renderWithClient(queryClient, <Page />)
1631
+
1632
+ await waitFor(() => rendered.getByText('data: 0'))
1633
+
1634
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1635
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1636
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1637
+
1638
+ await waitFor(() => rendered.getByText('data: 3'))
1639
+ // Initial
1640
+ expect(states[0]).toMatchObject({
1641
+ data: undefined,
1642
+ isFetching: true,
1643
+ isSuccess: false,
1644
+ isPlaceholderData: false,
1645
+ })
1646
+ // Fetched
1647
+ expect(states[1]).toMatchObject({
1648
+ data: 0,
1649
+ isFetching: false,
1650
+ isSuccess: true,
1651
+ isPlaceholderData: false,
1652
+ })
1653
+ // Set state -> count = 1
1654
+ expect(states[2]).toMatchObject({
1655
+ data: 0,
1656
+ isFetching: true,
1657
+ isSuccess: true,
1658
+ isPlaceholderData: true,
1659
+ })
1660
+ // Set state -> count = 2
1661
+ expect(states[3]).toMatchObject({
1662
+ data: 0,
1663
+ isFetching: true,
1664
+ isSuccess: true,
1665
+ isPlaceholderData: true,
1666
+ })
1667
+ // Set state -> count = 3
1668
+ expect(states[4]).toMatchObject({
1669
+ data: 0,
1670
+ isFetching: true,
1671
+ isSuccess: true,
1672
+ isPlaceholderData: true,
1673
+ })
1674
+ // New data
1675
+ expect(states[5]).toMatchObject({
1676
+ data: 3,
1677
+ isFetching: false,
1678
+ isSuccess: true,
1679
+ isPlaceholderData: false,
1680
+ })
1681
+ })
1682
+
1729
1683
  it('should transition to error state when placeholderData is set', async () => {
1730
1684
  const key = queryKey()
1731
1685
  const states: UseQueryResult<number>[] = []
@@ -2432,53 +2386,6 @@ describe('useQuery', () => {
2432
2386
  expect(renders).toBe(2)
2433
2387
  })
2434
2388
 
2435
- it('should batch re-renders including hook callbacks', async () => {
2436
- const key = queryKey()
2437
-
2438
- let renders = 0
2439
- let callbackCount = 0
2440
-
2441
- const queryFn = async () => {
2442
- await sleep(10)
2443
- return 'data'
2444
- }
2445
-
2446
- function Page() {
2447
- const [count, setCount] = React.useState(0)
2448
- useQuery({
2449
- queryKey: key,
2450
- queryFn,
2451
- onSuccess: () => {
2452
- setCount((x) => x + 1)
2453
- },
2454
- })
2455
- useQuery({
2456
- queryKey: key,
2457
- queryFn,
2458
- onSuccess: () => {
2459
- setCount((x) => x + 1)
2460
- },
2461
- })
2462
-
2463
- React.useEffect(() => {
2464
- renders++
2465
- callbackCount = count
2466
- })
2467
-
2468
- return <div>count: {count}</div>
2469
- }
2470
-
2471
- const rendered = renderWithClient(queryClient, <Page />)
2472
-
2473
- await waitFor(() => rendered.getByText('count: 2'))
2474
-
2475
- // Should be 3 instead of 5
2476
- expect(renders).toBe(3)
2477
-
2478
- // Both callbacks should have been executed
2479
- expect(callbackCount).toBe(2)
2480
- })
2481
-
2482
2389
  it('should render latest data even if react has discarded certain renders', async () => {
2483
2390
  const key = queryKey()
2484
2391
 
@@ -2584,7 +2491,7 @@ describe('useQuery', () => {
2584
2491
 
2585
2492
  it('should not refetch query on focus when `enabled` is set to `false`', async () => {
2586
2493
  const key = queryKey()
2587
- const queryFn = jest.fn<string, unknown[]>().mockReturnValue('data')
2494
+ const queryFn = vi.fn<unknown[], string>().mockReturnValue('data')
2588
2495
 
2589
2496
  function Page() {
2590
2497
  const { data = 'default' } = useQuery({
@@ -2894,8 +2801,8 @@ describe('useQuery', () => {
2894
2801
  await waitFor(() => rendered.getByText('Error test jaylen'))
2895
2802
  })
2896
2803
 
2897
- it('should throw error if queryFn throws and throwErrors is in use', async () => {
2898
- const consoleMock = jest
2804
+ it('should throw error if queryFn throws and throwOnError is in use', async () => {
2805
+ const consoleMock = vi
2899
2806
  .spyOn(console, 'error')
2900
2807
  .mockImplementation(() => undefined)
2901
2808
  const key = queryKey()
@@ -2905,7 +2812,7 @@ describe('useQuery', () => {
2905
2812
  queryKey: key,
2906
2813
  queryFn: () => Promise.reject(new Error('Error test jaylen')),
2907
2814
  retry: false,
2908
- throwErrors: true,
2815
+ throwOnError: true,
2909
2816
  })
2910
2817
 
2911
2818
  return (
@@ -2927,7 +2834,7 @@ describe('useQuery', () => {
2927
2834
  consoleMock.mockRestore()
2928
2835
  })
2929
2836
 
2930
- it('should update with data if we observe no properties and throwErrors', async () => {
2837
+ it('should update with data if we observe no properties and throwOnError', async () => {
2931
2838
  const key = queryKey()
2932
2839
 
2933
2840
  let result: UseQueryResult<string> | undefined
@@ -2936,7 +2843,7 @@ describe('useQuery', () => {
2936
2843
  const query = useQuery({
2937
2844
  queryKey: key,
2938
2845
  queryFn: () => Promise.resolve('data'),
2939
- throwErrors: true,
2846
+ throwOnError: true,
2940
2847
  })
2941
2848
 
2942
2849
  React.useEffect(() => {
@@ -2964,7 +2871,7 @@ describe('useQuery', () => {
2964
2871
  queryFn: () => Promise.reject(new Error('Local Error')),
2965
2872
 
2966
2873
  retry: false,
2967
- throwErrors: (err) => err.message !== 'Local Error',
2874
+ throwOnError: (err) => err.message !== 'Local Error',
2968
2875
  })
2969
2876
 
2970
2877
  return (
@@ -2987,7 +2894,7 @@ describe('useQuery', () => {
2987
2894
  })
2988
2895
 
2989
2896
  it('should throw error instead of setting status when error should be thrown', async () => {
2990
- const consoleMock = jest
2897
+ const consoleMock = vi
2991
2898
  .spyOn(console, 'error')
2992
2899
  .mockImplementation(() => undefined)
2993
2900
 
@@ -2999,7 +2906,7 @@ describe('useQuery', () => {
2999
2906
  queryFn: () => Promise.reject(new Error('Remote Error')),
3000
2907
 
3001
2908
  retry: false,
3002
- throwErrors: (err) => err.message !== 'Local Error',
2909
+ throwOnError: (err) => err.message !== 'Local Error',
3003
2910
  })
3004
2911
 
3005
2912
  return (
@@ -3355,7 +3262,7 @@ describe('useQuery', () => {
3355
3262
  it('should retry specified number of times', async () => {
3356
3263
  const key = queryKey()
3357
3264
 
3358
- const queryFn = jest.fn<unknown, unknown[]>()
3265
+ const queryFn = vi.fn<unknown[], unknown>()
3359
3266
  queryFn.mockImplementation(() => {
3360
3267
  return Promise.reject(new Error('Error test Barrett'))
3361
3268
  })
@@ -3392,7 +3299,7 @@ describe('useQuery', () => {
3392
3299
  it('should not retry if retry function `false`', async () => {
3393
3300
  const key = queryKey()
3394
3301
 
3395
- const queryFn = jest.fn<unknown, unknown[]>()
3302
+ const queryFn = vi.fn<unknown[], unknown>()
3396
3303
 
3397
3304
  queryFn.mockImplementationOnce(() => {
3398
3305
  return Promise.reject(new Error('Error test Tanner'))
@@ -3438,7 +3345,7 @@ describe('useQuery', () => {
3438
3345
 
3439
3346
  type DelayError = { delay: number }
3440
3347
 
3441
- const queryFn = jest.fn<unknown, unknown[]>()
3348
+ const queryFn = vi.fn<unknown[], unknown>()
3442
3349
  queryFn.mockImplementation(() => {
3443
3350
  return Promise.reject({ delay: 50 })
3444
3351
  })
@@ -3631,10 +3538,10 @@ describe('useQuery', () => {
3631
3538
  const key = queryKey()
3632
3539
  const states: UseQueryResult<string>[] = []
3633
3540
 
3634
- const queryFn = jest.fn<string, unknown[]>()
3541
+ const queryFn = vi.fn<unknown[], string>()
3635
3542
  queryFn.mockImplementation(() => 'data')
3636
3543
 
3637
- const prefetchQueryFn = jest.fn<string, unknown[]>()
3544
+ const prefetchQueryFn = vi.fn<unknown[], string>()
3638
3545
  prefetchQueryFn.mockImplementation(() => 'not yet...')
3639
3546
 
3640
3547
  await queryClient.prefetchQuery({
@@ -3662,10 +3569,10 @@ describe('useQuery', () => {
3662
3569
  it('should not refetch if not stale after a prefetch', async () => {
3663
3570
  const key = queryKey()
3664
3571
 
3665
- const queryFn = jest.fn<string, unknown[]>()
3572
+ const queryFn = vi.fn<unknown[], string>()
3666
3573
  queryFn.mockImplementation(() => 'data')
3667
3574
 
3668
- const prefetchQueryFn = jest.fn<Promise<string>, unknown[]>()
3575
+ const prefetchQueryFn = vi.fn<unknown[], Promise<string>>()
3669
3576
  prefetchQueryFn.mockImplementation(async () => {
3670
3577
  await sleep(10)
3671
3578
  return 'not yet...'
@@ -3971,7 +3878,7 @@ describe('useQuery', () => {
3971
3878
 
3972
3879
  it('it should support enabled:false in query object syntax', async () => {
3973
3880
  const key = queryKey()
3974
- const queryFn = jest.fn<string, unknown[]>()
3881
+ const queryFn = vi.fn<unknown[], string>()
3975
3882
  queryFn.mockImplementation(() => 'data')
3976
3883
 
3977
3884
  function Page() {
@@ -4030,15 +3937,11 @@ describe('useQuery', () => {
4030
3937
  const rendered = renderWithClient(queryClient, <Page />)
4031
3938
 
4032
3939
  await waitFor(() => rendered.getByText('fetched data'))
4033
- jest.useFakeTimers({
4034
- legacyFakeTimers: true,
4035
- })
4036
- const setTimeoutSpy = jest.spyOn(globalThis.window, 'setTimeout')
3940
+ const setTimeoutSpy = vi.spyOn(globalThis.window, 'setTimeout')
4037
3941
 
4038
3942
  rendered.unmount()
4039
3943
 
4040
3944
  expect(setTimeoutSpy).not.toHaveBeenCalled()
4041
- jest.useRealTimers()
4042
3945
  })
4043
3946
 
4044
3947
  test('should schedule garbage collection, if gcTimeout is not set to infinity', async () => {
@@ -4057,10 +3960,7 @@ describe('useQuery', () => {
4057
3960
 
4058
3961
  await waitFor(() => rendered.getByText('fetched data'))
4059
3962
 
4060
- jest.useFakeTimers({
4061
- legacyFakeTimers: true,
4062
- })
4063
- const setTimeoutSpy = jest.spyOn(globalThis.window, 'setTimeout')
3963
+ const setTimeoutSpy = vi.spyOn(globalThis.window, 'setTimeout')
4064
3964
 
4065
3965
  rendered.unmount()
4066
3966
 
@@ -4068,13 +3968,12 @@ describe('useQuery', () => {
4068
3968
  expect.any(Function),
4069
3969
  1000 * 60 * 10,
4070
3970
  )
4071
- jest.useRealTimers()
4072
3971
  })
4073
3972
 
4074
3973
  it('should not cause memo churn when data does not change', async () => {
4075
3974
  const key = queryKey()
4076
- const queryFn = jest.fn<string, unknown[]>().mockReturnValue('data')
4077
- const memoFn = jest.fn()
3975
+ const queryFn = vi.fn<unknown[], string>().mockReturnValue('data')
3976
+ const memoFn = vi.fn()
4078
3977
 
4079
3978
  function Page() {
4080
3979
  const result = useQuery({
@@ -4281,7 +4180,7 @@ describe('useQuery', () => {
4281
4180
  it('should refetch if any query instance becomes enabled', async () => {
4282
4181
  const key = queryKey()
4283
4182
 
4284
- const queryFn = jest.fn<string, unknown[]>().mockReturnValue('data')
4183
+ const queryFn = vi.fn<unknown[], string>().mockReturnValue('data')
4285
4184
 
4286
4185
  function Disabled() {
4287
4186
  useQuery({ queryKey: key, queryFn, enabled: false })
@@ -4640,11 +4539,11 @@ describe('useQuery', () => {
4640
4539
 
4641
4540
  it('should cancel the query function when there are no more subscriptions', async () => {
4642
4541
  const key = queryKey()
4643
- let cancelFn: jest.Mock = jest.fn()
4542
+ let cancelFn: Mock = vi.fn()
4644
4543
 
4645
4544
  const queryFn = ({ signal }: { signal?: AbortSignal }) => {
4646
4545
  const promise = new Promise<string>((resolve, reject) => {
4647
- cancelFn = jest.fn(() => reject('Cancelled'))
4546
+ cancelFn = vi.fn(() => reject('Cancelled'))
4648
4547
  signal?.addEventListener('abort', cancelFn)
4649
4548
  sleep(20).then(() => resolve('OK'))
4650
4549
  })
@@ -4963,7 +4862,7 @@ describe('useQuery', () => {
4963
4862
  })
4964
4863
 
4965
4864
  it('should refetch when changed enabled to true in error state', async () => {
4966
- const queryFn = jest.fn<unknown, unknown[]>()
4865
+ const queryFn = vi.fn<unknown[], unknown>()
4967
4866
  queryFn.mockImplementation(async () => {
4968
4867
  await sleep(10)
4969
4868
  return Promise.reject(new Error('Suspense Error Bingo'))
@@ -5979,36 +5878,6 @@ describe('useQuery', () => {
5979
5878
  })
5980
5879
  })
5981
5880
 
5982
- it('setQueryData - should not call onSuccess callback of active observers', async () => {
5983
- const key = queryKey()
5984
- const onSuccess = jest.fn()
5985
-
5986
- function Page() {
5987
- const state = useQuery({
5988
- queryKey: key,
5989
- queryFn: () => 'data',
5990
- onSuccess,
5991
- })
5992
- return (
5993
- <div>
5994
- <div>data: {state.data}</div>
5995
- <button onClick={() => queryClient.setQueryData(key, 'newData')}>
5996
- setQueryData
5997
- </button>
5998
- </div>
5999
- )
6000
- }
6001
-
6002
- const rendered = renderWithClient(queryClient, <Page />)
6003
-
6004
- await waitFor(() => rendered.getByText('data: data'))
6005
- fireEvent.click(rendered.getByRole('button', { name: /setQueryData/i }))
6006
- await waitFor(() => rendered.getByText('data: newData'))
6007
-
6008
- expect(onSuccess).toHaveBeenCalledTimes(1)
6009
- expect(onSuccess).toHaveBeenCalledWith('data')
6010
- })
6011
-
6012
5881
  it('setQueryData - should respect updatedAt', async () => {
6013
5882
  const key = queryKey()
6014
5883