@@ -1238,3 +1238,233 @@ describe('useQueries with suspense', () => {
1238
1238
expect ( results ) . toEqual ( [ '1' , '2' , 'loading' ] )
1239
1239
} )
1240
1240
} )
1241
+
1242
+ describe ( 'cacheTime minimum enforcement with suspense' , ( ) => {
1243
+ const queryClient = createQueryClient ( )
1244
+
1245
+ it ( 'should not cause infinite re-renders with synchronous query function and cacheTime: 0' , async ( ) => {
1246
+ const key = queryKey ( )
1247
+ let renderCount = 0
1248
+ let queryFnCallCount = 0
1249
+ const maxChecks = 20
1250
+
1251
+ function Page ( ) {
1252
+ renderCount ++
1253
+
1254
+ if ( renderCount > maxChecks ) {
1255
+ throw new Error ( `Infinite loop detected! Renders: ${ renderCount } ` )
1256
+ }
1257
+
1258
+ const result = useQuery (
1259
+ key ,
1260
+ ( ) => {
1261
+ queryFnCallCount ++
1262
+ return 42
1263
+ } ,
1264
+ {
1265
+ cacheTime : 0 ,
1266
+ suspense : true ,
1267
+ } ,
1268
+ )
1269
+
1270
+ return < div > data: { result . data } </ div >
1271
+ }
1272
+
1273
+ const rendered = renderWithClient (
1274
+ queryClient ,
1275
+ < React . Suspense fallback = "loading" >
1276
+ < Page />
1277
+ </ React . Suspense > ,
1278
+ )
1279
+
1280
+ await waitFor ( ( ) => rendered . getByText ( 'data: 42' ) )
1281
+
1282
+ expect ( renderCount ) . toBeLessThan ( 5 )
1283
+ expect ( queryFnCallCount ) . toBe ( 1 )
1284
+ expect ( rendered . queryByText ( 'data: 42' ) ) . not . toBeNull ( )
1285
+ expect ( rendered . queryByText ( 'loading' ) ) . toBeNull ( )
1286
+ } )
1287
+
1288
+ describe ( 'boundary value tests' , ( ) => {
1289
+ test . each ( [
1290
+ [ 0 , 1000 ] ,
1291
+ [ 1 , 1000 ] ,
1292
+ [ 999 , 1000 ] ,
1293
+ [ 1000 , 1000 ] ,
1294
+ [ 2000 , 2000 ] ,
1295
+ ] ) (
1296
+ 'cacheTime %i should be adjusted to %i with suspense' ,
1297
+ async ( input , expected ) => {
1298
+ const key = queryKey ( )
1299
+
1300
+ function Page ( ) {
1301
+ const result = useQuery ( key , ( ) => 42 , {
1302
+ suspense : true ,
1303
+ cacheTime : input ,
1304
+ } )
1305
+ return < div > data: { result . data } </ div >
1306
+ }
1307
+
1308
+ const rendered = renderWithClient (
1309
+ queryClient ,
1310
+ < React . Suspense fallback = "loading" >
1311
+ < Page />
1312
+ </ React . Suspense > ,
1313
+ )
1314
+
1315
+ await waitFor ( ( ) => rendered . getByText ( 'data: 42' ) )
1316
+
1317
+ const query = queryClient . getQueryCache ( ) . find ( key )
1318
+ const options = query ?. options
1319
+ expect ( options ?. cacheTime ) . toBe ( expected )
1320
+ } ,
1321
+ )
1322
+ } )
1323
+
1324
+ it ( 'should preserve user cacheTime when >= 1000ms' , async ( ) => {
1325
+ const key = queryKey ( )
1326
+ const userCacheTime = 5000
1327
+
1328
+ function Page ( ) {
1329
+ useQuery ( key , ( ) => 'test' , {
1330
+ suspense : true ,
1331
+ cacheTime : userCacheTime ,
1332
+ } )
1333
+ return < div > rendered</ div >
1334
+ }
1335
+
1336
+ renderWithClient (
1337
+ queryClient ,
1338
+ < React . Suspense fallback = "loading" >
1339
+ < Page />
1340
+ </ React . Suspense > ,
1341
+ )
1342
+
1343
+ await waitFor ( ( ) => {
1344
+ const query = queryClient . getQueryCache ( ) . find ( key )
1345
+ const options = query ?. options
1346
+ expect ( options ?. cacheTime ) . toBe ( userCacheTime )
1347
+ } )
1348
+ } )
1349
+
1350
+ it ( 'should handle async queries with adjusted cacheTime' , async ( ) => {
1351
+ const key = queryKey ( )
1352
+ let renderCount = 0
1353
+
1354
+ function Page ( ) {
1355
+ renderCount ++
1356
+ const result = useQuery (
1357
+ key ,
1358
+ async ( ) => {
1359
+ await sleep ( 10 )
1360
+ return 'async-result'
1361
+ } ,
1362
+ {
1363
+ suspense : true ,
1364
+ cacheTime : 0 ,
1365
+ } ,
1366
+ )
1367
+ return < div > data: { result . data } </ div >
1368
+ }
1369
+
1370
+ const rendered = renderWithClient (
1371
+ queryClient ,
1372
+ < React . Suspense fallback = "loading" >
1373
+ < Page />
1374
+ </ React . Suspense > ,
1375
+ )
1376
+
1377
+ await waitFor ( ( ) => rendered . getByText ( 'data: async-result' ) )
1378
+ expect ( renderCount ) . toBeLessThan ( 5 )
1379
+ } )
1380
+
1381
+ describe ( 'staleTime and cacheTime relationship' , ( ) => {
1382
+ it ( 'should handle when both need adjustment' , async ( ) => {
1383
+ const key = queryKey ( )
1384
+
1385
+ function Page ( ) {
1386
+ useQuery ( key , ( ) => 42 , {
1387
+ suspense : true ,
1388
+ cacheTime : 0 ,
1389
+ staleTime : undefined ,
1390
+ } )
1391
+ return < div > rendered</ div >
1392
+ }
1393
+
1394
+ renderWithClient (
1395
+ queryClient ,
1396
+ < React . Suspense fallback = "loading" >
1397
+ < Page />
1398
+ </ React . Suspense > ,
1399
+ )
1400
+
1401
+ await waitFor ( ( ) => {
1402
+ const query = queryClient . getQueryCache ( ) . find ( key )
1403
+ const options = query ?. options as any
1404
+ expect ( options ?. cacheTime ) . toBe ( 1000 )
1405
+ expect ( options ?. staleTime ) . toBe ( 1000 )
1406
+ } )
1407
+ } )
1408
+
1409
+ it ( 'should maintain staleTime < cacheTime invariant' , async ( ) => {
1410
+ const key = queryKey ( )
1411
+
1412
+ function Page ( ) {
1413
+ useQuery ( key , ( ) => 42 , {
1414
+ suspense : true ,
1415
+ cacheTime : 500 ,
1416
+ staleTime : 2000 ,
1417
+ } )
1418
+ return < div > rendered</ div >
1419
+ }
1420
+
1421
+ renderWithClient (
1422
+ queryClient ,
1423
+ < React . Suspense fallback = "loading" >
1424
+ < Page />
1425
+ </ React . Suspense > ,
1426
+ )
1427
+
1428
+ await waitFor ( ( ) => {
1429
+ const query = queryClient . getQueryCache ( ) . find ( key )
1430
+ const options = query ?. options as any
1431
+ expect ( options ?. cacheTime ) . toBe ( 1000 )
1432
+ expect ( options ?. staleTime ) . toBe ( 2000 )
1433
+ } )
1434
+ } )
1435
+ } )
1436
+
1437
+ it ( 'should fix synchronous query with cacheTime 0 infinite loop' , async ( ) => {
1438
+ const key = queryKey ( )
1439
+ let renderCount = 0
1440
+ let queryFnCallCount = 0
1441
+
1442
+ function Page ( ) {
1443
+ renderCount ++
1444
+ const result = useQuery (
1445
+ key ,
1446
+ ( ) => {
1447
+ queryFnCallCount ++
1448
+ return 42
1449
+ } ,
1450
+ {
1451
+ suspense : true ,
1452
+ cacheTime : 0 ,
1453
+ } ,
1454
+ )
1455
+ return < div > data: { result . data } </ div >
1456
+ }
1457
+
1458
+ const rendered = renderWithClient (
1459
+ queryClient ,
1460
+ < React . Suspense fallback = "loading" >
1461
+ < Page />
1462
+ </ React . Suspense > ,
1463
+ )
1464
+
1465
+ await waitFor ( ( ) => rendered . getByText ( 'data: 42' ) )
1466
+
1467
+ expect ( renderCount ) . toBeLessThan ( 5 )
1468
+ expect ( queryFnCallCount ) . toBe ( 1 )
1469
+ } )
1470
+ } )
0 commit comments