@geekmidas/client 0.4.0 → 0.5.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/dist/auth-fetcher.cjs +0 -1
- package/dist/auth-fetcher.cjs.map +1 -1
- package/dist/auth-fetcher.d.cts +1 -1
- package/dist/auth-fetcher.d.cts.map +1 -1
- package/dist/auth-fetcher.d.mts +1 -1
- package/dist/auth-fetcher.d.mts.map +1 -1
- package/dist/auth-fetcher.mjs +0 -1
- package/dist/auth-fetcher.mjs.map +1 -1
- package/dist/endpoint-hooks.cjs +10 -5
- package/dist/endpoint-hooks.cjs.map +1 -1
- package/dist/endpoint-hooks.d.cts +2 -2
- package/dist/endpoint-hooks.d.cts.map +1 -1
- package/dist/endpoint-hooks.d.mts +2 -2
- package/dist/endpoint-hooks.d.mts.map +1 -1
- package/dist/endpoint-hooks.mjs +10 -5
- package/dist/endpoint-hooks.mjs.map +1 -1
- package/dist/fetcher-5fnBE7Dk.mjs.map +1 -1
- package/dist/fetcher-CgLEaIAC.cjs.map +1 -1
- package/dist/fetcher.d.cts +1 -1
- package/dist/fetcher.d.cts.map +1 -1
- package/dist/fetcher.d.mts +1 -1
- package/dist/fetcher.d.mts.map +1 -1
- package/dist/infer.d.cts.map +1 -1
- package/dist/infer.d.mts.map +1 -1
- package/dist/openapi-hooks.cjs.map +1 -1
- package/dist/openapi-hooks.d.cts +2 -2
- package/dist/openapi-hooks.d.cts.map +1 -1
- package/dist/openapi-hooks.d.mts +2 -2
- package/dist/openapi-hooks.d.mts.map +1 -1
- package/dist/openapi-hooks.mjs.map +1 -1
- package/dist/openapi-types.d.cts.map +1 -1
- package/dist/openapi-types.d.mts.map +1 -1
- package/dist/openapi.cjs.map +1 -1
- package/dist/openapi.mjs.map +1 -1
- package/dist/react-query.cjs.map +1 -1
- package/dist/react-query.d.cts +1 -1
- package/dist/react-query.d.cts.map +1 -1
- package/dist/react-query.d.mts +1 -1
- package/dist/react-query.d.mts.map +1 -1
- package/dist/react-query.mjs.map +1 -1
- package/dist/{types-FxummKaL.d.mts → types-4K4N-Fl1.d.cts} +2 -2
- package/dist/types-4K4N-Fl1.d.cts.map +1 -0
- package/dist/{types-vutATyWv.d.cts → types-hhkZWjQn.d.mts} +2 -2
- package/dist/types-hhkZWjQn.d.mts.map +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +3 -3
- package/src/__tests__/auth-fetcher.spec.ts +476 -476
- package/src/__tests__/endpoint-hooks.spec.tsx +348 -348
- package/src/__tests__/fetcher.spec.ts +403 -403
- package/src/__tests__/infer.integration.spec.ts +171 -171
- package/src/__tests__/infer.spec.ts +182 -182
- package/src/__tests__/method-restrictions.spec.tsx +165 -165
- package/src/__tests__/openapi-hooks.spec.tsx +536 -536
- package/src/__tests__/react-query-infinite.spec.tsx +989 -989
- package/src/__tests__/react-query-invalidation.spec.tsx +223 -222
- package/src/__tests__/react-query.spec.tsx +567 -567
- package/src/__tests__/setup.ts +260 -260
- package/src/__tests__/types.spec.ts +127 -127
- package/src/__tests__/url-parsing.spec.ts +191 -191
- package/src/auth-fetcher.ts +160 -162
- package/src/endpoint-hooks.ts +151 -156
- package/src/fetcher.ts +163 -163
- package/src/infer.ts +64 -63
- package/src/openapi-hooks.ts +146 -146
- package/src/openapi-types.d.ts +428 -428
- package/src/openapi.json +593 -593
- package/src/react-query.ts +281 -281
- package/src/types.ts +121 -124
- package/dist/types-FxummKaL.d.mts.map +0 -1
- package/dist/types-vutATyWv.d.cts.map +0 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
5
5
|
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
6
|
-
import {
|
|
6
|
+
import { HttpResponse, http } from 'msw';
|
|
7
7
|
// biome-ignore lint/style/useImportType: <explanation>
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
@@ -12,992 +12,992 @@ import { createTypedQueryClient } from '../react-query';
|
|
|
12
12
|
import './setup';
|
|
13
13
|
|
|
14
14
|
describe('TypedQueryClient - useInfiniteQuery', () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
15
|
+
const queryClient = new QueryClient({
|
|
16
|
+
defaultOptions: {
|
|
17
|
+
queries: {
|
|
18
|
+
retry: false,
|
|
19
|
+
gcTime: 0,
|
|
20
|
+
staleTime: 0,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
26
|
+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
queryClient.clear();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should correctly merge query parameters with pageParam', async () => {
|
|
34
|
+
// Mock fetch to verify the URL
|
|
35
|
+
const originalFetch = global.fetch;
|
|
36
|
+
const fetchSpy = vi.fn(originalFetch);
|
|
37
|
+
global.fetch = fetchSpy;
|
|
38
|
+
|
|
39
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
40
|
+
baseURL: 'https://api.example.com',
|
|
41
|
+
fetch: fetchSpy,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const { result } = renderHook(
|
|
45
|
+
() =>
|
|
46
|
+
typedClient.useInfiniteQuery(
|
|
47
|
+
'GET /posts',
|
|
48
|
+
{
|
|
49
|
+
initialPageParam: 1,
|
|
50
|
+
getNextPageParam: () => undefined,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
query: {
|
|
54
|
+
sort: 'desc',
|
|
55
|
+
limit: 10,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
),
|
|
59
|
+
{ wrapper },
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
63
|
+
|
|
64
|
+
// Restore original fetch
|
|
65
|
+
global.fetch = originalFetch;
|
|
66
|
+
|
|
67
|
+
// Verify the fetch URL contains all query parameters
|
|
68
|
+
expect(fetchSpy).toHaveBeenCalled();
|
|
69
|
+
const callArg = fetchSpy.mock.calls[0][0];
|
|
70
|
+
const url = new URL(
|
|
71
|
+
callArg instanceof Request ? callArg.url : callArg.toString(),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
expect(url.searchParams.get('page')).toBe('1');
|
|
75
|
+
expect(url.searchParams.get('sort')).toBe('desc');
|
|
76
|
+
expect(url.searchParams.get('limit')).toBe('10');
|
|
77
|
+
|
|
78
|
+
// Verify response data
|
|
79
|
+
expect(result.current.data?.pages[0]).toBeDefined();
|
|
80
|
+
expect(result.current.data?.pages[0].sort).toBe('desc');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should correctly type the data structure with pages array', () => {
|
|
84
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
85
|
+
baseURL: 'https://api.example.com',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const { result } = renderHook(
|
|
89
|
+
() => {
|
|
90
|
+
const query = typedClient.useInfiniteQuery('GET /users/paginated', {
|
|
91
|
+
initialPageParam: 1,
|
|
92
|
+
getNextPageParam: (lastPage, allPages, lastPageParam) => {
|
|
93
|
+
if (!lastPage) return undefined;
|
|
94
|
+
// Type tests - these should compile without error
|
|
95
|
+
const _pageNum: number = lastPage.pagination.page;
|
|
96
|
+
const hasMore: boolean = lastPage.pagination.hasMore;
|
|
97
|
+
const _users: Array<{ id: string; name: string; email: string }> =
|
|
98
|
+
lastPage.users;
|
|
99
|
+
|
|
100
|
+
// allPages should be an array
|
|
101
|
+
const _pagesArray: (typeof lastPage)[] = allPages;
|
|
102
|
+
|
|
103
|
+
// lastPageParam should be number (as we defined)
|
|
104
|
+
const param: number = lastPageParam;
|
|
105
|
+
|
|
106
|
+
return hasMore ? param + 1 : undefined;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Type test for the returned data structure
|
|
111
|
+
if (query.data) {
|
|
112
|
+
// This should compile - data.pages should exist and be an array
|
|
113
|
+
const pages: Array<{
|
|
114
|
+
users: Array<{ id: string; name: string; email: string }>;
|
|
115
|
+
pagination: {
|
|
116
|
+
page: number;
|
|
117
|
+
limit: number;
|
|
118
|
+
total: number;
|
|
119
|
+
hasMore: boolean;
|
|
120
|
+
};
|
|
121
|
+
}> = query.data.pages;
|
|
122
|
+
|
|
123
|
+
// pageParams should also be typed correctly
|
|
124
|
+
const _pageParams: number[] = query.data.pageParams;
|
|
125
|
+
|
|
126
|
+
// Test accessing nested data
|
|
127
|
+
if (pages.length > 0) {
|
|
128
|
+
const firstPageUsers = pages[0].users;
|
|
129
|
+
const firstUser = firstPageUsers[0];
|
|
130
|
+
if (firstUser) {
|
|
131
|
+
const _userId: string = firstUser.id;
|
|
132
|
+
const _userName: string = firstUser.name;
|
|
133
|
+
const _userEmail: string = firstUser.email;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return query;
|
|
139
|
+
},
|
|
140
|
+
{ wrapper },
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// The test passes if TypeScript compiles without error
|
|
144
|
+
expect(result.current).toBeDefined();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should work with cursor-based pagination types', () => {
|
|
148
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
149
|
+
baseURL: 'https://api.example.com',
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const { result } = renderHook(
|
|
153
|
+
() => {
|
|
154
|
+
const query = typedClient.useInfiniteQuery('GET /messages', {
|
|
155
|
+
initialPageParam: undefined as string | undefined,
|
|
156
|
+
getNextPageParam: (lastPage) => {
|
|
157
|
+
// Type test - nextCursor should be string | null
|
|
158
|
+
const cursor: string | null = lastPage.nextCursor;
|
|
159
|
+
return cursor ?? undefined;
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Type test for cursor-based data
|
|
164
|
+
if (query.data) {
|
|
165
|
+
const _pages: Array<{
|
|
166
|
+
messages: Array<{ id: string; text: string; timestamp: string }>;
|
|
167
|
+
nextCursor: string | null;
|
|
168
|
+
}> = query.data.pages;
|
|
169
|
+
|
|
170
|
+
const _pageParams: (string | undefined)[] = query.data.pageParams;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return query;
|
|
174
|
+
},
|
|
175
|
+
{ wrapper },
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
expect(result.current).toBeDefined();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should preserve existing query parameters when paginating', async () => {
|
|
182
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
183
|
+
baseURL: 'https://api.example.com',
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const { result } = renderHook(
|
|
187
|
+
() =>
|
|
188
|
+
typedClient.useInfiniteQuery(
|
|
189
|
+
'GET /posts',
|
|
190
|
+
{
|
|
191
|
+
initialPageParam: 1,
|
|
192
|
+
getNextPageParam: (lastPage) => {
|
|
193
|
+
const nextPage = lastPage?.pagination?.page
|
|
194
|
+
? lastPage.pagination.page + 1
|
|
195
|
+
: undefined;
|
|
196
|
+
return nextPage && nextPage <= 3 ? nextPage : undefined;
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
query: {
|
|
201
|
+
limit: 5,
|
|
202
|
+
sort: 'asc',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
),
|
|
206
|
+
{ wrapper },
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// Wait for initial load
|
|
210
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
211
|
+
|
|
212
|
+
// Verify initial data has query params applied
|
|
213
|
+
expect(result.current.data?.pages[0]).toBeDefined();
|
|
214
|
+
expect(result.current.data?.pages[0].pagination.limit).toBe(5);
|
|
215
|
+
expect(result.current.data?.pages[0].sort).toBe('asc');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should merge query parameters with pageParam correctly', async () => {
|
|
219
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
220
|
+
baseURL: 'https://api.example.com',
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const { result } = renderHook(
|
|
224
|
+
() =>
|
|
225
|
+
typedClient.useInfiniteQuery(
|
|
226
|
+
'GET /posts',
|
|
227
|
+
{
|
|
228
|
+
initialPageParam: 1,
|
|
229
|
+
getNextPageParam: (_lastPage, _allPages, lastPageParam) =>
|
|
230
|
+
lastPageParam < 3 ? lastPageParam + 1 : undefined,
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
query: {
|
|
234
|
+
sort: 'desc',
|
|
235
|
+
limit: 15,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
),
|
|
239
|
+
{ wrapper },
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
243
|
+
|
|
244
|
+
// Check that initial query parameters are present
|
|
245
|
+
expect(result.current.data?.pages[0].sort).toBe('desc');
|
|
246
|
+
expect(result.current.data?.pages[0].pagination.limit).toBe(15);
|
|
247
|
+
expect(result.current.data?.pages[0].pagination.page).toBe(1);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should handle object pageParam with existing query parameters', async () => {
|
|
251
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
252
|
+
baseURL: 'https://api.example.com',
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const { result } = renderHook(
|
|
256
|
+
() =>
|
|
257
|
+
typedClient.useInfiniteQuery(
|
|
258
|
+
'GET /messages',
|
|
259
|
+
{
|
|
260
|
+
initialPageParam: {
|
|
261
|
+
cursor: undefined as string | undefined,
|
|
262
|
+
limit: 10,
|
|
263
|
+
},
|
|
264
|
+
getNextPageParam: (lastPage) =>
|
|
265
|
+
lastPage.nextCursor
|
|
266
|
+
? { cursor: lastPage.nextCursor, limit: 10 }
|
|
267
|
+
: undefined,
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
query: {
|
|
271
|
+
limit: 20, // This should be overridden by pageParam
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
),
|
|
275
|
+
{ wrapper },
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
279
|
+
|
|
280
|
+
// The pageParam should override the initial query parameter
|
|
281
|
+
expect(result.current.data?.pages[0].messages).toBeDefined();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should handle numeric pageParam without config', async () => {
|
|
285
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
286
|
+
baseURL: 'https://api.example.com',
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const { result } = renderHook(
|
|
290
|
+
() =>
|
|
291
|
+
typedClient.useInfiniteQuery('GET /posts', {
|
|
292
|
+
initialPageParam: 1,
|
|
293
|
+
getNextPageParam: () => undefined,
|
|
294
|
+
}),
|
|
295
|
+
{ wrapper },
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
299
|
+
|
|
300
|
+
expect(result.current.data?.pages[0].pagination.page).toBe(1);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should include query parameters in cache key', async () => {
|
|
304
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
305
|
+
baseURL: 'https://api.example.com',
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
const { result: result1 } = renderHook(
|
|
309
|
+
() =>
|
|
310
|
+
typedClient.useInfiniteQuery(
|
|
311
|
+
'GET /posts',
|
|
312
|
+
{
|
|
313
|
+
initialPageParam: 1,
|
|
314
|
+
getNextPageParam: () => undefined,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
query: { sort: 'asc' },
|
|
318
|
+
},
|
|
319
|
+
),
|
|
320
|
+
{ wrapper },
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const { result: result2 } = renderHook(
|
|
324
|
+
() =>
|
|
325
|
+
typedClient.useInfiniteQuery(
|
|
326
|
+
'GET /posts',
|
|
327
|
+
{
|
|
328
|
+
initialPageParam: 1,
|
|
329
|
+
getNextPageParam: () => undefined,
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
query: { sort: 'desc' },
|
|
333
|
+
},
|
|
334
|
+
),
|
|
335
|
+
{ wrapper },
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
await waitFor(() => {
|
|
339
|
+
expect(result1.current.isSuccess).toBe(true);
|
|
340
|
+
expect(result2.current.isSuccess).toBe(true);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Different query parameters should result in different cache entries
|
|
344
|
+
expect(result1.current.data?.pages[0].sort).toBe('asc');
|
|
345
|
+
expect(result2.current.data?.pages[0].sort).toBe('desc');
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('should maintain all query parameters across multiple page fetches', async () => {
|
|
349
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
350
|
+
baseURL: 'https://api.example.com',
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// Mock fetch to verify URLs
|
|
354
|
+
const originalFetch = global.fetch;
|
|
355
|
+
const fetchCalls: string[] = [];
|
|
356
|
+
const fetchSpy = vi.fn((url, ...args) => {
|
|
357
|
+
const urlString = url instanceof Request ? url.url : url.toString();
|
|
358
|
+
fetchCalls.push(urlString);
|
|
359
|
+
return originalFetch(url, ...args);
|
|
360
|
+
});
|
|
361
|
+
global.fetch = fetchSpy;
|
|
362
|
+
|
|
363
|
+
const { result } = renderHook(
|
|
364
|
+
() =>
|
|
365
|
+
typedClient.useInfiniteQuery(
|
|
366
|
+
'GET /posts',
|
|
367
|
+
{
|
|
368
|
+
initialPageParam: 1,
|
|
369
|
+
getNextPageParam: (_lastPage, _allPages, lastPageParam) => {
|
|
370
|
+
return lastPageParam < 3 ? lastPageParam + 1 : undefined;
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
query: {
|
|
375
|
+
sort: 'desc',
|
|
376
|
+
limit: 10,
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
),
|
|
380
|
+
{ wrapper },
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
// Wait for initial page
|
|
384
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
385
|
+
|
|
386
|
+
// Fetch next pages
|
|
387
|
+
await result.current.fetchNextPage();
|
|
388
|
+
await result.current.fetchNextPage();
|
|
389
|
+
|
|
390
|
+
// Restore original fetch
|
|
391
|
+
global.fetch = originalFetch;
|
|
392
|
+
|
|
393
|
+
// Verify all requests had the correct query parameters
|
|
394
|
+
fetchCalls.forEach((urlString, index) => {
|
|
395
|
+
const url = new URL(urlString);
|
|
396
|
+
expect(url.searchParams.get('page')).toBe(String(index + 1));
|
|
397
|
+
expect(url.searchParams.get('sort')).toBe('desc');
|
|
398
|
+
expect(url.searchParams.get('limit')).toBe('10');
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('should handle complex object pageParam merging', async () => {
|
|
403
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
404
|
+
baseURL: 'https://api.example.com',
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
const { result } = renderHook(
|
|
408
|
+
() =>
|
|
409
|
+
typedClient.useInfiniteQuery(
|
|
410
|
+
'GET /messages',
|
|
411
|
+
{
|
|
412
|
+
initialPageParam: {
|
|
413
|
+
cursor: undefined as string | undefined,
|
|
414
|
+
limit: 5,
|
|
415
|
+
type: 'initial',
|
|
416
|
+
},
|
|
417
|
+
getNextPageParam: (lastPage) =>
|
|
418
|
+
lastPage.nextCursor
|
|
419
|
+
? {
|
|
420
|
+
cursor: lastPage.nextCursor,
|
|
421
|
+
limit: 5,
|
|
422
|
+
type: 'next',
|
|
423
|
+
}
|
|
424
|
+
: undefined,
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
query: {
|
|
428
|
+
limit: 10, // Should be overridden by pageParam
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
),
|
|
432
|
+
{ wrapper },
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
436
|
+
|
|
437
|
+
// The complex pageParam should properly merge with config
|
|
438
|
+
expect(result.current.data?.pages[0]).toBeDefined();
|
|
439
|
+
|
|
440
|
+
// Fetch next page to ensure complex objects continue to work
|
|
441
|
+
if (result.current.hasNextPage) {
|
|
442
|
+
await waitFor(async () => {
|
|
443
|
+
await result.current.fetchNextPage();
|
|
444
|
+
expect(result.current.data?.pages).toHaveLength(2);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it('should correctly build query key with query parameters', () => {
|
|
450
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
451
|
+
baseURL: 'https://api.example.com',
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// Test with query parameters
|
|
455
|
+
const queryKey1 = typedClient.buildQueryKey('GET /posts', {
|
|
456
|
+
query: { sort: 'asc', limit: 10 },
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
expect(queryKey1).toEqual([
|
|
460
|
+
'GET /posts',
|
|
461
|
+
{ query: { sort: 'asc', limit: 10 } },
|
|
462
|
+
]);
|
|
463
|
+
|
|
464
|
+
// Test with both params and query
|
|
465
|
+
const queryKey2 = typedClient.buildQueryKey('GET /users/{id}', {
|
|
466
|
+
params: { id: '123' },
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
expect(queryKey2).toEqual(['GET /users/{id}', { params: { id: '123' } }]);
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('should handle undefined pageParam correctly', async () => {
|
|
473
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
474
|
+
baseURL: 'https://api.example.com',
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
const { result } = renderHook(
|
|
478
|
+
() =>
|
|
479
|
+
typedClient.useInfiniteQuery(
|
|
480
|
+
'GET /messages',
|
|
481
|
+
{
|
|
482
|
+
initialPageParam: undefined,
|
|
483
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor || undefined,
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
query: {
|
|
487
|
+
limit: 15,
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
),
|
|
491
|
+
{ wrapper },
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
495
|
+
|
|
496
|
+
// Should still include the initial query parameters
|
|
497
|
+
expect(result.current.data?.pages[0].messages).toBeDefined();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('should validate query parameter types are preserved in responses', async () => {
|
|
501
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
502
|
+
baseURL: 'https://api.example.com',
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
const { result } = renderHook(
|
|
506
|
+
() =>
|
|
507
|
+
typedClient.useInfiniteQuery(
|
|
508
|
+
'GET /posts',
|
|
509
|
+
{
|
|
510
|
+
initialPageParam: 1,
|
|
511
|
+
getNextPageParam: () => undefined,
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
query: {
|
|
515
|
+
page: 1,
|
|
516
|
+
limit: 20,
|
|
517
|
+
sort: 'asc',
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
),
|
|
521
|
+
{ wrapper },
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
525
|
+
|
|
526
|
+
const firstPage = result.current.data?.pages[0];
|
|
527
|
+
|
|
528
|
+
// Type checks - these should compile
|
|
529
|
+
if (firstPage) {
|
|
530
|
+
const posts: Array<{
|
|
531
|
+
id: string;
|
|
532
|
+
title: string;
|
|
533
|
+
content: string;
|
|
534
|
+
authorId: string;
|
|
535
|
+
createdAt: string;
|
|
536
|
+
}> = firstPage.posts;
|
|
537
|
+
|
|
538
|
+
const pagination: {
|
|
539
|
+
page: number;
|
|
540
|
+
limit: number;
|
|
541
|
+
total: number;
|
|
542
|
+
} = firstPage.pagination;
|
|
543
|
+
|
|
544
|
+
const sort: 'asc' | 'desc' = firstPage.sort;
|
|
545
|
+
|
|
546
|
+
// Runtime checks
|
|
547
|
+
expect(posts).toBeInstanceOf(Array);
|
|
548
|
+
expect(typeof pagination.page).toBe('number');
|
|
549
|
+
expect(typeof pagination.limit).toBe('number');
|
|
550
|
+
expect(typeof pagination.total).toBe('number');
|
|
551
|
+
expect(['asc', 'desc']).toContain(sort);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it('should send all query parameters in HTTP request', async () => {
|
|
556
|
+
// Mock fetch to capture the actual request
|
|
557
|
+
const originalFetch = global.fetch;
|
|
558
|
+
const fetchSpy = vi.fn(originalFetch);
|
|
559
|
+
|
|
560
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
561
|
+
baseURL: 'https://api.example.com',
|
|
562
|
+
fetch: fetchSpy,
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
const { result } = renderHook(
|
|
566
|
+
() =>
|
|
567
|
+
typedClient.useInfiniteQuery(
|
|
568
|
+
'GET /posts',
|
|
569
|
+
{
|
|
570
|
+
initialPageParam: 2,
|
|
571
|
+
getNextPageParam: () => undefined,
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
query: {
|
|
575
|
+
sort: 'desc',
|
|
576
|
+
limit: 25,
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
),
|
|
580
|
+
{ wrapper },
|
|
581
|
+
);
|
|
582
|
+
|
|
583
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
584
|
+
|
|
585
|
+
// Check that the fetch was called with correct URL including all query params
|
|
586
|
+
expect(fetchSpy).toHaveBeenCalled();
|
|
587
|
+
const callArg = fetchSpy.mock.calls[0][0];
|
|
588
|
+
const url = new URL(
|
|
589
|
+
callArg instanceof Request ? callArg.url : callArg.toString(),
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
expect(url.searchParams.get('page')).toBe('2');
|
|
593
|
+
expect(url.searchParams.get('sort')).toBe('desc');
|
|
594
|
+
expect(url.searchParams.get('limit')).toBe('25');
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
it('should handle empty query config gracefully', async () => {
|
|
598
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
599
|
+
baseURL: 'https://api.example.com',
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
const { result } = renderHook(
|
|
603
|
+
() =>
|
|
604
|
+
typedClient.useInfiniteQuery('GET /posts', {
|
|
605
|
+
initialPageParam: 1,
|
|
606
|
+
getNextPageParam: () => undefined,
|
|
607
|
+
}),
|
|
608
|
+
{ wrapper },
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
612
|
+
|
|
613
|
+
expect(result.current.data?.pages[0]).toBeDefined();
|
|
614
|
+
expect(result.current.data?.pages[0].pagination.page).toBe(1);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('should handle query parameters with special characters', async () => {
|
|
618
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
619
|
+
baseURL: 'https://api.example.com',
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
const { result } = renderHook(
|
|
623
|
+
() =>
|
|
624
|
+
typedClient.useInfiniteQuery(
|
|
625
|
+
'GET /messages',
|
|
626
|
+
{
|
|
627
|
+
initialPageParam: 'cursor%20with%20spaces',
|
|
628
|
+
getNextPageParam: () => undefined,
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
query: {
|
|
632
|
+
limit: 10,
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
),
|
|
636
|
+
{ wrapper },
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
640
|
+
|
|
641
|
+
// Should handle special characters in pageParam correctly
|
|
642
|
+
expect(result.current.data?.pages[0]).toBeDefined();
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
it('should verify object pageParam merging with echo endpoint', async () => {
|
|
646
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
647
|
+
baseURL: 'https://api.example.com',
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
const { result } = renderHook(
|
|
651
|
+
() =>
|
|
652
|
+
typedClient.useInfiniteQuery(
|
|
653
|
+
'GET /echo',
|
|
654
|
+
{
|
|
655
|
+
initialPageParam: {
|
|
656
|
+
page: 1,
|
|
657
|
+
size: 20,
|
|
658
|
+
offset: 0,
|
|
659
|
+
},
|
|
660
|
+
getNextPageParam: (lastPage) =>
|
|
661
|
+
lastPage.pagination.hasMore
|
|
662
|
+
? {
|
|
663
|
+
page: lastPage.pagination.page + 1,
|
|
664
|
+
size: 20,
|
|
665
|
+
offset: lastPage.pagination.page * 20,
|
|
666
|
+
}
|
|
667
|
+
: undefined,
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
query: {
|
|
671
|
+
sort: 'asc',
|
|
672
|
+
type: 'premium',
|
|
673
|
+
} as any,
|
|
674
|
+
},
|
|
675
|
+
),
|
|
676
|
+
{ wrapper },
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
680
|
+
|
|
681
|
+
// Verify object pageParam is spread into query params
|
|
682
|
+
const firstPage = result.current.data?.pages[0];
|
|
683
|
+
expect(firstPage?.queryParams).toEqual({
|
|
684
|
+
page: '1',
|
|
685
|
+
size: '20',
|
|
686
|
+
offset: '0',
|
|
687
|
+
sort: 'asc',
|
|
688
|
+
type: 'premium',
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// Fetch next page
|
|
692
|
+
await result.current.fetchNextPage();
|
|
693
|
+
await waitFor(() => expect(result.current.data?.pages).toHaveLength(2));
|
|
694
|
+
|
|
695
|
+
const secondPage = result.current.data?.pages[1];
|
|
696
|
+
expect(secondPage?.queryParams).toEqual({
|
|
697
|
+
page: '2',
|
|
698
|
+
size: '20',
|
|
699
|
+
offset: '20',
|
|
700
|
+
sort: 'asc',
|
|
701
|
+
type: 'premium',
|
|
702
|
+
});
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it('should verify all query params are sent using echo endpoint', async () => {
|
|
706
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
707
|
+
baseURL: 'https://api.example.com',
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
const { result } = renderHook(
|
|
711
|
+
() =>
|
|
712
|
+
typedClient.useInfiniteQuery(
|
|
713
|
+
'GET /echo',
|
|
714
|
+
{
|
|
715
|
+
initialPageParam: 1,
|
|
716
|
+
getNextPageParam: (lastPage) =>
|
|
717
|
+
lastPage.pagination.hasMore
|
|
718
|
+
? lastPage.pagination.page + 1
|
|
719
|
+
: undefined,
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
query: {
|
|
723
|
+
sort: 'desc',
|
|
724
|
+
filter: 'active',
|
|
725
|
+
category: 'tech',
|
|
726
|
+
includeArchived: false,
|
|
727
|
+
limit: 25,
|
|
728
|
+
} as any, // Using any to allow arbitrary query params for echo endpoint
|
|
729
|
+
},
|
|
730
|
+
),
|
|
731
|
+
{ wrapper },
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
// Wait for initial load
|
|
735
|
+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
|
736
|
+
|
|
737
|
+
// Verify the echo endpoint returned all our query parameters
|
|
738
|
+
const firstPage = result.current.data?.pages[0];
|
|
739
|
+
expect(firstPage?.queryParams).toEqual({
|
|
740
|
+
page: '1', // From pageParam
|
|
741
|
+
sort: 'desc',
|
|
742
|
+
filter: 'active',
|
|
743
|
+
category: 'tech',
|
|
744
|
+
includeArchived: 'false',
|
|
745
|
+
limit: '25',
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
// Fetch next page
|
|
749
|
+
await result.current.fetchNextPage();
|
|
750
|
+
await waitFor(() => expect(result.current.data?.pages).toHaveLength(2));
|
|
751
|
+
|
|
752
|
+
// Verify second page also has all parameters with updated page
|
|
753
|
+
const secondPage = result.current.data?.pages[1];
|
|
754
|
+
expect(secondPage?.queryParams).toEqual({
|
|
755
|
+
page: '2', // Updated pageParam
|
|
756
|
+
sort: 'desc',
|
|
757
|
+
filter: 'active',
|
|
758
|
+
category: 'tech',
|
|
759
|
+
includeArchived: 'false',
|
|
760
|
+
limit: '25',
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
// Verify the actual data and pagination info
|
|
764
|
+
expect(firstPage?.pagination).toMatchObject({
|
|
765
|
+
page: 1,
|
|
766
|
+
limit: 25,
|
|
767
|
+
total: 50,
|
|
768
|
+
hasMore: true,
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
it('should distinguish between queries with different query parameters in cache', async () => {
|
|
773
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
774
|
+
baseURL: 'https://api.example.com',
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
// Query 1: sort=asc, limit=5
|
|
778
|
+
const { result: result1 } = renderHook(
|
|
779
|
+
() =>
|
|
780
|
+
typedClient.useInfiniteQuery(
|
|
781
|
+
'GET /posts',
|
|
782
|
+
{
|
|
783
|
+
initialPageParam: 1,
|
|
784
|
+
getNextPageParam: () => 2,
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
query: { sort: 'asc', limit: 5 },
|
|
788
|
+
},
|
|
789
|
+
),
|
|
790
|
+
{ wrapper },
|
|
791
|
+
);
|
|
792
|
+
|
|
793
|
+
// Query 2: sort=desc, limit=5
|
|
794
|
+
const { result: result2 } = renderHook(
|
|
795
|
+
() =>
|
|
796
|
+
typedClient.useInfiniteQuery(
|
|
797
|
+
'GET /posts',
|
|
798
|
+
{
|
|
799
|
+
initialPageParam: 1,
|
|
800
|
+
getNextPageParam: () => 2,
|
|
801
|
+
},
|
|
802
|
+
{
|
|
803
|
+
query: { sort: 'desc', limit: 5 },
|
|
804
|
+
},
|
|
805
|
+
),
|
|
806
|
+
{ wrapper },
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
// Query 3: sort=asc, limit=10
|
|
810
|
+
const { result: result3 } = renderHook(
|
|
811
|
+
() =>
|
|
812
|
+
typedClient.useInfiniteQuery(
|
|
813
|
+
'GET /posts',
|
|
814
|
+
{
|
|
815
|
+
initialPageParam: 1,
|
|
816
|
+
getNextPageParam: () => 2,
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
query: { sort: 'asc', limit: 10 },
|
|
820
|
+
},
|
|
821
|
+
),
|
|
822
|
+
{ wrapper },
|
|
823
|
+
);
|
|
824
|
+
|
|
825
|
+
await waitFor(() => {
|
|
826
|
+
expect(result1.current.isSuccess).toBe(true);
|
|
827
|
+
expect(result2.current.isSuccess).toBe(true);
|
|
828
|
+
expect(result3.current.isSuccess).toBe(true);
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
// Each query should have different data based on query params
|
|
832
|
+
expect(result1.current.data?.pages[0].sort).toBe('asc');
|
|
833
|
+
expect(result1.current.data?.pages[0].pagination.limit).toBe(5);
|
|
834
|
+
|
|
835
|
+
expect(result2.current.data?.pages[0].sort).toBe('desc');
|
|
836
|
+
expect(result2.current.data?.pages[0].pagination.limit).toBe(5);
|
|
837
|
+
|
|
838
|
+
expect(result3.current.data?.pages[0].sort).toBe('asc');
|
|
839
|
+
expect(result3.current.data?.pages[0].pagination.limit).toBe(10);
|
|
840
|
+
|
|
841
|
+
// Fetch next page for first query
|
|
842
|
+
await waitFor(async () => {
|
|
843
|
+
await result1.current.fetchNextPage();
|
|
844
|
+
expect(result1.current.data?.pages).toHaveLength(2);
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// Verify the second page also has correct query params
|
|
848
|
+
expect(result1.current.data?.pages[1].sort).toBe('asc');
|
|
849
|
+
expect(result1.current.data?.pages[1].pagination.limit).toBe(5);
|
|
850
|
+
expect(result1.current.data?.pages[1].pagination.page).toBe(2);
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
describe('Memoization', () => {
|
|
854
|
+
it('should not cause unnecessary re-renders when options object is recreated with same values', async () => {
|
|
855
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
856
|
+
baseURL: 'https://api.example.com',
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
// Track API calls using MSW request interception
|
|
860
|
+
let requestCount = 0;
|
|
861
|
+
const { server } = await import('./setup');
|
|
862
|
+
server.use(
|
|
863
|
+
http.get('https://api.example.com/users/paginated', ({ request }) => {
|
|
864
|
+
requestCount++;
|
|
865
|
+
const url = new URL(request.url);
|
|
866
|
+
const page = parseInt(url.searchParams.get('page') || '1', 10);
|
|
867
|
+
|
|
868
|
+
return HttpResponse.json({
|
|
869
|
+
users: [
|
|
870
|
+
{
|
|
871
|
+
id: `user-${page}`,
|
|
872
|
+
name: `User ${page}`,
|
|
873
|
+
email: `user${page}@example.com`,
|
|
874
|
+
},
|
|
875
|
+
],
|
|
876
|
+
pagination: {
|
|
877
|
+
page,
|
|
878
|
+
limit: 10,
|
|
879
|
+
total: 50,
|
|
880
|
+
hasMore: page < 5,
|
|
881
|
+
},
|
|
882
|
+
});
|
|
883
|
+
}),
|
|
884
|
+
);
|
|
885
|
+
|
|
886
|
+
let renderCount = 0;
|
|
887
|
+
|
|
888
|
+
const { rerender } = renderHook(
|
|
889
|
+
({ options }: { options?: { enabled?: boolean } }) => {
|
|
890
|
+
renderCount++;
|
|
891
|
+
return typedClient.useInfiniteQuery(
|
|
892
|
+
'GET /users/paginated',
|
|
893
|
+
{
|
|
894
|
+
initialPageParam: 1,
|
|
895
|
+
getNextPageParam: (lastPage) =>
|
|
896
|
+
lastPage.pagination.hasMore
|
|
897
|
+
? lastPage.pagination.page + 1
|
|
898
|
+
: undefined,
|
|
899
|
+
},
|
|
900
|
+
{ query: { limit: 10 }, ...options },
|
|
901
|
+
);
|
|
902
|
+
},
|
|
903
|
+
{
|
|
904
|
+
wrapper,
|
|
905
|
+
initialProps: { options: { enabled: true } },
|
|
906
|
+
},
|
|
907
|
+
);
|
|
908
|
+
|
|
909
|
+
await waitFor(() => {
|
|
910
|
+
expect(requestCount).toBe(1);
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
const initialRenderCount = renderCount;
|
|
914
|
+
|
|
915
|
+
// Rerender with a new options object that has the same values
|
|
916
|
+
rerender({ options: { enabled: true } });
|
|
917
|
+
|
|
918
|
+
// Give React time to potentially trigger re-renders
|
|
919
|
+
await act(async () => {
|
|
920
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// The API should not be called again because options haven't actually changed
|
|
924
|
+
expect(requestCount).toBe(1);
|
|
925
|
+
|
|
926
|
+
// Component should re-render due to props change, but React Query shouldn't refetch
|
|
927
|
+
expect(renderCount).toBeGreaterThan(initialRenderCount);
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
it('should handle pageParam changes correctly in infinite queries', async () => {
|
|
931
|
+
const typedClient = createTypedQueryClient<paths>({
|
|
932
|
+
baseURL: 'https://api.example.com',
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
// Track API calls using MSW request interception
|
|
936
|
+
let requestCount = 0;
|
|
937
|
+
const requestedPages: number[] = [];
|
|
938
|
+
const { server } = await import('./setup');
|
|
939
|
+
server.use(
|
|
940
|
+
http.get('https://api.example.com/users/paginated', ({ request }) => {
|
|
941
|
+
requestCount++;
|
|
942
|
+
const url = new URL(request.url);
|
|
943
|
+
const page = parseInt(url.searchParams.get('page') || '1', 10);
|
|
944
|
+
requestedPages.push(page);
|
|
945
|
+
|
|
946
|
+
return HttpResponse.json({
|
|
947
|
+
users: Array.from({ length: 10 }, (_, i) => ({
|
|
948
|
+
id: `user-${(page - 1) * 10 + i + 1}`,
|
|
949
|
+
name: `User ${(page - 1) * 10 + i + 1}`,
|
|
950
|
+
email: `user${(page - 1) * 10 + i + 1}@example.com`,
|
|
951
|
+
})),
|
|
952
|
+
pagination: {
|
|
953
|
+
page,
|
|
954
|
+
limit: 10,
|
|
955
|
+
total: 50,
|
|
956
|
+
hasMore: page < 3, // Reduced to avoid complexity
|
|
957
|
+
},
|
|
958
|
+
});
|
|
959
|
+
}),
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
const { result } = renderHook(
|
|
963
|
+
() =>
|
|
964
|
+
typedClient.useInfiniteQuery(
|
|
965
|
+
'GET /users/paginated',
|
|
966
|
+
{
|
|
967
|
+
initialPageParam: 1,
|
|
968
|
+
getNextPageParam: (lastPage) =>
|
|
969
|
+
lastPage.pagination.hasMore
|
|
970
|
+
? lastPage.pagination.page + 1
|
|
971
|
+
: undefined,
|
|
972
|
+
},
|
|
973
|
+
{ query: { limit: 10 } },
|
|
974
|
+
),
|
|
975
|
+
{ wrapper },
|
|
976
|
+
);
|
|
977
|
+
|
|
978
|
+
// Wait for initial load
|
|
979
|
+
await waitFor(() => {
|
|
980
|
+
expect(result.current.isSuccess).toBe(true);
|
|
981
|
+
expect(requestCount).toBe(1);
|
|
982
|
+
expect(requestedPages).toEqual([1]);
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
// Test the memoization by checking that multiple calls to fetchNextPage work
|
|
986
|
+
if (result.current.hasNextPage) {
|
|
987
|
+
await act(async () => {
|
|
988
|
+
await result.current.fetchNextPage();
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
await waitFor(() => {
|
|
992
|
+
expect(requestCount).toBe(2);
|
|
993
|
+
expect(requestedPages).toEqual([1, 2]);
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// Verify that pageParam changes trigger new requests
|
|
998
|
+
expect(requestCount).toBe(2);
|
|
999
|
+
expect(result.current.data?.pages).toBeDefined();
|
|
1000
|
+
expect(result.current.data?.pages.length).toBeGreaterThan(0);
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
1003
|
});
|