@@ -1238,3 +1238,233 @@ describe('useQueries with suspense', () => {
12381238 expect ( results ) . toEqual ( [ '1' , '2' , 'loading' ] )
12391239 } )
12401240} )
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