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

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
@@ -3,7 +3,8 @@ import { ErrorBoundary } from 'react-error-boundary'
3
3
  import * as React from 'react'
4
4
 
5
5
  import { createQueryClient, queryKey, renderWithClient, sleep } from './utils'
6
- import { QueryCache, QueryErrorResetBoundary, useQuery } from '..'
6
+ import { QueryCache, QueryErrorResetBoundary, useQuery, useQueries } from '..'
7
+ import { vi } from 'vitest'
7
8
 
8
9
  // TODO: This should be removed with the types for react-error-boundary get updated.
9
10
  declare module 'react-error-boundary' {
@@ -16,647 +17,779 @@ describe('QueryErrorResetBoundary', () => {
16
17
  const queryCache = new QueryCache()
17
18
  const queryClient = createQueryClient({ queryCache })
18
19
 
19
- it('should retry fetch if the reset error boundary has been reset', async () => {
20
- const consoleMock = jest
21
- .spyOn(console, 'error')
22
- .mockImplementation(() => undefined)
23
- const key = queryKey()
24
-
25
- let succeed = false
26
-
27
- function Page() {
28
- const { data } = useQuery({
29
- queryKey: key,
30
- queryFn: async () => {
31
- await sleep(10)
32
- if (!succeed) {
33
- throw new Error('Error')
34
- } else {
35
- return 'data'
36
- }
37
- },
38
- retry: false,
39
- throwErrors: true,
40
- })
41
- return <div>{data}</div>
42
- }
43
-
44
- const rendered = renderWithClient(
45
- queryClient,
46
- <QueryErrorResetBoundary>
47
- {({ reset }) => (
48
- <ErrorBoundary
49
- onReset={reset}
50
- fallbackRender={({ resetErrorBoundary }) => (
51
- <div>
52
- <div>error boundary</div>
53
- <button
54
- onClick={() => {
55
- resetErrorBoundary()
56
- }}
57
- >
58
- retry
59
- </button>
60
- </div>
61
- )}
62
- >
63
- <Page />
64
- </ErrorBoundary>
65
- )}
66
- </QueryErrorResetBoundary>,
67
- )
68
-
69
- await waitFor(() => rendered.getByText('error boundary'))
70
- await waitFor(() => rendered.getByText('retry'))
71
- succeed = true
72
- fireEvent.click(rendered.getByText('retry'))
73
- await waitFor(() => rendered.getByText('data'))
74
- consoleMock.mockRestore()
75
- })
76
-
77
- it('should not throw error if query is disabled', async () => {
78
- const consoleMock = jest
79
- .spyOn(console, 'error')
80
- .mockImplementation(() => undefined)
81
- const key = queryKey()
82
-
83
- let succeed = false
84
-
85
- function Page() {
86
- const { data, status } = useQuery({
87
- queryKey: key,
88
- queryFn: async () => {
89
- await sleep(10)
90
- if (!succeed) {
91
- throw new Error('Error')
92
- } else {
93
- return 'data'
94
- }
95
- },
96
- retry: false,
97
- enabled: !succeed,
98
- throwErrors: true,
99
- })
100
- return (
101
- <div>
102
- <div>status: {status}</div>
103
- <div>{data}</div>
104
- </div>
20
+ describe('useQuery', () => {
21
+ it('should retry fetch if the reset error boundary has been reset', async () => {
22
+ const consoleMock = vi
23
+ .spyOn(console, 'error')
24
+ .mockImplementation(() => undefined)
25
+ const key = queryKey()
26
+
27
+ let succeed = false
28
+
29
+ function Page() {
30
+ const { data } = useQuery({
31
+ queryKey: key,
32
+ queryFn: async () => {
33
+ await sleep(10)
34
+ if (!succeed) {
35
+ throw new Error('Error')
36
+ } else {
37
+ return 'data'
38
+ }
39
+ },
40
+ retry: false,
41
+ throwOnError: true,
42
+ })
43
+ return <div>{data}</div>
44
+ }
45
+
46
+ const rendered = renderWithClient(
47
+ queryClient,
48
+ <QueryErrorResetBoundary>
49
+ {({ reset }) => (
50
+ <ErrorBoundary
51
+ onReset={reset}
52
+ fallbackRender={({ resetErrorBoundary }) => (
53
+ <div>
54
+ <div>error boundary</div>
55
+ <button
56
+ onClick={() => {
57
+ resetErrorBoundary()
58
+ }}
59
+ >
60
+ retry
61
+ </button>
62
+ </div>
63
+ )}
64
+ >
65
+ <Page />
66
+ </ErrorBoundary>
67
+ )}
68
+ </QueryErrorResetBoundary>,
105
69
  )
106
- }
107
-
108
- const rendered = renderWithClient(
109
- queryClient,
110
- <QueryErrorResetBoundary>
111
- {({ reset }) => (
112
- <ErrorBoundary
113
- onReset={reset}
114
- fallbackRender={({ resetErrorBoundary }) => (
115
- <div>
116
- <div>error boundary</div>
117
- <button
118
- onClick={() => {
119
- resetErrorBoundary()
120
- }}
121
- >
122
- retry
123
- </button>
124
- </div>
125
- )}
126
- >
127
- <Page />
128
- </ErrorBoundary>
129
- )}
130
- </QueryErrorResetBoundary>,
131
- )
132
-
133
- await waitFor(() => rendered.getByText('error boundary'))
134
- await waitFor(() => rendered.getByText('retry'))
135
- succeed = true
136
- fireEvent.click(rendered.getByText('retry'))
137
- await waitFor(() => rendered.getByText('status: error'))
138
- consoleMock.mockRestore()
139
- })
140
-
141
- it('should not throw error if query is disabled, and refetch if query becomes enabled again', async () => {
142
- const consoleMock = jest
143
- .spyOn(console, 'error')
144
- .mockImplementation(() => undefined)
145
-
146
- const key = queryKey()
147
70
 
148
- let succeed = false
149
-
150
- function Page() {
151
- const [enabled, setEnabled] = React.useState(false)
152
- const { data } = useQuery({
153
- queryKey: key,
154
- queryFn: async () => {
155
- await sleep(10)
156
- if (!succeed) {
157
- throw new Error('Error')
158
- } else {
159
- return 'data'
160
- }
161
- },
162
- retry: false,
163
- enabled,
164
- throwErrors: true,
165
- })
166
-
167
- React.useEffect(() => {
168
- setEnabled(true)
169
- }, [])
170
-
171
- return <div>{data}</div>
172
- }
173
-
174
- const rendered = renderWithClient(
175
- queryClient,
176
- <QueryErrorResetBoundary>
177
- {({ reset }) => (
178
- <ErrorBoundary
179
- onReset={reset}
180
- fallbackRender={({ resetErrorBoundary }) => (
181
- <div>
182
- <div>error boundary</div>
183
- <button
184
- onClick={() => {
185
- resetErrorBoundary()
186
- }}
187
- >
188
- retry
189
- </button>
190
- </div>
191
- )}
192
- >
193
- <Page />
194
- </ErrorBoundary>
195
- )}
196
- </QueryErrorResetBoundary>,
197
- )
198
-
199
- await waitFor(() => rendered.getByText('error boundary'))
200
- await waitFor(() => rendered.getByText('retry'))
201
- succeed = true
202
- fireEvent.click(rendered.getByText('retry'))
203
- await waitFor(() => rendered.getByText('data'))
204
- consoleMock.mockRestore()
205
- })
206
-
207
- it('should throw error if query is disabled and manually refetched', async () => {
208
- const consoleMock = jest
209
- .spyOn(console, 'error')
210
- .mockImplementation(() => undefined)
211
-
212
- const key = queryKey()
213
-
214
- function Page() {
215
- const { data, refetch, status, fetchStatus } = useQuery<string>({
216
- queryKey: key,
217
- queryFn: async () => {
218
- throw new Error('Error')
219
- },
220
- retry: false,
221
- enabled: false,
222
- throwErrors: true,
223
- })
224
-
225
- return (
226
- <div>
227
- <button onClick={() => refetch()}>refetch</button>
71
+ await waitFor(() => rendered.getByText('error boundary'))
72
+ await waitFor(() => rendered.getByText('retry'))
73
+ succeed = true
74
+ fireEvent.click(rendered.getByText('retry'))
75
+ await waitFor(() => rendered.getByText('data'))
76
+ consoleMock.mockRestore()
77
+ })
78
+
79
+ it('should not throw error if query is disabled', async () => {
80
+ const consoleMock = vi
81
+ .spyOn(console, 'error')
82
+ .mockImplementation(() => undefined)
83
+ const key = queryKey()
84
+
85
+ let succeed = false
86
+
87
+ function Page() {
88
+ const { data, status } = useQuery({
89
+ queryKey: key,
90
+ queryFn: async () => {
91
+ await sleep(10)
92
+ if (!succeed) {
93
+ throw new Error('Error')
94
+ } else {
95
+ return 'data'
96
+ }
97
+ },
98
+ retry: false,
99
+ enabled: !succeed,
100
+ throwOnError: true,
101
+ })
102
+ return (
228
103
  <div>
229
- status: {status}, fetchStatus: {fetchStatus}
104
+ <div>status: {status}</div>
105
+ <div>{data}</div>
230
106
  </div>
231
- <div>{data}</div>
232
- </div>
107
+ )
108
+ }
109
+
110
+ const rendered = renderWithClient(
111
+ queryClient,
112
+ <QueryErrorResetBoundary>
113
+ {({ reset }) => (
114
+ <ErrorBoundary
115
+ onReset={reset}
116
+ fallbackRender={({ resetErrorBoundary }) => (
117
+ <div>
118
+ <div>error boundary</div>
119
+ <button
120
+ onClick={() => {
121
+ resetErrorBoundary()
122
+ }}
123
+ >
124
+ retry
125
+ </button>
126
+ </div>
127
+ )}
128
+ >
129
+ <Page />
130
+ </ErrorBoundary>
131
+ )}
132
+ </QueryErrorResetBoundary>,
233
133
  )
234
- }
235
-
236
- const rendered = renderWithClient(
237
- queryClient,
238
- <QueryErrorResetBoundary>
239
- {({ reset }) => (
240
- <ErrorBoundary
241
- onReset={reset}
242
- fallbackRender={({ resetErrorBoundary }) => (
243
- <div>
244
- <div>error boundary</div>
245
- <button
246
- onClick={() => {
247
- resetErrorBoundary()
248
- }}
249
- >
250
- retry
251
- </button>
252
- </div>
253
- )}
254
- >
255
- <Page />
256
- </ErrorBoundary>
257
- )}
258
- </QueryErrorResetBoundary>,
259
- )
260
-
261
- await waitFor(() =>
262
- rendered.getByText('status: pending, fetchStatus: idle'),
263
- )
264
- fireEvent.click(rendered.getByRole('button', { name: /refetch/i }))
265
- await waitFor(() => rendered.getByText('error boundary'))
266
- consoleMock.mockRestore()
267
- })
268
-
269
- it('should not retry fetch if the reset error boundary has not been reset', async () => {
270
- const consoleMock = jest
271
- .spyOn(console, 'error')
272
- .mockImplementation(() => undefined)
273
-
274
- const key = queryKey()
275
-
276
- let succeed = false
277
-
278
- function Page() {
279
- const { data } = useQuery({
280
- queryKey: key,
281
- queryFn: async () => {
282
- await sleep(10)
283
- if (!succeed) {
284
- throw new Error('Error')
285
- } else {
286
- return 'data'
287
- }
288
- },
289
- retry: false,
290
- throwErrors: true,
291
- })
292
- return <div>{data}</div>
293
- }
294
-
295
- const rendered = renderWithClient(
296
- queryClient,
297
- <QueryErrorResetBoundary>
298
- {() => (
299
- <ErrorBoundary
300
- fallbackRender={({ resetErrorBoundary }) => (
301
- <div>
302
- <div>error boundary</div>
303
- <button
304
- onClick={() => {
305
- resetErrorBoundary()
306
- }}
307
- >
308
- retry
309
- </button>
310
- </div>
311
- )}
312
- >
313
- <Page />
314
- </ErrorBoundary>
315
- )}
316
- </QueryErrorResetBoundary>,
317
- )
318
-
319
- await waitFor(() => rendered.getByText('error boundary'))
320
- await waitFor(() => rendered.getByText('retry'))
321
- succeed = true
322
- fireEvent.click(rendered.getByText('retry'))
323
- await waitFor(() => rendered.getByText('error boundary'))
324
- consoleMock.mockRestore()
325
- })
326
-
327
- it('should retry fetch if the reset error boundary has been reset and the query contains data from a previous fetch', async () => {
328
- const consoleMock = jest
329
- .spyOn(console, 'error')
330
- .mockImplementation(() => undefined)
331
-
332
- const key = queryKey()
333
134
 
334
- let succeed = false
135
+ await waitFor(() => rendered.getByText('error boundary'))
136
+ await waitFor(() => rendered.getByText('retry'))
137
+ succeed = true
138
+ fireEvent.click(rendered.getByText('retry'))
139
+ await waitFor(() => rendered.getByText('status: error'))
140
+ consoleMock.mockRestore()
141
+ })
142
+
143
+ it('should not throw error if query is disabled, and refetch if query becomes enabled again', async () => {
144
+ const consoleMock = vi
145
+ .spyOn(console, 'error')
146
+ .mockImplementation(() => undefined)
147
+
148
+ const key = queryKey()
149
+
150
+ let succeed = false
151
+
152
+ function Page() {
153
+ const [enabled, setEnabled] = React.useState(false)
154
+ const { data } = useQuery({
155
+ queryKey: key,
156
+ queryFn: async () => {
157
+ await sleep(10)
158
+ if (!succeed) {
159
+ throw new Error('Error')
160
+ } else {
161
+ return 'data'
162
+ }
163
+ },
164
+ retry: false,
165
+ enabled,
166
+ throwOnError: true,
167
+ })
168
+
169
+ React.useEffect(() => {
170
+ setEnabled(true)
171
+ }, [])
172
+
173
+ return <div>{data}</div>
174
+ }
175
+
176
+ const rendered = renderWithClient(
177
+ queryClient,
178
+ <QueryErrorResetBoundary>
179
+ {({ reset }) => (
180
+ <ErrorBoundary
181
+ onReset={reset}
182
+ fallbackRender={({ resetErrorBoundary }) => (
183
+ <div>
184
+ <div>error boundary</div>
185
+ <button
186
+ onClick={() => {
187
+ resetErrorBoundary()
188
+ }}
189
+ >
190
+ retry
191
+ </button>
192
+ </div>
193
+ )}
194
+ >
195
+ <Page />
196
+ </ErrorBoundary>
197
+ )}
198
+ </QueryErrorResetBoundary>,
199
+ )
335
200
 
336
- function Page() {
337
- const { data } = useQuery({
338
- queryKey: key,
339
- queryFn: async () => {
340
- await sleep(10)
341
- if (!succeed) {
201
+ await waitFor(() => rendered.getByText('error boundary'))
202
+ await waitFor(() => rendered.getByText('retry'))
203
+ succeed = true
204
+ fireEvent.click(rendered.getByText('retry'))
205
+ await waitFor(() => rendered.getByText('data'))
206
+ consoleMock.mockRestore()
207
+ })
208
+
209
+ it('should throw error if query is disabled and manually refetched', async () => {
210
+ const consoleMock = vi
211
+ .spyOn(console, 'error')
212
+ .mockImplementation(() => undefined)
213
+
214
+ const key = queryKey()
215
+
216
+ function Page() {
217
+ const { data, refetch, status, fetchStatus } = useQuery<string>({
218
+ queryKey: key,
219
+ queryFn: async () => {
342
220
  throw new Error('Error')
343
- } else {
344
- return 'data'
345
- }
346
- },
347
- retry: false,
348
- throwErrors: true,
349
- initialData: 'initial',
350
- })
351
- return <div>{data}</div>
352
- }
353
-
354
- const rendered = renderWithClient(
355
- queryClient,
356
- <QueryErrorResetBoundary>
357
- {({ reset }) => (
358
- <ErrorBoundary
359
- onReset={reset}
360
- fallbackRender={({ resetErrorBoundary }) => (
361
- <div>
362
- <div>error boundary</div>
363
- <button
364
- onClick={() => {
365
- resetErrorBoundary()
366
- }}
367
- >
368
- retry
369
- </button>
370
- </div>
371
- )}
372
- >
373
- <Page />
374
- </ErrorBoundary>
375
- )}
376
- </QueryErrorResetBoundary>,
377
- )
378
-
379
- await waitFor(() => rendered.getByText('error boundary'))
380
- await waitFor(() => rendered.getByText('retry'))
381
- succeed = true
382
- fireEvent.click(rendered.getByText('retry'))
383
- await waitFor(() => rendered.getByText('data'))
384
- consoleMock.mockRestore()
385
- })
221
+ },
222
+ retry: false,
223
+ enabled: false,
224
+ throwOnError: true,
225
+ })
386
226
 
387
- it('should not retry fetch if the reset error boundary has not been reset after a previous reset', async () => {
388
- const consoleMock = jest
389
- .spyOn(console, 'error')
390
- .mockImplementation(() => undefined)
391
-
392
- const key = queryKey()
227
+ return (
228
+ <div>
229
+ <button onClick={() => refetch()}>refetch</button>
230
+ <div>
231
+ status: {status}, fetchStatus: {fetchStatus}
232
+ </div>
233
+ <div>{data}</div>
234
+ </div>
235
+ )
236
+ }
237
+
238
+ const rendered = renderWithClient(
239
+ queryClient,
240
+ <QueryErrorResetBoundary>
241
+ {({ reset }) => (
242
+ <ErrorBoundary
243
+ onReset={reset}
244
+ fallbackRender={({ resetErrorBoundary }) => (
245
+ <div>
246
+ <div>error boundary</div>
247
+ <button
248
+ onClick={() => {
249
+ resetErrorBoundary()
250
+ }}
251
+ >
252
+ retry
253
+ </button>
254
+ </div>
255
+ )}
256
+ >
257
+ <Page />
258
+ </ErrorBoundary>
259
+ )}
260
+ </QueryErrorResetBoundary>,
261
+ )
393
262
 
394
- let succeed = false
395
- let shouldReset = true
263
+ await waitFor(() =>
264
+ rendered.getByText('status: pending, fetchStatus: idle'),
265
+ )
266
+ fireEvent.click(rendered.getByRole('button', { name: /refetch/i }))
267
+ await waitFor(() => rendered.getByText('error boundary'))
268
+ consoleMock.mockRestore()
269
+ })
270
+
271
+ it('should not retry fetch if the reset error boundary has not been reset', async () => {
272
+ const consoleMock = vi
273
+ .spyOn(console, 'error')
274
+ .mockImplementation(() => undefined)
275
+
276
+ const key = queryKey()
277
+
278
+ let succeed = false
279
+
280
+ function Page() {
281
+ const { data } = useQuery({
282
+ queryKey: key,
283
+ queryFn: async () => {
284
+ await sleep(10)
285
+ if (!succeed) {
286
+ throw new Error('Error')
287
+ } else {
288
+ return 'data'
289
+ }
290
+ },
291
+ retry: false,
292
+ throwOnError: true,
293
+ })
294
+ return <div>{data}</div>
295
+ }
296
+
297
+ const rendered = renderWithClient(
298
+ queryClient,
299
+ <QueryErrorResetBoundary>
300
+ {() => (
301
+ <ErrorBoundary
302
+ fallbackRender={({ resetErrorBoundary }) => (
303
+ <div>
304
+ <div>error boundary</div>
305
+ <button
306
+ onClick={() => {
307
+ resetErrorBoundary()
308
+ }}
309
+ >
310
+ retry
311
+ </button>
312
+ </div>
313
+ )}
314
+ >
315
+ <Page />
316
+ </ErrorBoundary>
317
+ )}
318
+ </QueryErrorResetBoundary>,
319
+ )
396
320
 
397
- function Page() {
398
- const { data } = useQuery({
399
- queryKey: key,
400
- queryFn: async () => {
401
- await sleep(10)
402
- if (!succeed) {
403
- throw new Error('Error')
404
- } else {
405
- return 'data'
406
- }
407
- },
408
- retry: false,
409
- throwErrors: true,
410
- })
411
- return <div>{data}</div>
412
- }
413
-
414
- const rendered = renderWithClient(
415
- queryClient,
416
- <QueryErrorResetBoundary>
417
- {({ reset }) => (
418
- <ErrorBoundary
419
- onReset={() => {
420
- if (shouldReset) {
421
- reset()
422
- }
423
- }}
424
- fallbackRender={({ resetErrorBoundary }) => (
425
- <div>
426
- <div>error boundary</div>
427
- <button
428
- onClick={() => {
429
- resetErrorBoundary()
430
- }}
431
- >
432
- retry
433
- </button>
434
- </div>
435
- )}
436
- >
437
- <Page />
438
- </ErrorBoundary>
439
- )}
440
- </QueryErrorResetBoundary>,
441
- )
442
-
443
- await waitFor(() => rendered.getByText('error boundary'))
444
- await waitFor(() => rendered.getByText('retry'))
445
- shouldReset = true
446
- fireEvent.click(rendered.getByText('retry'))
447
- await waitFor(() => rendered.getByText('error boundary'))
448
- succeed = true
449
- shouldReset = false
450
- fireEvent.click(rendered.getByText('retry'))
451
- await waitFor(() => rendered.getByText('error boundary'))
452
- consoleMock.mockRestore()
453
- })
321
+ await waitFor(() => rendered.getByText('error boundary'))
322
+ await waitFor(() => rendered.getByText('retry'))
323
+ succeed = true
324
+ fireEvent.click(rendered.getByText('retry'))
325
+ await waitFor(() => rendered.getByText('error boundary'))
326
+ consoleMock.mockRestore()
327
+ })
328
+
329
+ it('should retry fetch if the reset error boundary has been reset and the query contains data from a previous fetch', async () => {
330
+ const consoleMock = vi
331
+ .spyOn(console, 'error')
332
+ .mockImplementation(() => undefined)
333
+
334
+ const key = queryKey()
335
+
336
+ let succeed = false
337
+
338
+ function Page() {
339
+ const { data } = useQuery({
340
+ queryKey: key,
341
+ queryFn: async () => {
342
+ await sleep(10)
343
+ if (!succeed) {
344
+ throw new Error('Error')
345
+ } else {
346
+ return 'data'
347
+ }
348
+ },
349
+ retry: false,
350
+ throwOnError: true,
351
+ initialData: 'initial',
352
+ })
353
+ return <div>{data}</div>
354
+ }
355
+
356
+ const rendered = renderWithClient(
357
+ queryClient,
358
+ <QueryErrorResetBoundary>
359
+ {({ reset }) => (
360
+ <ErrorBoundary
361
+ onReset={reset}
362
+ fallbackRender={({ resetErrorBoundary }) => (
363
+ <div>
364
+ <div>error boundary</div>
365
+ <button
366
+ onClick={() => {
367
+ resetErrorBoundary()
368
+ }}
369
+ >
370
+ retry
371
+ </button>
372
+ </div>
373
+ )}
374
+ >
375
+ <Page />
376
+ </ErrorBoundary>
377
+ )}
378
+ </QueryErrorResetBoundary>,
379
+ )
454
380
 
455
- it('should throw again on error after the reset error boundary has been reset', async () => {
456
- const consoleMock = jest
457
- .spyOn(console, 'error')
458
- .mockImplementation(() => undefined)
459
-
460
- const key = queryKey()
461
- let fetchCount = 0
462
-
463
- function Page() {
464
- const { data } = useQuery<string>({
465
- queryKey: key,
466
- queryFn: async () => {
467
- fetchCount++
468
- await sleep(10)
469
- throw new Error('Error')
470
- },
471
- retry: false,
472
- throwErrors: true,
473
- })
474
- return <div>{data}</div>
475
- }
476
-
477
- const rendered = renderWithClient(
478
- queryClient,
479
- <QueryErrorResetBoundary>
480
- {({ reset }) => (
481
- <ErrorBoundary
482
- onReset={reset}
483
- fallbackRender={({ resetErrorBoundary }) => (
484
- <div>
485
- <div>error boundary</div>
486
- <button
487
- onClick={() => {
488
- resetErrorBoundary()
489
- }}
490
- >
491
- retry
492
- </button>
493
- </div>
494
- )}
495
- >
496
- <Page />
497
- </ErrorBoundary>
498
- )}
499
- </QueryErrorResetBoundary>,
500
- )
501
-
502
- await waitFor(() => rendered.getByText('error boundary'))
503
- await waitFor(() => rendered.getByText('retry'))
504
- fireEvent.click(rendered.getByText('retry'))
505
- await waitFor(() => rendered.getByText('error boundary'))
506
- await waitFor(() => rendered.getByText('retry'))
507
- fireEvent.click(rendered.getByText('retry'))
508
- await waitFor(() => rendered.getByText('error boundary'))
509
- expect(fetchCount).toBe(3)
510
- consoleMock.mockRestore()
511
- })
381
+ await waitFor(() => rendered.getByText('error boundary'))
382
+ await waitFor(() => rendered.getByText('retry'))
383
+ succeed = true
384
+ fireEvent.click(rendered.getByText('retry'))
385
+ await waitFor(() => rendered.getByText('data'))
386
+ consoleMock.mockRestore()
387
+ })
388
+
389
+ it('should not retry fetch if the reset error boundary has not been reset after a previous reset', async () => {
390
+ const consoleMock = vi
391
+ .spyOn(console, 'error')
392
+ .mockImplementation(() => undefined)
393
+
394
+ const key = queryKey()
395
+
396
+ let succeed = false
397
+ let shouldReset = true
398
+
399
+ function Page() {
400
+ const { data } = useQuery({
401
+ queryKey: key,
402
+ queryFn: async () => {
403
+ await sleep(10)
404
+ if (!succeed) {
405
+ throw new Error('Error')
406
+ } else {
407
+ return 'data'
408
+ }
409
+ },
410
+ retry: false,
411
+ throwOnError: true,
412
+ })
413
+ return <div>{data}</div>
414
+ }
415
+
416
+ const rendered = renderWithClient(
417
+ queryClient,
418
+ <QueryErrorResetBoundary>
419
+ {({ reset }) => (
420
+ <ErrorBoundary
421
+ onReset={() => {
422
+ if (shouldReset) {
423
+ reset()
424
+ }
425
+ }}
426
+ fallbackRender={({ resetErrorBoundary }) => (
427
+ <div>
428
+ <div>error boundary</div>
429
+ <button
430
+ onClick={() => {
431
+ resetErrorBoundary()
432
+ }}
433
+ >
434
+ retry
435
+ </button>
436
+ </div>
437
+ )}
438
+ >
439
+ <Page />
440
+ </ErrorBoundary>
441
+ )}
442
+ </QueryErrorResetBoundary>,
443
+ )
512
444
 
513
- it('should never render the component while the query is in error state', async () => {
514
- const consoleMock = jest
515
- .spyOn(console, 'error')
516
- .mockImplementation(() => undefined)
517
-
518
- const key = queryKey()
519
- let fetchCount = 0
520
- let renders = 0
521
-
522
- function Page() {
523
- const { data } = useQuery({
524
- queryKey: key,
525
- queryFn: async () => {
526
- fetchCount++
527
- await sleep(10)
528
- if (fetchCount > 2) {
529
- return 'data'
530
- } else {
445
+ await waitFor(() => rendered.getByText('error boundary'))
446
+ await waitFor(() => rendered.getByText('retry'))
447
+ shouldReset = true
448
+ fireEvent.click(rendered.getByText('retry'))
449
+ await waitFor(() => rendered.getByText('error boundary'))
450
+ succeed = true
451
+ shouldReset = false
452
+ fireEvent.click(rendered.getByText('retry'))
453
+ await waitFor(() => rendered.getByText('error boundary'))
454
+ consoleMock.mockRestore()
455
+ })
456
+
457
+ it('should throw again on error after the reset error boundary has been reset', async () => {
458
+ const consoleMock = vi
459
+ .spyOn(console, 'error')
460
+ .mockImplementation(() => undefined)
461
+
462
+ const key = queryKey()
463
+ let fetchCount = 0
464
+
465
+ function Page() {
466
+ const { data } = useQuery<string>({
467
+ queryKey: key,
468
+ queryFn: async () => {
469
+ fetchCount++
470
+ await sleep(10)
531
471
  throw new Error('Error')
532
- }
533
- },
534
- retry: false,
535
- suspense: true,
536
- })
537
- renders++
538
- return <div>{data}</div>
539
- }
540
-
541
- const rendered = renderWithClient(
542
- queryClient,
543
- <QueryErrorResetBoundary>
544
- {({ reset }) => (
545
- <ErrorBoundary
546
- onReset={reset}
547
- fallbackRender={({ resetErrorBoundary }) => (
548
- <div>
549
- <div>error boundary</div>
550
- <button
551
- onClick={() => {
552
- resetErrorBoundary()
553
- }}
554
- >
555
- retry
556
- </button>
557
- </div>
558
- )}
559
- >
560
- <React.Suspense fallback={<div>loading</div>}>
472
+ },
473
+ retry: false,
474
+ throwOnError: true,
475
+ })
476
+ return <div>{data}</div>
477
+ }
478
+
479
+ const rendered = renderWithClient(
480
+ queryClient,
481
+ <QueryErrorResetBoundary>
482
+ {({ reset }) => (
483
+ <ErrorBoundary
484
+ onReset={reset}
485
+ fallbackRender={({ resetErrorBoundary }) => (
486
+ <div>
487
+ <div>error boundary</div>
488
+ <button
489
+ onClick={() => {
490
+ resetErrorBoundary()
491
+ }}
492
+ >
493
+ retry
494
+ </button>
495
+ </div>
496
+ )}
497
+ >
561
498
  <Page />
562
- </React.Suspense>
563
- </ErrorBoundary>
564
- )}
565
- </QueryErrorResetBoundary>,
566
- )
567
-
568
- await waitFor(() => rendered.getByText('error boundary'))
569
- await waitFor(() => rendered.getByText('retry'))
570
- fireEvent.click(rendered.getByText('retry'))
571
- await waitFor(() => rendered.getByText('error boundary'))
572
- await waitFor(() => rendered.getByText('retry'))
573
- fireEvent.click(rendered.getByText('retry'))
574
- await waitFor(() => rendered.getByText('data'))
575
- expect(fetchCount).toBe(3)
576
- expect(renders).toBe(1)
577
- consoleMock.mockRestore()
578
- })
499
+ </ErrorBoundary>
500
+ )}
501
+ </QueryErrorResetBoundary>,
502
+ )
579
503
 
580
- it('should render children', async () => {
581
- const consoleMock = jest
582
- .spyOn(console, 'error')
583
- .mockImplementation(() => undefined)
504
+ await waitFor(() => rendered.getByText('error boundary'))
505
+ await waitFor(() => rendered.getByText('retry'))
506
+ fireEvent.click(rendered.getByText('retry'))
507
+ await waitFor(() => rendered.getByText('error boundary'))
508
+ await waitFor(() => rendered.getByText('retry'))
509
+ fireEvent.click(rendered.getByText('retry'))
510
+ await waitFor(() => rendered.getByText('error boundary'))
511
+ expect(fetchCount).toBe(3)
512
+ consoleMock.mockRestore()
513
+ })
514
+
515
+ it('should never render the component while the query is in error state', async () => {
516
+ const consoleMock = vi
517
+ .spyOn(console, 'error')
518
+ .mockImplementation(() => undefined)
519
+
520
+ const key = queryKey()
521
+ let fetchCount = 0
522
+ let renders = 0
523
+
524
+ function Page() {
525
+ const { data } = useQuery({
526
+ queryKey: key,
527
+ queryFn: async () => {
528
+ fetchCount++
529
+ await sleep(10)
530
+ if (fetchCount > 2) {
531
+ return 'data'
532
+ } else {
533
+ throw new Error('Error')
534
+ }
535
+ },
536
+ retry: false,
537
+ suspense: true,
538
+ })
539
+ renders++
540
+ return <div>{data}</div>
541
+ }
542
+
543
+ const rendered = renderWithClient(
544
+ queryClient,
545
+ <QueryErrorResetBoundary>
546
+ {({ reset }) => (
547
+ <ErrorBoundary
548
+ onReset={reset}
549
+ fallbackRender={({ resetErrorBoundary }) => (
550
+ <div>
551
+ <div>error boundary</div>
552
+ <button
553
+ onClick={() => {
554
+ resetErrorBoundary()
555
+ }}
556
+ >
557
+ retry
558
+ </button>
559
+ </div>
560
+ )}
561
+ >
562
+ <React.Suspense fallback={<div>loading</div>}>
563
+ <Page />
564
+ </React.Suspense>
565
+ </ErrorBoundary>
566
+ )}
567
+ </QueryErrorResetBoundary>,
568
+ )
584
569
 
585
- function Page() {
586
- return (
587
- <div>
588
- <span>page</span>
589
- </div>
570
+ await waitFor(() => rendered.getByText('error boundary'))
571
+ await waitFor(() => rendered.getByText('retry'))
572
+ fireEvent.click(rendered.getByText('retry'))
573
+ await waitFor(() => rendered.getByText('error boundary'))
574
+ await waitFor(() => rendered.getByText('retry'))
575
+ fireEvent.click(rendered.getByText('retry'))
576
+ await waitFor(() => rendered.getByText('data'))
577
+ expect(fetchCount).toBe(3)
578
+ expect(renders).toBe(1)
579
+ consoleMock.mockRestore()
580
+ })
581
+
582
+ it('should render children', async () => {
583
+ const consoleMock = vi
584
+ .spyOn(console, 'error')
585
+ .mockImplementation(() => undefined)
586
+
587
+ function Page() {
588
+ return (
589
+ <div>
590
+ <span>page</span>
591
+ </div>
592
+ )
593
+ }
594
+
595
+ const rendered = renderWithClient(
596
+ queryClient,
597
+ <QueryErrorResetBoundary>
598
+ <Page />
599
+ </QueryErrorResetBoundary>,
590
600
  )
591
- }
592
601
 
593
- const rendered = renderWithClient(
594
- queryClient,
595
- <QueryErrorResetBoundary>
596
- <Page />
597
- </QueryErrorResetBoundary>,
598
- )
602
+ expect(rendered.queryByText('page')).not.toBeNull()
603
+ consoleMock.mockRestore()
604
+ })
605
+
606
+ it('should show error boundary when using tracked queries even though we do not track the error field', async () => {
607
+ const consoleMock = vi
608
+ .spyOn(console, 'error')
609
+ .mockImplementation(() => undefined)
610
+
611
+ const key = queryKey()
612
+
613
+ let succeed = false
614
+
615
+ function Page() {
616
+ const { data } = useQuery({
617
+ queryKey: key,
618
+ queryFn: async () => {
619
+ await sleep(10)
620
+ if (!succeed) {
621
+ throw new Error('Error')
622
+ } else {
623
+ return 'data'
624
+ }
625
+ },
626
+ retry: false,
627
+ throwOnError: true,
628
+ })
629
+ return <div>{data}</div>
630
+ }
631
+
632
+ const rendered = renderWithClient(
633
+ queryClient,
634
+ <QueryErrorResetBoundary>
635
+ {({ reset }) => (
636
+ <ErrorBoundary
637
+ onReset={reset}
638
+ fallbackRender={({ resetErrorBoundary }) => (
639
+ <div>
640
+ <div>error boundary</div>
641
+ <button
642
+ onClick={() => {
643
+ resetErrorBoundary()
644
+ }}
645
+ >
646
+ retry
647
+ </button>
648
+ </div>
649
+ )}
650
+ >
651
+ <Page />
652
+ </ErrorBoundary>
653
+ )}
654
+ </QueryErrorResetBoundary>,
655
+ )
599
656
 
600
- expect(rendered.queryByText('page')).not.toBeNull()
601
- consoleMock.mockRestore()
657
+ await waitFor(() => rendered.getByText('error boundary'))
658
+ await waitFor(() => rendered.getByText('retry'))
659
+ succeed = true
660
+ fireEvent.click(rendered.getByText('retry'))
661
+ await waitFor(() => rendered.getByText('data'))
662
+ consoleMock.mockRestore()
663
+ })
602
664
  })
665
+ describe('useQueries', () => {
666
+ it('should retry fetch if the reset error boundary has been reset', async () => {
667
+ const consoleMock = vi
668
+ .spyOn(console, 'error')
669
+ .mockImplementation(() => undefined)
670
+ const key = queryKey()
671
+
672
+ let succeed = false
673
+
674
+ function Page() {
675
+ const [{ data }] = useQueries({
676
+ queries: [
677
+ {
678
+ queryKey: key,
679
+ queryFn: async () => {
680
+ await sleep(10)
681
+ if (!succeed) {
682
+ throw new Error('Error')
683
+ } else {
684
+ return 'data'
685
+ }
686
+ },
687
+ retry: false,
688
+ throwOnError: true,
689
+ retryOnMount: true,
690
+ },
691
+ ],
692
+ })
693
+ return <div>{data}</div>
694
+ }
695
+
696
+ const rendered = renderWithClient(
697
+ queryClient,
698
+ <QueryErrorResetBoundary>
699
+ {({ reset }) => (
700
+ <ErrorBoundary
701
+ onReset={reset}
702
+ fallbackRender={({ resetErrorBoundary }) => (
703
+ <div>
704
+ <div>error boundary</div>
705
+ <button
706
+ onClick={() => {
707
+ resetErrorBoundary()
708
+ }}
709
+ >
710
+ retry
711
+ </button>
712
+ </div>
713
+ )}
714
+ >
715
+ <Page />
716
+ </ErrorBoundary>
717
+ )}
718
+ </QueryErrorResetBoundary>,
719
+ )
603
720
 
604
- it('should show error boundary when using tracked queries even though we do not track the error field', async () => {
605
- const consoleMock = jest
606
- .spyOn(console, 'error')
607
- .mockImplementation(() => undefined)
608
-
609
- const key = queryKey()
610
-
611
- let succeed = false
721
+ await waitFor(() => rendered.getByText('error boundary'))
722
+ await waitFor(() => rendered.getByText('retry'))
723
+ succeed = true
724
+ fireEvent.click(rendered.getByText('retry'))
725
+ await waitFor(() => rendered.getByText('data'))
726
+ consoleMock.mockRestore()
727
+ })
728
+
729
+ it('with suspense should retry fetch if the reset error boundary has been reset', async () => {
730
+ const key = queryKey()
731
+ const consoleMock = vi
732
+ .spyOn(console, 'error')
733
+ .mockImplementation(() => undefined)
734
+
735
+ let succeed = false
736
+
737
+ function Page() {
738
+ const [{ data }] = useQueries({
739
+ queries: [
740
+ {
741
+ queryKey: key,
742
+ queryFn: async () => {
743
+ await sleep(10)
744
+ if (!succeed) {
745
+ throw new Error('Error')
746
+ } else {
747
+ return 'data'
748
+ }
749
+ },
750
+ retry: false,
751
+ throwOnError: true,
752
+ retryOnMount: true,
753
+ suspense: true,
754
+ },
755
+ ],
756
+ })
757
+ return <div>{data}</div>
758
+ }
759
+
760
+ const rendered = renderWithClient(
761
+ queryClient,
762
+ <QueryErrorResetBoundary>
763
+ {({ reset }) => (
764
+ <ErrorBoundary
765
+ onReset={reset}
766
+ fallbackRender={({ resetErrorBoundary }) => (
767
+ <div>
768
+ <div>error boundary</div>
769
+ <button
770
+ onClick={() => {
771
+ resetErrorBoundary()
772
+ }}
773
+ >
774
+ retry
775
+ </button>
776
+ </div>
777
+ )}
778
+ >
779
+ <React.Suspense fallback="Loader">
780
+ <Page />
781
+ </React.Suspense>
782
+ </ErrorBoundary>
783
+ )}
784
+ </QueryErrorResetBoundary>,
785
+ )
612
786
 
613
- function Page() {
614
- const { data } = useQuery({
615
- queryKey: key,
616
- queryFn: async () => {
617
- await sleep(10)
618
- if (!succeed) {
619
- throw new Error('Error')
620
- } else {
621
- return 'data'
622
- }
623
- },
624
- retry: false,
625
- throwErrors: true,
626
- })
627
- return <div>{data}</div>
628
- }
629
-
630
- const rendered = renderWithClient(
631
- queryClient,
632
- <QueryErrorResetBoundary>
633
- {({ reset }) => (
634
- <ErrorBoundary
635
- onReset={reset}
636
- fallbackRender={({ resetErrorBoundary }) => (
637
- <div>
638
- <div>error boundary</div>
639
- <button
640
- onClick={() => {
641
- resetErrorBoundary()
642
- }}
643
- >
644
- retry
645
- </button>
646
- </div>
647
- )}
648
- >
649
- <Page />
650
- </ErrorBoundary>
651
- )}
652
- </QueryErrorResetBoundary>,
653
- )
654
-
655
- await waitFor(() => rendered.getByText('error boundary'))
656
- await waitFor(() => rendered.getByText('retry'))
657
- succeed = true
658
- fireEvent.click(rendered.getByText('retry'))
659
- await waitFor(() => rendered.getByText('data'))
660
- consoleMock.mockRestore()
787
+ await waitFor(() => rendered.getByText('error boundary'))
788
+ await waitFor(() => rendered.getByText('retry'))
789
+ succeed = true
790
+ fireEvent.click(rendered.getByText('retry'))
791
+ await waitFor(() => rendered.getByText('data'))
792
+ consoleMock.mockRestore()
793
+ })
661
794
  })
662
795
  })