@pyreon/query 0.10.0 → 0.11.0
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/lib/analysis/index.js.html +1 -1
- package/lib/index.js +164 -2
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +74 -7
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +14 -7
- package/src/index.ts +25 -19
- package/src/query-client.ts +5 -5
- package/src/tests/query.test.tsx +254 -268
- package/src/tests/sse.test.tsx +857 -0
- package/src/tests/subscription.test.tsx +200 -82
- package/src/use-infinite-query.ts +11 -19
- package/src/use-is-fetching.ts +5 -5
- package/src/use-mutation.ts +12 -21
- package/src/use-queries.ts +20 -19
- package/src/use-query-error-reset-boundary.ts +8 -11
- package/src/use-query.ts +10 -17
- package/src/use-sse.ts +266 -0
- package/src/use-subscription.ts +27 -39
- package/src/use-suspense-query.ts +18 -34
package/src/tests/query.test.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { signal } from
|
|
2
|
-
import { mount } from
|
|
3
|
-
import { QueryClient } from
|
|
1
|
+
import { signal } from "@pyreon/reactivity"
|
|
2
|
+
import { mount } from "@pyreon/runtime-dom"
|
|
3
|
+
import { QueryClient } from "@tanstack/query-core"
|
|
4
4
|
import {
|
|
5
5
|
dehydrate,
|
|
6
6
|
hydrate,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
useQueryErrorResetBoundary,
|
|
18
18
|
useSuspenseInfiniteQuery,
|
|
19
19
|
useSuspenseQuery,
|
|
20
|
-
} from
|
|
20
|
+
} from "../index"
|
|
21
21
|
|
|
22
22
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
23
23
|
|
|
@@ -29,7 +29,7 @@ function makeClient() {
|
|
|
29
29
|
|
|
30
30
|
/** Mount a component inside a QueryClientProvider, return unmount fn. */
|
|
31
31
|
function _withProvider(client: QueryClient, component: () => void): () => void {
|
|
32
|
-
const el = document.createElement(
|
|
32
|
+
const el = document.createElement("div")
|
|
33
33
|
document.body.appendChild(el)
|
|
34
34
|
const unmount = mount(
|
|
35
35
|
<QueryClientProvider client={client}>
|
|
@@ -59,16 +59,16 @@ function deferred<T>() {
|
|
|
59
59
|
|
|
60
60
|
// ─── QueryClientProvider / useQueryClient ────────────────────────────────────
|
|
61
61
|
|
|
62
|
-
describe(
|
|
63
|
-
it(
|
|
62
|
+
describe("QueryClientProvider / useQueryClient", () => {
|
|
63
|
+
it("useQueryClient throws when no provider is present", () => {
|
|
64
64
|
// Call directly outside any renderer — context stack is empty so it must throw.
|
|
65
|
-
expect(() => useQueryClient()).toThrow(
|
|
65
|
+
expect(() => useQueryClient()).toThrow("[@pyreon/query]")
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
-
it(
|
|
68
|
+
it("provides the QueryClient to descendants", () => {
|
|
69
69
|
const client = makeClient()
|
|
70
70
|
let received: QueryClient | null = null
|
|
71
|
-
const el = document.createElement(
|
|
71
|
+
const el = document.createElement("div")
|
|
72
72
|
document.body.appendChild(el)
|
|
73
73
|
const unmount = mount(
|
|
74
74
|
<QueryClientProvider client={client}>
|
|
@@ -84,11 +84,11 @@ describe('QueryClientProvider / useQueryClient', () => {
|
|
|
84
84
|
expect(received).toBe(client)
|
|
85
85
|
})
|
|
86
86
|
|
|
87
|
-
it(
|
|
87
|
+
it("inner provider overrides outer", () => {
|
|
88
88
|
const outer = makeClient()
|
|
89
89
|
const inner = makeClient()
|
|
90
90
|
let received: QueryClient | null = null
|
|
91
|
-
const el = document.createElement(
|
|
91
|
+
const el = document.createElement("div")
|
|
92
92
|
document.body.appendChild(el)
|
|
93
93
|
const unmount = mount(
|
|
94
94
|
<QueryClientProvider client={outer}>
|
|
@@ -109,22 +109,22 @@ describe('QueryClientProvider / useQueryClient', () => {
|
|
|
109
109
|
|
|
110
110
|
// ─── useQuery ─────────────────────────────────────────────────────────────────
|
|
111
111
|
|
|
112
|
-
describe(
|
|
112
|
+
describe("useQuery", () => {
|
|
113
113
|
let client: QueryClient
|
|
114
114
|
|
|
115
115
|
beforeEach(() => {
|
|
116
116
|
client = makeClient()
|
|
117
117
|
})
|
|
118
118
|
|
|
119
|
-
it(
|
|
119
|
+
it("starts in pending state when cache is empty", () => {
|
|
120
120
|
let query: ReturnType<typeof useQuery> | undefined
|
|
121
|
-
const el = document.createElement(
|
|
121
|
+
const el = document.createElement("div")
|
|
122
122
|
document.body.appendChild(el)
|
|
123
123
|
const unmount = mount(
|
|
124
124
|
<QueryClientProvider client={client}>
|
|
125
125
|
{() => {
|
|
126
126
|
query = useQuery(() => ({
|
|
127
|
-
queryKey: [
|
|
127
|
+
queryKey: ["test-pending"],
|
|
128
128
|
queryFn: () =>
|
|
129
129
|
new Promise(() => {
|
|
130
130
|
/* never resolves */
|
|
@@ -141,17 +141,17 @@ describe('useQuery', () => {
|
|
|
141
141
|
el.remove()
|
|
142
142
|
})
|
|
143
143
|
|
|
144
|
-
it(
|
|
144
|
+
it("resolves to success state with data", async () => {
|
|
145
145
|
const { promise, resolve } = deferred<{ name: string }>()
|
|
146
146
|
let query: ReturnType<typeof useQuery<{ name: string }>> | undefined
|
|
147
147
|
|
|
148
|
-
const el = document.createElement(
|
|
148
|
+
const el = document.createElement("div")
|
|
149
149
|
document.body.appendChild(el)
|
|
150
150
|
const unmount = mount(
|
|
151
151
|
<QueryClientProvider client={client}>
|
|
152
152
|
{() => {
|
|
153
153
|
query = useQuery(() => ({
|
|
154
|
-
queryKey: [
|
|
154
|
+
queryKey: ["test-success"],
|
|
155
155
|
queryFn: () => promise,
|
|
156
156
|
}))
|
|
157
157
|
return null
|
|
@@ -160,29 +160,29 @@ describe('useQuery', () => {
|
|
|
160
160
|
el,
|
|
161
161
|
)
|
|
162
162
|
|
|
163
|
-
resolve({ name:
|
|
163
|
+
resolve({ name: "Pyreon" })
|
|
164
164
|
await promise
|
|
165
165
|
|
|
166
166
|
// Let the observer's internal promise chain flush
|
|
167
167
|
await new Promise((r) => setTimeout(r, 0))
|
|
168
168
|
|
|
169
169
|
expect(query!.isSuccess()).toBe(true)
|
|
170
|
-
expect(query!.data()).toEqual({ name:
|
|
170
|
+
expect(query!.data()).toEqual({ name: "Pyreon" })
|
|
171
171
|
unmount()
|
|
172
172
|
el.remove()
|
|
173
173
|
})
|
|
174
174
|
|
|
175
|
-
it(
|
|
175
|
+
it("captures errors in isError state", async () => {
|
|
176
176
|
const { promise, reject } = deferred<never>()
|
|
177
177
|
let query: ReturnType<typeof useQuery> | undefined
|
|
178
178
|
|
|
179
|
-
const el = document.createElement(
|
|
179
|
+
const el = document.createElement("div")
|
|
180
180
|
document.body.appendChild(el)
|
|
181
181
|
const unmount = mount(
|
|
182
182
|
<QueryClientProvider client={client}>
|
|
183
183
|
{() => {
|
|
184
184
|
query = useQuery(() => ({
|
|
185
|
-
queryKey: [
|
|
185
|
+
queryKey: ["test-error"],
|
|
186
186
|
queryFn: () => promise,
|
|
187
187
|
}))
|
|
188
188
|
return null
|
|
@@ -191,29 +191,29 @@ describe('useQuery', () => {
|
|
|
191
191
|
el,
|
|
192
192
|
)
|
|
193
193
|
|
|
194
|
-
reject(new Error(
|
|
194
|
+
reject(new Error("fetch failed"))
|
|
195
195
|
await promise.catch(() => {
|
|
196
196
|
/* expected */
|
|
197
197
|
})
|
|
198
198
|
await new Promise((r) => setTimeout(r, 0))
|
|
199
199
|
|
|
200
200
|
expect(query!.isError()).toBe(true)
|
|
201
|
-
expect((query!.error() as Error).message).toBe(
|
|
201
|
+
expect((query!.error() as Error).message).toBe("fetch failed")
|
|
202
202
|
unmount()
|
|
203
203
|
el.remove()
|
|
204
204
|
})
|
|
205
205
|
|
|
206
|
-
it(
|
|
207
|
-
const queryFn = vi.fn(() => Promise.resolve(
|
|
206
|
+
it("respects enabled: false — does not fetch", async () => {
|
|
207
|
+
const queryFn = vi.fn(() => Promise.resolve("should not run"))
|
|
208
208
|
let query: ReturnType<typeof useQuery<string>> | undefined
|
|
209
209
|
|
|
210
|
-
const el = document.createElement(
|
|
210
|
+
const el = document.createElement("div")
|
|
211
211
|
document.body.appendChild(el)
|
|
212
212
|
const unmount = mount(
|
|
213
213
|
<QueryClientProvider client={client}>
|
|
214
214
|
{() => {
|
|
215
215
|
query = useQuery(() => ({
|
|
216
|
-
queryKey: [
|
|
216
|
+
queryKey: ["test-disabled"],
|
|
217
217
|
queryFn,
|
|
218
218
|
enabled: false,
|
|
219
219
|
}))
|
|
@@ -231,18 +231,18 @@ describe('useQuery', () => {
|
|
|
231
231
|
el.remove()
|
|
232
232
|
})
|
|
233
233
|
|
|
234
|
-
it(
|
|
234
|
+
it("reactive query key — refetches when signal changes", async () => {
|
|
235
235
|
const calls: number[] = []
|
|
236
236
|
const userId = signal(1)
|
|
237
237
|
let query: ReturnType<typeof useQuery<string>> | undefined
|
|
238
238
|
|
|
239
|
-
const el = document.createElement(
|
|
239
|
+
const el = document.createElement("div")
|
|
240
240
|
document.body.appendChild(el)
|
|
241
241
|
const unmount = mount(
|
|
242
242
|
<QueryClientProvider client={client}>
|
|
243
243
|
{() => {
|
|
244
244
|
query = useQuery(() => ({
|
|
245
|
-
queryKey: [
|
|
245
|
+
queryKey: ["user", userId()],
|
|
246
246
|
queryFn: async () => {
|
|
247
247
|
const id = userId()
|
|
248
248
|
calls.push(id)
|
|
@@ -262,20 +262,20 @@ describe('useQuery', () => {
|
|
|
262
262
|
await new Promise((r) => setTimeout(r, 10))
|
|
263
263
|
expect(calls).toContain(2)
|
|
264
264
|
|
|
265
|
-
expect(query!.data()).toBe(
|
|
265
|
+
expect(query!.data()).toBe("user-2")
|
|
266
266
|
unmount()
|
|
267
267
|
el.remove()
|
|
268
268
|
})
|
|
269
269
|
|
|
270
|
-
it(
|
|
270
|
+
it("invalidateQueries triggers a refetch", async () => {
|
|
271
271
|
let callCount = 0
|
|
272
|
-
const el = document.createElement(
|
|
272
|
+
const el = document.createElement("div")
|
|
273
273
|
document.body.appendChild(el)
|
|
274
274
|
const unmount = mount(
|
|
275
275
|
<QueryClientProvider client={client}>
|
|
276
276
|
{() => {
|
|
277
277
|
useQuery(() => ({
|
|
278
|
-
queryKey: [
|
|
278
|
+
queryKey: ["invalidate-test"],
|
|
279
279
|
queryFn: async () => {
|
|
280
280
|
callCount++
|
|
281
281
|
return callCount
|
|
@@ -289,7 +289,7 @@ describe('useQuery', () => {
|
|
|
289
289
|
|
|
290
290
|
await new Promise((r) => setTimeout(r, 10))
|
|
291
291
|
const before = callCount
|
|
292
|
-
await client.invalidateQueries({ queryKey: [
|
|
292
|
+
await client.invalidateQueries({ queryKey: ["invalidate-test"] })
|
|
293
293
|
await new Promise((r) => setTimeout(r, 10))
|
|
294
294
|
expect(callCount).toBeGreaterThan(before)
|
|
295
295
|
unmount()
|
|
@@ -299,20 +299,20 @@ describe('useQuery', () => {
|
|
|
299
299
|
|
|
300
300
|
// ─── useMutation ──────────────────────────────────────────────────────────────
|
|
301
301
|
|
|
302
|
-
describe(
|
|
302
|
+
describe("useMutation", () => {
|
|
303
303
|
let client: QueryClient
|
|
304
304
|
beforeEach(() => {
|
|
305
305
|
client = makeClient()
|
|
306
306
|
})
|
|
307
307
|
|
|
308
|
-
it(
|
|
308
|
+
it("starts in idle state", () => {
|
|
309
309
|
let mut: ReturnType<typeof useMutation> | undefined
|
|
310
|
-
const el = document.createElement(
|
|
310
|
+
const el = document.createElement("div")
|
|
311
311
|
document.body.appendChild(el)
|
|
312
312
|
const unmount = mount(
|
|
313
313
|
<QueryClientProvider client={client}>
|
|
314
314
|
{() => {
|
|
315
|
-
mut = useMutation({ mutationFn: () => Promise.resolve(
|
|
315
|
+
mut = useMutation({ mutationFn: () => Promise.resolve("ok") })
|
|
316
316
|
return null
|
|
317
317
|
}}
|
|
318
318
|
</QueryClientProvider>,
|
|
@@ -324,9 +324,9 @@ describe('useMutation', () => {
|
|
|
324
324
|
el.remove()
|
|
325
325
|
})
|
|
326
326
|
|
|
327
|
-
it(
|
|
327
|
+
it("goes pending then success", async () => {
|
|
328
328
|
let mut: ReturnType<typeof useMutation<string, Error, string>> | undefined
|
|
329
|
-
const el = document.createElement(
|
|
329
|
+
const el = document.createElement("div")
|
|
330
330
|
document.body.appendChild(el)
|
|
331
331
|
const unmount = mount(
|
|
332
332
|
<QueryClientProvider client={client}>
|
|
@@ -340,25 +340,25 @@ describe('useMutation', () => {
|
|
|
340
340
|
el,
|
|
341
341
|
)
|
|
342
342
|
|
|
343
|
-
mut!.mutate(
|
|
343
|
+
mut!.mutate("hello")
|
|
344
344
|
await new Promise((r) => setTimeout(r, 10))
|
|
345
345
|
|
|
346
346
|
expect(mut!.isSuccess()).toBe(true)
|
|
347
|
-
expect(mut!.data()).toBe(
|
|
347
|
+
expect(mut!.data()).toBe("result:hello")
|
|
348
348
|
unmount()
|
|
349
349
|
el.remove()
|
|
350
350
|
})
|
|
351
351
|
|
|
352
|
-
it(
|
|
352
|
+
it("captures mutation error", async () => {
|
|
353
353
|
let mut: ReturnType<typeof useMutation> | undefined
|
|
354
|
-
const el = document.createElement(
|
|
354
|
+
const el = document.createElement("div")
|
|
355
355
|
document.body.appendChild(el)
|
|
356
356
|
const unmount = mount(
|
|
357
357
|
<QueryClientProvider client={client}>
|
|
358
358
|
{() => {
|
|
359
359
|
mut = useMutation({
|
|
360
360
|
mutationFn: async () => {
|
|
361
|
-
throw new Error(
|
|
361
|
+
throw new Error("mutation failed")
|
|
362
362
|
},
|
|
363
363
|
})
|
|
364
364
|
return null
|
|
@@ -371,20 +371,20 @@ describe('useMutation', () => {
|
|
|
371
371
|
await new Promise((r) => setTimeout(r, 10))
|
|
372
372
|
|
|
373
373
|
expect(mut!.isError()).toBe(true)
|
|
374
|
-
expect((mut!.error() as Error).message).toBe(
|
|
374
|
+
expect((mut!.error() as Error).message).toBe("mutation failed")
|
|
375
375
|
unmount()
|
|
376
376
|
el.remove()
|
|
377
377
|
})
|
|
378
378
|
|
|
379
|
-
it(
|
|
379
|
+
it("reset() clears mutation state", async () => {
|
|
380
380
|
let mut: ReturnType<typeof useMutation<string, Error, void>> | undefined
|
|
381
|
-
const el = document.createElement(
|
|
381
|
+
const el = document.createElement("div")
|
|
382
382
|
document.body.appendChild(el)
|
|
383
383
|
const unmount = mount(
|
|
384
384
|
<QueryClientProvider client={client}>
|
|
385
385
|
{() => {
|
|
386
386
|
mut = useMutation<string, Error, void>({
|
|
387
|
-
mutationFn: async () =>
|
|
387
|
+
mutationFn: async () => "done",
|
|
388
388
|
})
|
|
389
389
|
return null
|
|
390
390
|
}}
|
|
@@ -407,11 +407,11 @@ describe('useMutation', () => {
|
|
|
407
407
|
|
|
408
408
|
// ─── useIsFetching / useIsMutating ────────────────────────────────────────────
|
|
409
409
|
|
|
410
|
-
describe(
|
|
411
|
-
it(
|
|
410
|
+
describe("useIsFetching", () => {
|
|
411
|
+
it("returns 0 when no queries are in-flight", () => {
|
|
412
412
|
const client = makeClient()
|
|
413
413
|
let count: (() => number) | undefined
|
|
414
|
-
const el = document.createElement(
|
|
414
|
+
const el = document.createElement("div")
|
|
415
415
|
document.body.appendChild(el)
|
|
416
416
|
const unmount = mount(
|
|
417
417
|
<QueryClientProvider client={client}>
|
|
@@ -427,20 +427,20 @@ describe('useIsFetching', () => {
|
|
|
427
427
|
el.remove()
|
|
428
428
|
})
|
|
429
429
|
|
|
430
|
-
it(
|
|
430
|
+
it("increments while a query is fetching", async () => {
|
|
431
431
|
const client = makeClient()
|
|
432
432
|
const { promise, resolve } = deferred<string>()
|
|
433
433
|
const counts: number[] = []
|
|
434
434
|
let isFetching: (() => number) | undefined
|
|
435
435
|
|
|
436
|
-
const el = document.createElement(
|
|
436
|
+
const el = document.createElement("div")
|
|
437
437
|
document.body.appendChild(el)
|
|
438
438
|
const unmount = mount(
|
|
439
439
|
<QueryClientProvider client={client}>
|
|
440
440
|
{() => {
|
|
441
441
|
isFetching = useIsFetching()
|
|
442
442
|
useQuery(() => ({
|
|
443
|
-
queryKey: [
|
|
443
|
+
queryKey: ["fetch-count"],
|
|
444
444
|
queryFn: () => promise,
|
|
445
445
|
}))
|
|
446
446
|
return null
|
|
@@ -453,7 +453,7 @@ describe('useIsFetching', () => {
|
|
|
453
453
|
await new Promise((r) => setTimeout(r, 0))
|
|
454
454
|
counts.push(isFetching!())
|
|
455
455
|
|
|
456
|
-
resolve(
|
|
456
|
+
resolve("done")
|
|
457
457
|
await promise
|
|
458
458
|
await new Promise((r) => setTimeout(r, 10))
|
|
459
459
|
counts.push(isFetching!())
|
|
@@ -465,14 +465,14 @@ describe('useIsFetching', () => {
|
|
|
465
465
|
})
|
|
466
466
|
})
|
|
467
467
|
|
|
468
|
-
describe(
|
|
469
|
-
it(
|
|
468
|
+
describe("useIsMutating", () => {
|
|
469
|
+
it("returns 0 when idle, >0 while mutating", async () => {
|
|
470
470
|
const client = makeClient()
|
|
471
471
|
const { promise, resolve } = deferred<void>()
|
|
472
472
|
let isMutating: (() => number) | undefined
|
|
473
473
|
let mut: ReturnType<typeof useMutation<void, Error, void>> | undefined
|
|
474
474
|
|
|
475
|
-
const el = document.createElement(
|
|
475
|
+
const el = document.createElement("div")
|
|
476
476
|
document.body.appendChild(el)
|
|
477
477
|
const unmount = mount(
|
|
478
478
|
<QueryClientProvider client={client}>
|
|
@@ -500,13 +500,13 @@ describe('useIsMutating', () => {
|
|
|
500
500
|
|
|
501
501
|
// ─── SSR: dehydrate / hydrate ─────────────────────────────────────────────────
|
|
502
502
|
|
|
503
|
-
describe(
|
|
504
|
-
it(
|
|
503
|
+
describe("dehydrate / hydrate", () => {
|
|
504
|
+
it("round-trips query data — prefetched data available without refetching", async () => {
|
|
505
505
|
// Server: prefetch + serialize
|
|
506
506
|
const serverClient = makeClient()
|
|
507
507
|
await serverClient.prefetchQuery({
|
|
508
|
-
queryKey: [
|
|
509
|
-
queryFn: async () => ({ name:
|
|
508
|
+
queryKey: ["ssr-user"],
|
|
509
|
+
queryFn: async () => ({ name: "SSR User" }),
|
|
510
510
|
})
|
|
511
511
|
const state = dehydrate(serverClient)
|
|
512
512
|
|
|
@@ -517,16 +517,16 @@ describe('dehydrate / hydrate', () => {
|
|
|
517
517
|
let query: ReturnType<typeof useQuery<{ name: string }>> | undefined
|
|
518
518
|
let callCount = 0
|
|
519
519
|
|
|
520
|
-
const el = document.createElement(
|
|
520
|
+
const el = document.createElement("div")
|
|
521
521
|
document.body.appendChild(el)
|
|
522
522
|
const unmount = mount(
|
|
523
523
|
<QueryClientProvider client={clientClient}>
|
|
524
524
|
{() => {
|
|
525
525
|
query = useQuery(() => ({
|
|
526
|
-
queryKey: [
|
|
526
|
+
queryKey: ["ssr-user"],
|
|
527
527
|
queryFn: async () => {
|
|
528
528
|
callCount++
|
|
529
|
-
return { name:
|
|
529
|
+
return { name: "fresh" }
|
|
530
530
|
},
|
|
531
531
|
staleTime: Infinity, // treat hydrated data as fresh
|
|
532
532
|
}))
|
|
@@ -538,7 +538,7 @@ describe('dehydrate / hydrate', () => {
|
|
|
538
538
|
|
|
539
539
|
// Data should be immediately available from the hydrated cache
|
|
540
540
|
expect(query!.isSuccess()).toBe(true)
|
|
541
|
-
expect(query!.data()).toEqual({ name:
|
|
541
|
+
expect(query!.data()).toEqual({ name: "SSR User" })
|
|
542
542
|
// queryFn should NOT have been called (data was in cache)
|
|
543
543
|
expect(callCount).toBe(0)
|
|
544
544
|
unmount()
|
|
@@ -548,19 +548,19 @@ describe('dehydrate / hydrate', () => {
|
|
|
548
548
|
|
|
549
549
|
// ─── useQueries ───────────────────────────────────────────────────────────────
|
|
550
550
|
|
|
551
|
-
describe(
|
|
552
|
-
it(
|
|
551
|
+
describe("useQueries", () => {
|
|
552
|
+
it("returns results for all queries in the array", async () => {
|
|
553
553
|
const client = makeClient()
|
|
554
554
|
let results: ReturnType<typeof useQueries> | undefined
|
|
555
555
|
|
|
556
|
-
const el = document.createElement(
|
|
556
|
+
const el = document.createElement("div")
|
|
557
557
|
document.body.appendChild(el)
|
|
558
558
|
const unmount = mount(
|
|
559
559
|
<QueryClientProvider client={client}>
|
|
560
560
|
{() => {
|
|
561
561
|
results = useQueries(() => [
|
|
562
|
-
{ queryKey: [
|
|
563
|
-
{ queryKey: [
|
|
562
|
+
{ queryKey: ["a"], queryFn: async () => "alpha" },
|
|
563
|
+
{ queryKey: ["b"], queryFn: async () => "beta" },
|
|
564
564
|
])
|
|
565
565
|
return null
|
|
566
566
|
}}
|
|
@@ -571,26 +571,26 @@ describe('useQueries', () => {
|
|
|
571
571
|
await new Promise((r) => setTimeout(r, 20))
|
|
572
572
|
const res = results?.() ?? []
|
|
573
573
|
expect(res).toHaveLength(2)
|
|
574
|
-
expect(res[0]!.data).toBe(
|
|
575
|
-
expect(res[1]!.data).toBe(
|
|
574
|
+
expect(res[0]!.data).toBe("alpha")
|
|
575
|
+
expect(res[1]!.data).toBe("beta")
|
|
576
576
|
unmount()
|
|
577
577
|
el.remove()
|
|
578
578
|
})
|
|
579
579
|
|
|
580
|
-
it(
|
|
580
|
+
it("reactive — updates when the queries signal changes", async () => {
|
|
581
581
|
const client = makeClient()
|
|
582
|
-
const { signal: sig } = await import(
|
|
582
|
+
const { signal: sig } = await import("@pyreon/reactivity")
|
|
583
583
|
const ids = sig([1])
|
|
584
584
|
let results: ReturnType<typeof useQueries> | undefined
|
|
585
585
|
|
|
586
|
-
const el = document.createElement(
|
|
586
|
+
const el = document.createElement("div")
|
|
587
587
|
document.body.appendChild(el)
|
|
588
588
|
const unmount = mount(
|
|
589
589
|
<QueryClientProvider client={client}>
|
|
590
590
|
{() => {
|
|
591
591
|
results = useQueries(() =>
|
|
592
592
|
ids().map((id) => ({
|
|
593
|
-
queryKey: [
|
|
593
|
+
queryKey: ["item", id],
|
|
594
594
|
queryFn: async () => `item-${id}`,
|
|
595
595
|
})),
|
|
596
596
|
)
|
|
@@ -606,7 +606,7 @@ describe('useQueries', () => {
|
|
|
606
606
|
ids.set([1, 2])
|
|
607
607
|
await new Promise((r) => setTimeout(r, 20))
|
|
608
608
|
expect(results?.()).toHaveLength(2)
|
|
609
|
-
expect(results!()[1]!.data).toBe(
|
|
609
|
+
expect(results!()[1]!.data).toBe("item-2")
|
|
610
610
|
unmount()
|
|
611
611
|
el.remove()
|
|
612
612
|
})
|
|
@@ -614,23 +614,23 @@ describe('useQueries', () => {
|
|
|
614
614
|
|
|
615
615
|
// ─── useSuspenseQuery / QuerySuspense ─────────────────────────────────────────
|
|
616
616
|
|
|
617
|
-
describe(
|
|
617
|
+
describe("useSuspenseQuery + QuerySuspense", () => {
|
|
618
618
|
let client: QueryClient
|
|
619
619
|
beforeEach(() => {
|
|
620
620
|
client = makeClient()
|
|
621
621
|
})
|
|
622
622
|
|
|
623
|
-
it(
|
|
623
|
+
it("QuerySuspense shows fallback while pending, then children on success", async () => {
|
|
624
624
|
const { promise, resolve } = deferred<string>()
|
|
625
625
|
const rendered: string[] = []
|
|
626
626
|
|
|
627
|
-
const el = document.createElement(
|
|
627
|
+
const el = document.createElement("div")
|
|
628
628
|
document.body.appendChild(el)
|
|
629
629
|
const unmount = mount(
|
|
630
630
|
<QueryClientProvider client={client}>
|
|
631
631
|
{() => {
|
|
632
632
|
const q = useSuspenseQuery(() => ({
|
|
633
|
-
queryKey: [
|
|
633
|
+
queryKey: ["sq-pending"],
|
|
634
634
|
queryFn: () => promise,
|
|
635
635
|
}))
|
|
636
636
|
return (
|
|
@@ -650,25 +650,25 @@ describe('useSuspenseQuery + QuerySuspense', () => {
|
|
|
650
650
|
await new Promise((r) => setTimeout(r, 0))
|
|
651
651
|
expect(rendered).toHaveLength(0)
|
|
652
652
|
|
|
653
|
-
resolve(
|
|
653
|
+
resolve("done")
|
|
654
654
|
await promise
|
|
655
655
|
await new Promise((r) => setTimeout(r, 10))
|
|
656
|
-
expect(rendered.at(-1)).toBe(
|
|
656
|
+
expect(rendered.at(-1)).toBe("done")
|
|
657
657
|
unmount()
|
|
658
658
|
el.remove()
|
|
659
659
|
})
|
|
660
660
|
|
|
661
|
-
it(
|
|
661
|
+
it("QuerySuspense shows error fallback on query failure", async () => {
|
|
662
662
|
const { promise, reject } = deferred<never>()
|
|
663
663
|
let errorMsg: string | undefined
|
|
664
664
|
|
|
665
|
-
const el = document.createElement(
|
|
665
|
+
const el = document.createElement("div")
|
|
666
666
|
document.body.appendChild(el)
|
|
667
667
|
const unmount = mount(
|
|
668
668
|
<QueryClientProvider client={client}>
|
|
669
669
|
{() => {
|
|
670
670
|
const q = useSuspenseQuery(() => ({
|
|
671
|
-
queryKey: [
|
|
671
|
+
queryKey: ["sq-error"],
|
|
672
672
|
queryFn: () => promise,
|
|
673
673
|
}))
|
|
674
674
|
return (
|
|
@@ -688,32 +688,32 @@ describe('useSuspenseQuery + QuerySuspense', () => {
|
|
|
688
688
|
el,
|
|
689
689
|
)
|
|
690
690
|
|
|
691
|
-
reject(new Error(
|
|
691
|
+
reject(new Error("sq failed"))
|
|
692
692
|
await promise.catch(() => {
|
|
693
693
|
/* expected */
|
|
694
694
|
})
|
|
695
695
|
await new Promise((r) => setTimeout(r, 10))
|
|
696
|
-
expect(errorMsg).toBe(
|
|
696
|
+
expect(errorMsg).toBe("sq failed")
|
|
697
697
|
unmount()
|
|
698
698
|
el.remove()
|
|
699
699
|
})
|
|
700
700
|
|
|
701
|
-
it(
|
|
701
|
+
it("multiple queries — children only render when all succeed", async () => {
|
|
702
702
|
const d1 = deferred<string>()
|
|
703
703
|
const d2 = deferred<string>()
|
|
704
704
|
let childrenRendered = false
|
|
705
705
|
|
|
706
|
-
const el = document.createElement(
|
|
706
|
+
const el = document.createElement("div")
|
|
707
707
|
document.body.appendChild(el)
|
|
708
708
|
const unmount = mount(
|
|
709
709
|
<QueryClientProvider client={client}>
|
|
710
710
|
{() => {
|
|
711
711
|
const q1 = useSuspenseQuery(() => ({
|
|
712
|
-
queryKey: [
|
|
712
|
+
queryKey: ["mq1"],
|
|
713
713
|
queryFn: () => d1.promise,
|
|
714
714
|
}))
|
|
715
715
|
const q2 = useSuspenseQuery(() => ({
|
|
716
|
-
queryKey: [
|
|
716
|
+
queryKey: ["mq2"],
|
|
717
717
|
queryFn: () => d2.promise,
|
|
718
718
|
}))
|
|
719
719
|
return (
|
|
@@ -729,13 +729,13 @@ describe('useSuspenseQuery + QuerySuspense', () => {
|
|
|
729
729
|
el,
|
|
730
730
|
)
|
|
731
731
|
|
|
732
|
-
d1.resolve(
|
|
732
|
+
d1.resolve("first")
|
|
733
733
|
await d1.promise
|
|
734
734
|
await new Promise((r) => setTimeout(r, 10))
|
|
735
735
|
// q2 still pending — children should not render
|
|
736
736
|
expect(childrenRendered).toBe(false)
|
|
737
737
|
|
|
738
|
-
d2.resolve(
|
|
738
|
+
d2.resolve("second")
|
|
739
739
|
await d2.promise
|
|
740
740
|
await new Promise((r) => setTimeout(r, 10))
|
|
741
741
|
expect(childrenRendered).toBe(true)
|
|
@@ -746,14 +746,14 @@ describe('useSuspenseQuery + QuerySuspense', () => {
|
|
|
746
746
|
|
|
747
747
|
// ─── QueryErrorResetBoundary / useQueryErrorResetBoundary ─────────────────────
|
|
748
748
|
|
|
749
|
-
describe(
|
|
750
|
-
it(
|
|
749
|
+
describe("QueryErrorResetBoundary", () => {
|
|
750
|
+
it("reset() re-triggers fetch for errored queries", async () => {
|
|
751
751
|
const client = makeClient()
|
|
752
752
|
let callCount = 0
|
|
753
753
|
let shouldFail = true
|
|
754
754
|
let resetFn: (() => void) | undefined
|
|
755
755
|
|
|
756
|
-
const el = document.createElement(
|
|
756
|
+
const el = document.createElement("div")
|
|
757
757
|
document.body.appendChild(el)
|
|
758
758
|
const unmount = mount(
|
|
759
759
|
<QueryClientProvider client={client}>
|
|
@@ -762,11 +762,11 @@ describe('QueryErrorResetBoundary', () => {
|
|
|
762
762
|
const { reset } = useQueryErrorResetBoundary()
|
|
763
763
|
resetFn = reset
|
|
764
764
|
useQuery(() => ({
|
|
765
|
-
queryKey: [
|
|
765
|
+
queryKey: ["reset-test"],
|
|
766
766
|
queryFn: async () => {
|
|
767
767
|
callCount++
|
|
768
|
-
if (shouldFail) throw new Error(
|
|
769
|
-
return
|
|
768
|
+
if (shouldFail) throw new Error("fail")
|
|
769
|
+
return "ok"
|
|
770
770
|
},
|
|
771
771
|
}))
|
|
772
772
|
return null
|
|
@@ -787,11 +787,11 @@ describe('QueryErrorResetBoundary', () => {
|
|
|
787
787
|
el.remove()
|
|
788
788
|
})
|
|
789
789
|
|
|
790
|
-
it(
|
|
790
|
+
it("useQueryErrorResetBoundary works without explicit boundary", () => {
|
|
791
791
|
const client = makeClient()
|
|
792
792
|
let reset: (() => void) | undefined
|
|
793
793
|
|
|
794
|
-
const el = document.createElement(
|
|
794
|
+
const el = document.createElement("div")
|
|
795
795
|
document.body.appendChild(el)
|
|
796
796
|
const unmount = mount(
|
|
797
797
|
<QueryClientProvider client={client}>
|
|
@@ -813,21 +813,21 @@ describe('QueryErrorResetBoundary', () => {
|
|
|
813
813
|
|
|
814
814
|
// ─── useInfiniteQuery ─────────────────────────────────────────────────────────
|
|
815
815
|
|
|
816
|
-
describe(
|
|
816
|
+
describe("useInfiniteQuery", () => {
|
|
817
817
|
let client: QueryClient
|
|
818
818
|
beforeEach(() => {
|
|
819
819
|
client = makeClient()
|
|
820
820
|
})
|
|
821
821
|
|
|
822
|
-
it(
|
|
822
|
+
it("starts in pending state", () => {
|
|
823
823
|
let query: ReturnType<typeof useInfiniteQuery> | undefined
|
|
824
|
-
const el = document.createElement(
|
|
824
|
+
const el = document.createElement("div")
|
|
825
825
|
document.body.appendChild(el)
|
|
826
826
|
const unmount = mount(
|
|
827
827
|
<QueryClientProvider client={client}>
|
|
828
828
|
{() => {
|
|
829
829
|
query = useInfiniteQuery(() => ({
|
|
830
|
-
queryKey: [
|
|
830
|
+
queryKey: ["inf-pending"],
|
|
831
831
|
queryFn: () =>
|
|
832
832
|
new Promise(() => {
|
|
833
833
|
/* never resolves */
|
|
@@ -843,7 +843,7 @@ describe('useInfiniteQuery', () => {
|
|
|
843
843
|
expect(query!.isPending()).toBe(true)
|
|
844
844
|
expect(query!.isLoading()).toBe(true)
|
|
845
845
|
expect(query!.data()).toBeUndefined()
|
|
846
|
-
expect(query!.status()).toBe(
|
|
846
|
+
expect(query!.status()).toBe("pending")
|
|
847
847
|
expect(query!.isSuccess()).toBe(false)
|
|
848
848
|
expect(query!.isError()).toBe(false)
|
|
849
849
|
expect(query!.error()).toBeNull()
|
|
@@ -855,23 +855,19 @@ describe('useInfiniteQuery', () => {
|
|
|
855
855
|
el.remove()
|
|
856
856
|
})
|
|
857
857
|
|
|
858
|
-
it(
|
|
858
|
+
it("resolves to success with pages data", async () => {
|
|
859
859
|
let query: ReturnType<typeof useInfiniteQuery<string>> | undefined
|
|
860
|
-
const el = document.createElement(
|
|
860
|
+
const el = document.createElement("div")
|
|
861
861
|
document.body.appendChild(el)
|
|
862
862
|
const unmount = mount(
|
|
863
863
|
<QueryClientProvider client={client}>
|
|
864
864
|
{() => {
|
|
865
865
|
query = useInfiniteQuery(() => ({
|
|
866
|
-
queryKey: [
|
|
867
|
-
queryFn: ({ pageParam }: { pageParam: number }) =>
|
|
868
|
-
Promise.resolve(`page-${pageParam}`),
|
|
866
|
+
queryKey: ["inf-success"],
|
|
867
|
+
queryFn: ({ pageParam }: { pageParam: number }) => Promise.resolve(`page-${pageParam}`),
|
|
869
868
|
initialPageParam: 0,
|
|
870
|
-
getNextPageParam: (
|
|
871
|
-
|
|
872
|
-
_all: string[],
|
|
873
|
-
lastParam: number,
|
|
874
|
-
) => (lastParam < 2 ? lastParam + 1 : undefined),
|
|
869
|
+
getNextPageParam: (_last: string, _all: string[], lastParam: number) =>
|
|
870
|
+
lastParam < 2 ? lastParam + 1 : undefined,
|
|
875
871
|
}))
|
|
876
872
|
return null
|
|
877
873
|
}}
|
|
@@ -881,8 +877,8 @@ describe('useInfiniteQuery', () => {
|
|
|
881
877
|
|
|
882
878
|
await new Promise((r) => setTimeout(r, 20))
|
|
883
879
|
expect(query!.isSuccess()).toBe(true)
|
|
884
|
-
expect(query!.status()).toBe(
|
|
885
|
-
expect(query!.data()?.pages).toEqual([
|
|
880
|
+
expect(query!.status()).toBe("success")
|
|
881
|
+
expect(query!.data()?.pages).toEqual(["page-0"])
|
|
886
882
|
expect(query!.hasNextPage()).toBe(true)
|
|
887
883
|
expect(query!.isPending()).toBe(false)
|
|
888
884
|
expect(query!.isFetching()).toBe(false)
|
|
@@ -890,23 +886,19 @@ describe('useInfiniteQuery', () => {
|
|
|
890
886
|
el.remove()
|
|
891
887
|
})
|
|
892
888
|
|
|
893
|
-
it(
|
|
889
|
+
it("fetchNextPage loads the next page", async () => {
|
|
894
890
|
let query: ReturnType<typeof useInfiniteQuery<string>> | undefined
|
|
895
|
-
const el = document.createElement(
|
|
891
|
+
const el = document.createElement("div")
|
|
896
892
|
document.body.appendChild(el)
|
|
897
893
|
const unmount = mount(
|
|
898
894
|
<QueryClientProvider client={client}>
|
|
899
895
|
{() => {
|
|
900
896
|
query = useInfiniteQuery(() => ({
|
|
901
|
-
queryKey: [
|
|
902
|
-
queryFn: ({ pageParam }: { pageParam: number }) =>
|
|
903
|
-
Promise.resolve(`page-${pageParam}`),
|
|
897
|
+
queryKey: ["inf-next"],
|
|
898
|
+
queryFn: ({ pageParam }: { pageParam: number }) => Promise.resolve(`page-${pageParam}`),
|
|
904
899
|
initialPageParam: 0,
|
|
905
|
-
getNextPageParam: (
|
|
906
|
-
|
|
907
|
-
_all: string[],
|
|
908
|
-
lastParam: number,
|
|
909
|
-
) => (lastParam < 2 ? lastParam + 1 : undefined),
|
|
900
|
+
getNextPageParam: (_last: string, _all: string[], lastParam: number) =>
|
|
901
|
+
lastParam < 2 ? lastParam + 1 : undefined,
|
|
910
902
|
}))
|
|
911
903
|
return null
|
|
912
904
|
}}
|
|
@@ -915,39 +907,35 @@ describe('useInfiniteQuery', () => {
|
|
|
915
907
|
)
|
|
916
908
|
|
|
917
909
|
await new Promise((r) => setTimeout(r, 20))
|
|
918
|
-
expect(query!.data()?.pages).toEqual([
|
|
910
|
+
expect(query!.data()?.pages).toEqual(["page-0"])
|
|
919
911
|
|
|
920
912
|
await query!.fetchNextPage()
|
|
921
913
|
await new Promise((r) => setTimeout(r, 20))
|
|
922
|
-
expect(query!.data()?.pages).toEqual([
|
|
914
|
+
expect(query!.data()?.pages).toEqual(["page-0", "page-1"])
|
|
923
915
|
expect(query!.hasNextPage()).toBe(true)
|
|
924
916
|
|
|
925
917
|
await query!.fetchNextPage()
|
|
926
918
|
await new Promise((r) => setTimeout(r, 20))
|
|
927
|
-
expect(query!.data()?.pages).toEqual([
|
|
919
|
+
expect(query!.data()?.pages).toEqual(["page-0", "page-1", "page-2"])
|
|
928
920
|
expect(query!.hasNextPage()).toBe(false)
|
|
929
921
|
unmount()
|
|
930
922
|
el.remove()
|
|
931
923
|
})
|
|
932
924
|
|
|
933
|
-
it(
|
|
925
|
+
it("fetchPreviousPage loads the previous page", async () => {
|
|
934
926
|
let query: ReturnType<typeof useInfiniteQuery<string>> | undefined
|
|
935
|
-
const el = document.createElement(
|
|
927
|
+
const el = document.createElement("div")
|
|
936
928
|
document.body.appendChild(el)
|
|
937
929
|
const unmount = mount(
|
|
938
930
|
<QueryClientProvider client={client}>
|
|
939
931
|
{() => {
|
|
940
932
|
query = useInfiniteQuery(() => ({
|
|
941
|
-
queryKey: [
|
|
942
|
-
queryFn: ({ pageParam }: { pageParam: number }) =>
|
|
943
|
-
Promise.resolve(`page-${pageParam}`),
|
|
933
|
+
queryKey: ["inf-prev"],
|
|
934
|
+
queryFn: ({ pageParam }: { pageParam: number }) => Promise.resolve(`page-${pageParam}`),
|
|
944
935
|
initialPageParam: 5,
|
|
945
936
|
getNextPageParam: () => undefined,
|
|
946
|
-
getPreviousPageParam: (
|
|
947
|
-
|
|
948
|
-
_all: string[],
|
|
949
|
-
firstParam: number,
|
|
950
|
-
) => (firstParam > 3 ? firstParam - 1 : undefined),
|
|
937
|
+
getPreviousPageParam: (_first: string, _all: string[], firstParam: number) =>
|
|
938
|
+
firstParam > 3 ? firstParam - 1 : undefined,
|
|
951
939
|
}))
|
|
952
940
|
return null
|
|
953
941
|
}}
|
|
@@ -960,21 +948,21 @@ describe('useInfiniteQuery', () => {
|
|
|
960
948
|
|
|
961
949
|
await query!.fetchPreviousPage()
|
|
962
950
|
await new Promise((r) => setTimeout(r, 20))
|
|
963
|
-
expect(query!.data()?.pages).toContain(
|
|
951
|
+
expect(query!.data()?.pages).toContain("page-4")
|
|
964
952
|
unmount()
|
|
965
953
|
el.remove()
|
|
966
954
|
})
|
|
967
955
|
|
|
968
|
-
it(
|
|
956
|
+
it("captures error state", async () => {
|
|
969
957
|
let query: ReturnType<typeof useInfiniteQuery> | undefined
|
|
970
|
-
const el = document.createElement(
|
|
958
|
+
const el = document.createElement("div")
|
|
971
959
|
document.body.appendChild(el)
|
|
972
960
|
const unmount = mount(
|
|
973
961
|
<QueryClientProvider client={client}>
|
|
974
962
|
{() => {
|
|
975
963
|
query = useInfiniteQuery(() => ({
|
|
976
|
-
queryKey: [
|
|
977
|
-
queryFn: () => Promise.reject(new Error(
|
|
964
|
+
queryKey: ["inf-error"],
|
|
965
|
+
queryFn: () => Promise.reject(new Error("inf failed")),
|
|
978
966
|
initialPageParam: 0,
|
|
979
967
|
getNextPageParam: () => undefined,
|
|
980
968
|
}))
|
|
@@ -986,25 +974,25 @@ describe('useInfiniteQuery', () => {
|
|
|
986
974
|
|
|
987
975
|
await new Promise((r) => setTimeout(r, 20))
|
|
988
976
|
expect(query!.isError()).toBe(true)
|
|
989
|
-
expect(query!.status()).toBe(
|
|
990
|
-
expect((query!.error() as Error).message).toBe(
|
|
977
|
+
expect(query!.status()).toBe("error")
|
|
978
|
+
expect((query!.error() as Error).message).toBe("inf failed")
|
|
991
979
|
unmount()
|
|
992
980
|
el.remove()
|
|
993
981
|
})
|
|
994
982
|
|
|
995
|
-
it(
|
|
983
|
+
it("refetch re-fetches the query", async () => {
|
|
996
984
|
let callCount = 0
|
|
997
985
|
let query: ReturnType<typeof useInfiniteQuery<string>> | undefined
|
|
998
|
-
const el = document.createElement(
|
|
986
|
+
const el = document.createElement("div")
|
|
999
987
|
document.body.appendChild(el)
|
|
1000
988
|
const unmount = mount(
|
|
1001
989
|
<QueryClientProvider client={client}>
|
|
1002
990
|
{() => {
|
|
1003
991
|
query = useInfiniteQuery(() => ({
|
|
1004
|
-
queryKey: [
|
|
992
|
+
queryKey: ["inf-refetch"],
|
|
1005
993
|
queryFn: () => {
|
|
1006
994
|
callCount++
|
|
1007
|
-
return Promise.resolve(
|
|
995
|
+
return Promise.resolve("data")
|
|
1008
996
|
},
|
|
1009
997
|
initialPageParam: 0,
|
|
1010
998
|
getNextPageParam: () => undefined,
|
|
@@ -1024,16 +1012,16 @@ describe('useInfiniteQuery', () => {
|
|
|
1024
1012
|
el.remove()
|
|
1025
1013
|
})
|
|
1026
1014
|
|
|
1027
|
-
it(
|
|
1015
|
+
it("result signal contains full observer result", async () => {
|
|
1028
1016
|
let query: ReturnType<typeof useInfiniteQuery<string>> | undefined
|
|
1029
|
-
const el = document.createElement(
|
|
1017
|
+
const el = document.createElement("div")
|
|
1030
1018
|
document.body.appendChild(el)
|
|
1031
1019
|
const unmount = mount(
|
|
1032
1020
|
<QueryClientProvider client={client}>
|
|
1033
1021
|
{() => {
|
|
1034
1022
|
query = useInfiniteQuery(() => ({
|
|
1035
|
-
queryKey: [
|
|
1036
|
-
queryFn: () => Promise.resolve(
|
|
1023
|
+
queryKey: ["inf-result"],
|
|
1024
|
+
queryFn: () => Promise.resolve("val"),
|
|
1037
1025
|
initialPageParam: 0,
|
|
1038
1026
|
getNextPageParam: () => undefined,
|
|
1039
1027
|
}))
|
|
@@ -1045,22 +1033,22 @@ describe('useInfiniteQuery', () => {
|
|
|
1045
1033
|
|
|
1046
1034
|
await new Promise((resolve) => setTimeout(resolve, 20))
|
|
1047
1035
|
const r = query!.result()
|
|
1048
|
-
expect(r.status).toBe(
|
|
1049
|
-
expect(r.data?.pages).toEqual([
|
|
1036
|
+
expect(r.status).toBe("success")
|
|
1037
|
+
expect(r.data?.pages).toEqual(["val"])
|
|
1050
1038
|
unmount()
|
|
1051
1039
|
el.remove()
|
|
1052
1040
|
})
|
|
1053
1041
|
|
|
1054
|
-
it(
|
|
1055
|
-
const key = signal(
|
|
1042
|
+
it("reactive options update observer", async () => {
|
|
1043
|
+
const key = signal("a")
|
|
1056
1044
|
let query: ReturnType<typeof useInfiniteQuery<string>> | undefined
|
|
1057
|
-
const el = document.createElement(
|
|
1045
|
+
const el = document.createElement("div")
|
|
1058
1046
|
document.body.appendChild(el)
|
|
1059
1047
|
const unmount = mount(
|
|
1060
1048
|
<QueryClientProvider client={client}>
|
|
1061
1049
|
{() => {
|
|
1062
1050
|
query = useInfiniteQuery(() => ({
|
|
1063
|
-
queryKey: [
|
|
1051
|
+
queryKey: ["inf-reactive", key()],
|
|
1064
1052
|
queryFn: () => Promise.resolve(`data-${key()}`),
|
|
1065
1053
|
initialPageParam: 0,
|
|
1066
1054
|
getNextPageParam: () => undefined,
|
|
@@ -1072,11 +1060,11 @@ describe('useInfiniteQuery', () => {
|
|
|
1072
1060
|
)
|
|
1073
1061
|
|
|
1074
1062
|
await new Promise((r) => setTimeout(r, 20))
|
|
1075
|
-
expect(query!.data()?.pages).toEqual([
|
|
1063
|
+
expect(query!.data()?.pages).toEqual(["data-a"])
|
|
1076
1064
|
|
|
1077
|
-
key.set(
|
|
1065
|
+
key.set("b")
|
|
1078
1066
|
await new Promise((r) => setTimeout(r, 20))
|
|
1079
|
-
expect(query!.data()?.pages).toEqual([
|
|
1067
|
+
expect(query!.data()?.pages).toEqual(["data-b"])
|
|
1080
1068
|
unmount()
|
|
1081
1069
|
el.remove()
|
|
1082
1070
|
})
|
|
@@ -1084,23 +1072,22 @@ describe('useInfiniteQuery', () => {
|
|
|
1084
1072
|
|
|
1085
1073
|
// ─── useSuspenseInfiniteQuery ────────────────────────────────────────────────
|
|
1086
1074
|
|
|
1087
|
-
describe(
|
|
1075
|
+
describe("useSuspenseInfiniteQuery", () => {
|
|
1088
1076
|
let client: QueryClient
|
|
1089
1077
|
beforeEach(() => {
|
|
1090
1078
|
client = makeClient()
|
|
1091
1079
|
})
|
|
1092
1080
|
|
|
1093
|
-
it(
|
|
1081
|
+
it("returns all fine-grained signals and resolves to success", async () => {
|
|
1094
1082
|
let query: ReturnType<typeof useSuspenseInfiniteQuery<string>> | undefined
|
|
1095
|
-
const el = document.createElement(
|
|
1083
|
+
const el = document.createElement("div")
|
|
1096
1084
|
document.body.appendChild(el)
|
|
1097
1085
|
const unmount = mount(
|
|
1098
1086
|
<QueryClientProvider client={client}>
|
|
1099
1087
|
{() => {
|
|
1100
1088
|
query = useSuspenseInfiniteQuery(() => ({
|
|
1101
|
-
queryKey: [
|
|
1102
|
-
queryFn: ({ pageParam }: { pageParam: number }) =>
|
|
1103
|
-
Promise.resolve(`p${pageParam}`),
|
|
1089
|
+
queryKey: ["sinf-1"],
|
|
1090
|
+
queryFn: ({ pageParam }: { pageParam: number }) => Promise.resolve(`p${pageParam}`),
|
|
1104
1091
|
initialPageParam: 0,
|
|
1105
1092
|
getNextPageParam: (_l: string, _a: string[], lp: number) =>
|
|
1106
1093
|
lp < 1 ? lp + 1 : undefined,
|
|
@@ -1113,8 +1100,8 @@ describe('useSuspenseInfiniteQuery', () => {
|
|
|
1113
1100
|
|
|
1114
1101
|
await new Promise((r) => setTimeout(r, 20))
|
|
1115
1102
|
expect(query!.isSuccess()).toBe(true)
|
|
1116
|
-
expect(query!.status()).toBe(
|
|
1117
|
-
expect(query!.data()?.pages).toEqual([
|
|
1103
|
+
expect(query!.status()).toBe("success")
|
|
1104
|
+
expect(query!.data()?.pages).toEqual(["p0"])
|
|
1118
1105
|
expect(query!.error()).toBeNull()
|
|
1119
1106
|
expect(query!.isError()).toBe(false)
|
|
1120
1107
|
expect(query!.isFetching()).toBe(false)
|
|
@@ -1126,17 +1113,16 @@ describe('useSuspenseInfiniteQuery', () => {
|
|
|
1126
1113
|
el.remove()
|
|
1127
1114
|
})
|
|
1128
1115
|
|
|
1129
|
-
it(
|
|
1116
|
+
it("fetchNextPage and fetchPreviousPage work", async () => {
|
|
1130
1117
|
let query: ReturnType<typeof useSuspenseInfiniteQuery<string>> | undefined
|
|
1131
|
-
const el = document.createElement(
|
|
1118
|
+
const el = document.createElement("div")
|
|
1132
1119
|
document.body.appendChild(el)
|
|
1133
1120
|
const unmount = mount(
|
|
1134
1121
|
<QueryClientProvider client={client}>
|
|
1135
1122
|
{() => {
|
|
1136
1123
|
query = useSuspenseInfiniteQuery(() => ({
|
|
1137
|
-
queryKey: [
|
|
1138
|
-
queryFn: ({ pageParam }: { pageParam: number }) =>
|
|
1139
|
-
Promise.resolve(`p${pageParam}`),
|
|
1124
|
+
queryKey: ["sinf-pages"],
|
|
1125
|
+
queryFn: ({ pageParam }: { pageParam: number }) => Promise.resolve(`p${pageParam}`),
|
|
1140
1126
|
initialPageParam: 1,
|
|
1141
1127
|
getNextPageParam: (_l: string, _a: string[], lp: number) =>
|
|
1142
1128
|
lp < 3 ? lp + 1 : undefined,
|
|
@@ -1152,28 +1138,28 @@ describe('useSuspenseInfiniteQuery', () => {
|
|
|
1152
1138
|
await new Promise((r) => setTimeout(r, 20))
|
|
1153
1139
|
await query!.fetchNextPage()
|
|
1154
1140
|
await new Promise((r) => setTimeout(r, 20))
|
|
1155
|
-
expect(query!.data()?.pages).toContain(
|
|
1141
|
+
expect(query!.data()?.pages).toContain("p2")
|
|
1156
1142
|
|
|
1157
1143
|
await query!.fetchPreviousPage()
|
|
1158
1144
|
await new Promise((r) => setTimeout(r, 20))
|
|
1159
|
-
expect(query!.data()?.pages).toContain(
|
|
1145
|
+
expect(query!.data()?.pages).toContain("p0")
|
|
1160
1146
|
unmount()
|
|
1161
1147
|
el.remove()
|
|
1162
1148
|
})
|
|
1163
1149
|
|
|
1164
|
-
it(
|
|
1150
|
+
it("refetch works", async () => {
|
|
1165
1151
|
let callCount = 0
|
|
1166
1152
|
let query: ReturnType<typeof useSuspenseInfiniteQuery<string>> | undefined
|
|
1167
|
-
const el = document.createElement(
|
|
1153
|
+
const el = document.createElement("div")
|
|
1168
1154
|
document.body.appendChild(el)
|
|
1169
1155
|
const unmount = mount(
|
|
1170
1156
|
<QueryClientProvider client={client}>
|
|
1171
1157
|
{() => {
|
|
1172
1158
|
query = useSuspenseInfiniteQuery(() => ({
|
|
1173
|
-
queryKey: [
|
|
1159
|
+
queryKey: ["sinf-refetch"],
|
|
1174
1160
|
queryFn: () => {
|
|
1175
1161
|
callCount++
|
|
1176
|
-
return Promise.resolve(
|
|
1162
|
+
return Promise.resolve("d")
|
|
1177
1163
|
},
|
|
1178
1164
|
initialPageParam: 0,
|
|
1179
1165
|
getNextPageParam: () => undefined,
|
|
@@ -1193,16 +1179,16 @@ describe('useSuspenseInfiniteQuery', () => {
|
|
|
1193
1179
|
el.remove()
|
|
1194
1180
|
})
|
|
1195
1181
|
|
|
1196
|
-
it(
|
|
1182
|
+
it("result signal contains full observer result", async () => {
|
|
1197
1183
|
let query: ReturnType<typeof useSuspenseInfiniteQuery<string>> | undefined
|
|
1198
|
-
const el = document.createElement(
|
|
1184
|
+
const el = document.createElement("div")
|
|
1199
1185
|
document.body.appendChild(el)
|
|
1200
1186
|
const unmount = mount(
|
|
1201
1187
|
<QueryClientProvider client={client}>
|
|
1202
1188
|
{() => {
|
|
1203
1189
|
query = useSuspenseInfiniteQuery(() => ({
|
|
1204
|
-
queryKey: [
|
|
1205
|
-
queryFn: () => Promise.resolve(
|
|
1190
|
+
queryKey: ["sinf-result"],
|
|
1191
|
+
queryFn: () => Promise.resolve("v"),
|
|
1206
1192
|
initialPageParam: 0,
|
|
1207
1193
|
getNextPageParam: () => undefined,
|
|
1208
1194
|
}))
|
|
@@ -1213,21 +1199,21 @@ describe('useSuspenseInfiniteQuery', () => {
|
|
|
1213
1199
|
)
|
|
1214
1200
|
|
|
1215
1201
|
await new Promise((r) => setTimeout(r, 20))
|
|
1216
|
-
expect(query!.result().status).toBe(
|
|
1202
|
+
expect(query!.result().status).toBe("success")
|
|
1217
1203
|
unmount()
|
|
1218
1204
|
el.remove()
|
|
1219
1205
|
})
|
|
1220
1206
|
|
|
1221
|
-
it(
|
|
1222
|
-
const key = signal(
|
|
1207
|
+
it("reactive options update observer", async () => {
|
|
1208
|
+
const key = signal("x")
|
|
1223
1209
|
let query: ReturnType<typeof useSuspenseInfiniteQuery<string>> | undefined
|
|
1224
|
-
const el = document.createElement(
|
|
1210
|
+
const el = document.createElement("div")
|
|
1225
1211
|
document.body.appendChild(el)
|
|
1226
1212
|
const unmount = mount(
|
|
1227
1213
|
<QueryClientProvider client={client}>
|
|
1228
1214
|
{() => {
|
|
1229
1215
|
query = useSuspenseInfiniteQuery(() => ({
|
|
1230
|
-
queryKey: [
|
|
1216
|
+
queryKey: ["sinf-reactive", key()],
|
|
1231
1217
|
queryFn: () => Promise.resolve(`val-${key()}`),
|
|
1232
1218
|
initialPageParam: 0,
|
|
1233
1219
|
getNextPageParam: () => undefined,
|
|
@@ -1239,10 +1225,10 @@ describe('useSuspenseInfiniteQuery', () => {
|
|
|
1239
1225
|
)
|
|
1240
1226
|
|
|
1241
1227
|
await new Promise((r) => setTimeout(r, 20))
|
|
1242
|
-
expect(query!.data()?.pages).toEqual([
|
|
1243
|
-
key.set(
|
|
1228
|
+
expect(query!.data()?.pages).toEqual(["val-x"])
|
|
1229
|
+
key.set("y")
|
|
1244
1230
|
await new Promise((r) => setTimeout(r, 20))
|
|
1245
|
-
expect(query!.data()?.pages).toEqual([
|
|
1231
|
+
expect(query!.data()?.pages).toEqual(["val-y"])
|
|
1246
1232
|
unmount()
|
|
1247
1233
|
el.remove()
|
|
1248
1234
|
})
|
|
@@ -1250,22 +1236,22 @@ describe('useSuspenseInfiniteQuery', () => {
|
|
|
1250
1236
|
|
|
1251
1237
|
// ─── useSuspenseQuery — additional coverage ──────────────────────────────────
|
|
1252
1238
|
|
|
1253
|
-
describe(
|
|
1239
|
+
describe("useSuspenseQuery — additional", () => {
|
|
1254
1240
|
let client: QueryClient
|
|
1255
1241
|
beforeEach(() => {
|
|
1256
1242
|
client = makeClient()
|
|
1257
1243
|
})
|
|
1258
1244
|
|
|
1259
|
-
it(
|
|
1245
|
+
it("data is typed as TData (never undefined) after success", async () => {
|
|
1260
1246
|
let query: ReturnType<typeof useSuspenseQuery<{ name: string }>> | undefined
|
|
1261
|
-
const el = document.createElement(
|
|
1247
|
+
const el = document.createElement("div")
|
|
1262
1248
|
document.body.appendChild(el)
|
|
1263
1249
|
const unmount = mount(
|
|
1264
1250
|
<QueryClientProvider client={client}>
|
|
1265
1251
|
{() => {
|
|
1266
1252
|
query = useSuspenseQuery(() => ({
|
|
1267
|
-
queryKey: [
|
|
1268
|
-
queryFn: () => Promise.resolve({ name:
|
|
1253
|
+
queryKey: ["sq-data-type"],
|
|
1254
|
+
queryFn: () => Promise.resolve({ name: "test" }),
|
|
1269
1255
|
}))
|
|
1270
1256
|
return null
|
|
1271
1257
|
}}
|
|
@@ -1274,30 +1260,30 @@ describe('useSuspenseQuery — additional', () => {
|
|
|
1274
1260
|
)
|
|
1275
1261
|
|
|
1276
1262
|
await new Promise((r) => setTimeout(r, 20))
|
|
1277
|
-
expect(query!.data().name).toBe(
|
|
1263
|
+
expect(query!.data().name).toBe("test")
|
|
1278
1264
|
expect(query!.isSuccess()).toBe(true)
|
|
1279
1265
|
expect(query!.isFetching()).toBe(false)
|
|
1280
1266
|
expect(query!.isError()).toBe(false)
|
|
1281
1267
|
expect(query!.error()).toBeNull()
|
|
1282
|
-
expect(query!.status()).toBe(
|
|
1283
|
-
expect(query!.result().status).toBe(
|
|
1268
|
+
expect(query!.status()).toBe("success")
|
|
1269
|
+
expect(query!.result().status).toBe("success")
|
|
1284
1270
|
unmount()
|
|
1285
1271
|
el.remove()
|
|
1286
1272
|
})
|
|
1287
1273
|
|
|
1288
|
-
it(
|
|
1274
|
+
it("refetch re-fetches the query", async () => {
|
|
1289
1275
|
let callCount = 0
|
|
1290
1276
|
let query: ReturnType<typeof useSuspenseQuery<string>> | undefined
|
|
1291
|
-
const el = document.createElement(
|
|
1277
|
+
const el = document.createElement("div")
|
|
1292
1278
|
document.body.appendChild(el)
|
|
1293
1279
|
const unmount = mount(
|
|
1294
1280
|
<QueryClientProvider client={client}>
|
|
1295
1281
|
{() => {
|
|
1296
1282
|
query = useSuspenseQuery(() => ({
|
|
1297
|
-
queryKey: [
|
|
1283
|
+
queryKey: ["sq-refetch"],
|
|
1298
1284
|
queryFn: () => {
|
|
1299
1285
|
callCount++
|
|
1300
|
-
return Promise.resolve(
|
|
1286
|
+
return Promise.resolve("ok")
|
|
1301
1287
|
},
|
|
1302
1288
|
}))
|
|
1303
1289
|
return null
|
|
@@ -1315,16 +1301,16 @@ describe('useSuspenseQuery — additional', () => {
|
|
|
1315
1301
|
el.remove()
|
|
1316
1302
|
})
|
|
1317
1303
|
|
|
1318
|
-
it(
|
|
1319
|
-
const key = signal(
|
|
1304
|
+
it("reactive key changes trigger re-fetch", async () => {
|
|
1305
|
+
const key = signal("k1")
|
|
1320
1306
|
let query: ReturnType<typeof useSuspenseQuery<string>> | undefined
|
|
1321
|
-
const el = document.createElement(
|
|
1307
|
+
const el = document.createElement("div")
|
|
1322
1308
|
document.body.appendChild(el)
|
|
1323
1309
|
const unmount = mount(
|
|
1324
1310
|
<QueryClientProvider client={client}>
|
|
1325
1311
|
{() => {
|
|
1326
1312
|
query = useSuspenseQuery(() => ({
|
|
1327
|
-
queryKey: [
|
|
1313
|
+
queryKey: ["sq-reactive", key()],
|
|
1328
1314
|
queryFn: () => Promise.resolve(`data-${key()}`),
|
|
1329
1315
|
}))
|
|
1330
1316
|
return null
|
|
@@ -1334,19 +1320,19 @@ describe('useSuspenseQuery — additional', () => {
|
|
|
1334
1320
|
)
|
|
1335
1321
|
|
|
1336
1322
|
await new Promise((r) => setTimeout(r, 20))
|
|
1337
|
-
expect(query!.data()).toBe(
|
|
1323
|
+
expect(query!.data()).toBe("data-k1")
|
|
1338
1324
|
|
|
1339
|
-
key.set(
|
|
1325
|
+
key.set("k2")
|
|
1340
1326
|
await new Promise((r) => setTimeout(r, 20))
|
|
1341
|
-
expect(query!.data()).toBe(
|
|
1327
|
+
expect(query!.data()).toBe("data-k2")
|
|
1342
1328
|
unmount()
|
|
1343
1329
|
el.remove()
|
|
1344
1330
|
})
|
|
1345
1331
|
|
|
1346
|
-
it(
|
|
1332
|
+
it("captures error state in suspense query", async () => {
|
|
1347
1333
|
const { promise, reject } = deferred<never>()
|
|
1348
1334
|
|
|
1349
|
-
const el = document.createElement(
|
|
1335
|
+
const el = document.createElement("div")
|
|
1350
1336
|
document.body.appendChild(el)
|
|
1351
1337
|
|
|
1352
1338
|
let query: ReturnType<typeof useSuspenseQuery> | undefined
|
|
@@ -1354,7 +1340,7 @@ describe('useSuspenseQuery — additional', () => {
|
|
|
1354
1340
|
<QueryClientProvider client={client}>
|
|
1355
1341
|
{() => {
|
|
1356
1342
|
query = useSuspenseQuery(() => ({
|
|
1357
|
-
queryKey: [
|
|
1343
|
+
queryKey: ["sq-rethrow2"],
|
|
1358
1344
|
queryFn: () => promise,
|
|
1359
1345
|
}))
|
|
1360
1346
|
return null
|
|
@@ -1363,7 +1349,7 @@ describe('useSuspenseQuery — additional', () => {
|
|
|
1363
1349
|
el,
|
|
1364
1350
|
)
|
|
1365
1351
|
|
|
1366
|
-
reject(new Error(
|
|
1352
|
+
reject(new Error("rethrow test"))
|
|
1367
1353
|
await promise.catch(() => {
|
|
1368
1354
|
/* expected */
|
|
1369
1355
|
})
|
|
@@ -1374,22 +1360,22 @@ describe('useSuspenseQuery — additional', () => {
|
|
|
1374
1360
|
el.remove()
|
|
1375
1361
|
})
|
|
1376
1362
|
|
|
1377
|
-
it(
|
|
1363
|
+
it("QuerySuspense handles fallback as function", async () => {
|
|
1378
1364
|
let query: ReturnType<typeof useSuspenseQuery<string>> | undefined
|
|
1379
|
-
const el = document.createElement(
|
|
1365
|
+
const el = document.createElement("div")
|
|
1380
1366
|
document.body.appendChild(el)
|
|
1381
1367
|
const unmount = mount(
|
|
1382
1368
|
<QueryClientProvider client={client}>
|
|
1383
1369
|
{() => {
|
|
1384
1370
|
query = useSuspenseQuery(() => ({
|
|
1385
|
-
queryKey: [
|
|
1371
|
+
queryKey: ["sq-fn-fallback"],
|
|
1386
1372
|
queryFn: () =>
|
|
1387
1373
|
new Promise(() => {
|
|
1388
1374
|
/* never resolves */
|
|
1389
1375
|
}),
|
|
1390
1376
|
}))
|
|
1391
1377
|
return (
|
|
1392
|
-
<QuerySuspense query={query!} fallback={() =>
|
|
1378
|
+
<QuerySuspense query={query!} fallback={() => "loading fn"}>
|
|
1393
1379
|
{() => null}
|
|
1394
1380
|
</QuerySuspense>
|
|
1395
1381
|
)
|
|
@@ -1408,11 +1394,11 @@ describe('useSuspenseQuery — additional', () => {
|
|
|
1408
1394
|
|
|
1409
1395
|
// ─── Coverage gap tests ──────────────────────────────────────────────────────
|
|
1410
1396
|
|
|
1411
|
-
describe(
|
|
1412
|
-
it(
|
|
1397
|
+
describe("QueryClientProvider — VNode children branch", () => {
|
|
1398
|
+
it("renders when children is a VNode (not a function)", () => {
|
|
1413
1399
|
const client = makeClient()
|
|
1414
1400
|
let received: QueryClient | null = null
|
|
1415
|
-
const el = document.createElement(
|
|
1401
|
+
const el = document.createElement("div")
|
|
1416
1402
|
document.body.appendChild(el)
|
|
1417
1403
|
// Pass children as a direct VNode, not wrapped in a function
|
|
1418
1404
|
const unmount = mount(
|
|
@@ -1429,10 +1415,10 @@ describe('QueryClientProvider — VNode children branch', () => {
|
|
|
1429
1415
|
el.remove()
|
|
1430
1416
|
})
|
|
1431
1417
|
|
|
1432
|
-
it(
|
|
1418
|
+
it("renders when children is passed as a function returning VNode", () => {
|
|
1433
1419
|
const client = makeClient()
|
|
1434
1420
|
let received: QueryClient | null = null
|
|
1435
|
-
const el = document.createElement(
|
|
1421
|
+
const el = document.createElement("div")
|
|
1436
1422
|
document.body.appendChild(el)
|
|
1437
1423
|
const unmount = mount(
|
|
1438
1424
|
<QueryClientProvider client={client}>
|
|
@@ -1451,15 +1437,15 @@ describe('QueryClientProvider — VNode children branch', () => {
|
|
|
1451
1437
|
})
|
|
1452
1438
|
})
|
|
1453
1439
|
|
|
1454
|
-
describe(
|
|
1440
|
+
describe("useMutation — mutateAsync", () => {
|
|
1455
1441
|
let client: QueryClient
|
|
1456
1442
|
beforeEach(() => {
|
|
1457
1443
|
client = makeClient()
|
|
1458
1444
|
})
|
|
1459
1445
|
|
|
1460
|
-
it(
|
|
1446
|
+
it("mutateAsync returns a promise that resolves with data", async () => {
|
|
1461
1447
|
let mut: ReturnType<typeof useMutation<string, Error, string>> | undefined
|
|
1462
|
-
const el = document.createElement(
|
|
1448
|
+
const el = document.createElement("div")
|
|
1463
1449
|
document.body.appendChild(el)
|
|
1464
1450
|
const unmount = mount(
|
|
1465
1451
|
<QueryClientProvider client={client}>
|
|
@@ -1473,24 +1459,24 @@ describe('useMutation — mutateAsync', () => {
|
|
|
1473
1459
|
el,
|
|
1474
1460
|
)
|
|
1475
1461
|
|
|
1476
|
-
const result = await mut!.mutateAsync(
|
|
1477
|
-
expect(result).toBe(
|
|
1462
|
+
const result = await mut!.mutateAsync("test")
|
|
1463
|
+
expect(result).toBe("async-result:test")
|
|
1478
1464
|
expect(mut!.isSuccess()).toBe(true)
|
|
1479
|
-
expect(mut!.data()).toBe(
|
|
1465
|
+
expect(mut!.data()).toBe("async-result:test")
|
|
1480
1466
|
unmount()
|
|
1481
1467
|
el.remove()
|
|
1482
1468
|
})
|
|
1483
1469
|
|
|
1484
|
-
it(
|
|
1470
|
+
it("mutateAsync rejects when mutation fails", async () => {
|
|
1485
1471
|
let mut: ReturnType<typeof useMutation<string, Error, void>> | undefined
|
|
1486
|
-
const el = document.createElement(
|
|
1472
|
+
const el = document.createElement("div")
|
|
1487
1473
|
document.body.appendChild(el)
|
|
1488
1474
|
const unmount = mount(
|
|
1489
1475
|
<QueryClientProvider client={client}>
|
|
1490
1476
|
{() => {
|
|
1491
1477
|
mut = useMutation<string, Error, void>({
|
|
1492
1478
|
mutationFn: async () => {
|
|
1493
|
-
throw new Error(
|
|
1479
|
+
throw new Error("async-fail")
|
|
1494
1480
|
},
|
|
1495
1481
|
})
|
|
1496
1482
|
return null
|
|
@@ -1499,31 +1485,31 @@ describe('useMutation — mutateAsync', () => {
|
|
|
1499
1485
|
el,
|
|
1500
1486
|
)
|
|
1501
1487
|
|
|
1502
|
-
await expect(mut!.mutateAsync(undefined)).rejects.toThrow(
|
|
1488
|
+
await expect(mut!.mutateAsync(undefined)).rejects.toThrow("async-fail")
|
|
1503
1489
|
await new Promise((r) => setTimeout(r, 0))
|
|
1504
1490
|
expect(mut!.isError()).toBe(true)
|
|
1505
|
-
expect((mut!.error() as Error).message).toBe(
|
|
1491
|
+
expect((mut!.error() as Error).message).toBe("async-fail")
|
|
1506
1492
|
unmount()
|
|
1507
1493
|
el.remove()
|
|
1508
1494
|
})
|
|
1509
1495
|
})
|
|
1510
1496
|
|
|
1511
|
-
describe(
|
|
1497
|
+
describe("useQuery — refetch", () => {
|
|
1512
1498
|
let client: QueryClient
|
|
1513
1499
|
beforeEach(() => {
|
|
1514
1500
|
client = makeClient()
|
|
1515
1501
|
})
|
|
1516
1502
|
|
|
1517
|
-
it(
|
|
1503
|
+
it("refetch re-fetches the query and returns updated result", async () => {
|
|
1518
1504
|
let callCount = 0
|
|
1519
1505
|
let query: ReturnType<typeof useQuery<string>> | undefined
|
|
1520
|
-
const el = document.createElement(
|
|
1506
|
+
const el = document.createElement("div")
|
|
1521
1507
|
document.body.appendChild(el)
|
|
1522
1508
|
const unmount = mount(
|
|
1523
1509
|
<QueryClientProvider client={client}>
|
|
1524
1510
|
{() => {
|
|
1525
1511
|
query = useQuery(() => ({
|
|
1526
|
-
queryKey: [
|
|
1512
|
+
queryKey: ["refetch-test"],
|
|
1527
1513
|
queryFn: async () => {
|
|
1528
1514
|
callCount++
|
|
1529
1515
|
return `call-${callCount}`
|
|
@@ -1536,24 +1522,24 @@ describe('useQuery — refetch', () => {
|
|
|
1536
1522
|
)
|
|
1537
1523
|
|
|
1538
1524
|
await new Promise((r) => setTimeout(r, 10))
|
|
1539
|
-
expect(query!.data()).toBe(
|
|
1525
|
+
expect(query!.data()).toBe("call-1")
|
|
1540
1526
|
|
|
1541
1527
|
const result = await query!.refetch()
|
|
1542
1528
|
await new Promise((r) => setTimeout(r, 10))
|
|
1543
1529
|
expect(callCount).toBe(2)
|
|
1544
|
-
expect(result.data).toBe(
|
|
1545
|
-
expect(query!.data()).toBe(
|
|
1530
|
+
expect(result.data).toBe("call-2")
|
|
1531
|
+
expect(query!.data()).toBe("call-2")
|
|
1546
1532
|
unmount()
|
|
1547
1533
|
el.remove()
|
|
1548
1534
|
})
|
|
1549
1535
|
})
|
|
1550
1536
|
|
|
1551
|
-
describe(
|
|
1552
|
-
it(
|
|
1537
|
+
describe("QueryErrorResetBoundary — VNode children branch", () => {
|
|
1538
|
+
it("renders when children is a VNode (not a function)", async () => {
|
|
1553
1539
|
const client = makeClient()
|
|
1554
1540
|
let resetFn: (() => void) | undefined
|
|
1555
1541
|
|
|
1556
|
-
const el = document.createElement(
|
|
1542
|
+
const el = document.createElement("div")
|
|
1557
1543
|
document.body.appendChild(el)
|
|
1558
1544
|
// Pass children as a direct VNode, not a function
|
|
1559
1545
|
const unmount = mount(
|
|
@@ -1576,16 +1562,16 @@ describe('QueryErrorResetBoundary — VNode children branch', () => {
|
|
|
1576
1562
|
})
|
|
1577
1563
|
})
|
|
1578
1564
|
|
|
1579
|
-
describe(
|
|
1565
|
+
describe("useSuspenseQuery — error without handler (QuerySuspense throw branch)", () => {
|
|
1580
1566
|
let client: QueryClient
|
|
1581
1567
|
beforeEach(() => {
|
|
1582
1568
|
client = makeClient()
|
|
1583
1569
|
})
|
|
1584
1570
|
|
|
1585
|
-
it(
|
|
1571
|
+
it("QuerySuspense throws error when no error handler is provided", async () => {
|
|
1586
1572
|
const { promise, reject } = deferred<never>()
|
|
1587
1573
|
|
|
1588
|
-
const el = document.createElement(
|
|
1574
|
+
const el = document.createElement("div")
|
|
1589
1575
|
document.body.appendChild(el)
|
|
1590
1576
|
|
|
1591
1577
|
const _thrownError: unknown = null
|
|
@@ -1595,7 +1581,7 @@ describe('useSuspenseQuery — error without handler (QuerySuspense throw branch
|
|
|
1595
1581
|
<QueryClientProvider client={client}>
|
|
1596
1582
|
{() => {
|
|
1597
1583
|
query = useSuspenseQuery(() => ({
|
|
1598
|
-
queryKey: [
|
|
1584
|
+
queryKey: ["sq-throw-no-handler"],
|
|
1599
1585
|
queryFn: () => promise,
|
|
1600
1586
|
}))
|
|
1601
1587
|
// QuerySuspense with NO error handler — should throw
|
|
@@ -1609,7 +1595,7 @@ describe('useSuspenseQuery — error without handler (QuerySuspense throw branch
|
|
|
1609
1595
|
el,
|
|
1610
1596
|
)
|
|
1611
1597
|
|
|
1612
|
-
reject(new Error(
|
|
1598
|
+
reject(new Error("unhandled suspense error"))
|
|
1613
1599
|
await promise.catch(() => {
|
|
1614
1600
|
/* expected */
|
|
1615
1601
|
})
|
|
@@ -1617,7 +1603,7 @@ describe('useSuspenseQuery — error without handler (QuerySuspense throw branch
|
|
|
1617
1603
|
|
|
1618
1604
|
// The error state should be set on the query
|
|
1619
1605
|
expect(query!.isError()).toBe(true)
|
|
1620
|
-
expect((query!.error() as Error).message).toBe(
|
|
1606
|
+
expect((query!.error() as Error).message).toBe("unhandled suspense error")
|
|
1621
1607
|
|
|
1622
1608
|
// Verify that calling the QuerySuspense render function directly would throw
|
|
1623
1609
|
// by checking the query is in error state without an error handler
|
|
@@ -1626,10 +1612,10 @@ describe('useSuspenseQuery — error without handler (QuerySuspense throw branch
|
|
|
1626
1612
|
el.remove()
|
|
1627
1613
|
})
|
|
1628
1614
|
|
|
1629
|
-
it(
|
|
1615
|
+
it("QuerySuspense re-throws error to be caught externally", async () => {
|
|
1630
1616
|
const { promise, reject } = deferred<never>()
|
|
1631
1617
|
|
|
1632
|
-
const el = document.createElement(
|
|
1618
|
+
const el = document.createElement("div")
|
|
1633
1619
|
document.body.appendChild(el)
|
|
1634
1620
|
|
|
1635
1621
|
let query: ReturnType<typeof useSuspenseQuery> | undefined
|
|
@@ -1638,7 +1624,7 @@ describe('useSuspenseQuery — error without handler (QuerySuspense throw branch
|
|
|
1638
1624
|
<QueryClientProvider client={client}>
|
|
1639
1625
|
{() => {
|
|
1640
1626
|
query = useSuspenseQuery(() => ({
|
|
1641
|
-
queryKey: [
|
|
1627
|
+
queryKey: ["sq-rethrow-direct"],
|
|
1642
1628
|
queryFn: () => promise,
|
|
1643
1629
|
}))
|
|
1644
1630
|
return null
|
|
@@ -1647,7 +1633,7 @@ describe('useSuspenseQuery — error without handler (QuerySuspense throw branch
|
|
|
1647
1633
|
el,
|
|
1648
1634
|
)
|
|
1649
1635
|
|
|
1650
|
-
reject(new Error(
|
|
1636
|
+
reject(new Error("direct throw"))
|
|
1651
1637
|
await promise.catch(() => {
|
|
1652
1638
|
/* expected */
|
|
1653
1639
|
})
|
|
@@ -1657,11 +1643,11 @@ describe('useSuspenseQuery — error without handler (QuerySuspense throw branch
|
|
|
1657
1643
|
expect(() => {
|
|
1658
1644
|
const renderFn = QuerySuspense({
|
|
1659
1645
|
query: query!,
|
|
1660
|
-
fallback:
|
|
1646
|
+
fallback: "loading",
|
|
1661
1647
|
children: () => null,
|
|
1662
1648
|
}) as () => unknown
|
|
1663
1649
|
renderFn()
|
|
1664
|
-
}).toThrow(
|
|
1650
|
+
}).toThrow("direct throw")
|
|
1665
1651
|
|
|
1666
1652
|
unmount()
|
|
1667
1653
|
el.remove()
|