77} from "@testing-library/react-render-stream" ;
88import { userEvent } from "@testing-library/user-event" ;
99import React , { Suspense } from "react" ;
10+ import { flushSync } from "react-dom" ;
1011import { ErrorBoundary } from "react-error-boundary" ;
1112import { delay , of } from "rxjs" ;
1213
@@ -69,11 +70,16 @@ async function renderHook<
6970 return null ;
7071 }
7172
73+ type RefetchFunction = useLoadableQuery . Handlers <
74+ TData ,
75+ TVariables
76+ > [ "refetch" ] ;
77+
7278 function App ( { props } : { props : Props | undefined } ) {
7379 useTrackRenders ( { name : "useLoadableQuery" } ) ;
74- const [ loadQuery , queryRef ] = renderHookImpl ( props as any ) ;
80+ const [ loadQuery , queryRef , { refetch } ] = renderHookImpl ( props as any ) ;
7581
76- mergeSnapshot ( { loadQuery } ) ;
82+ mergeSnapshot ( { loadQuery, refetch } ) ;
7783
7884 return (
7985 < Suspense fallback = { < SuspenseFallback /> } >
@@ -96,10 +102,15 @@ async function renderHook<
96102 } = createRenderStream <
97103 | {
98104 loadQuery : useLoadableQuery . LoadQueryFunction < TVariables > ;
105+ refetch : RefetchFunction ;
99106 result ?: useReadQuery . Result < TData , TStates > ;
100107 }
101108 | { error : ErrorLike }
102- > ( { initialSnapshot : { loadQuery : null as any } } ) ;
109+ > ( {
110+ // These values should always be available, but createRenderStream needs an
111+ // initial snapshot when using mergeSnapshot so we provide it with something
112+ initialSnapshot : { loadQuery : null as any , refetch : null as any } ,
113+ } ) ;
103114
104115 const utils = await render ( < App props = { options . initialProps } /> , options ) ;
105116
@@ -117,7 +128,21 @@ async function renderHook<
117128 return snapshot ;
118129 }
119130
120- return { takeRender, rerender, getCurrentSnapshot } ;
131+ // React 18 skips committing the suspense fallback when loadQuery/refetch is
132+ // triggered as a default-priority update, so the fallback render is missed
133+ // and tests may fail. flushSync forces a synchronous commit so the fallback
134+ // renders in both React 18 and 19, while returning the underlying result.
135+ const loadQuery : useLoadableQuery . LoadQueryFunction < TVariables > = (
136+ ...args
137+ ) => {
138+ return flushSync ( ( ) => getCurrentSnapshot ( ) . loadQuery ( ...args ) ) ;
139+ } ;
140+
141+ const refetch : RefetchFunction = ( ...args ) => {
142+ return flushSync ( ( ) => getCurrentSnapshot ( ) . refetch ( ...args ) ) ;
143+ } ;
144+
145+ return { takeRender, rerender, getCurrentSnapshot, refetch, loadQuery } ;
121146}
122147
123148test ( "serializes scalar variables used in field arguments" , async ( ) => {
@@ -452,15 +477,9 @@ test("preserves referential identity when refetching identical serialized scalar
452477 ) ,
453478 } ) ;
454479
455- let refetch ! : useLoadableQuery . Result [ "2" ] [ "refetch" ] ;
456-
457480 using _disabledAct = disableActEnvironment ( ) ;
458- const { takeRender, getCurrentSnapshot } = await renderHook (
459- ( ) => {
460- const result = useLoadableQuery ( query ) ;
461- refetch = result [ 2 ] . refetch ;
462- return result ;
463- } ,
481+ const { takeRender, refetch, loadQuery } = await renderHook (
482+ ( ) => useLoadableQuery ( query ) ,
464483 { wrapper : createClientWrapper ( client ) }
465484 ) ;
466485
@@ -470,7 +489,7 @@ test("preserves referential identity when refetching identical serialized scalar
470489 expect ( renderedComponents ) . toStrictEqual ( [ "useLoadableQuery" ] ) ;
471490 }
472491
473- getCurrentSnapshot ( ) . loadQuery ( ) ;
492+ loadQuery ( ) ;
474493
475494 {
476495 const { renderedComponents } = await takeRender ( ) ;
@@ -590,7 +609,7 @@ test("serializes scalar fields in the error with a `none` error policy", async (
590609 } ) ;
591610
592611 using _disabledAct = disableActEnvironment ( ) ;
593- const { takeRender, getCurrentSnapshot } = await renderHook (
612+ const { takeRender, loadQuery } = await renderHook (
594613 ( ) => useLoadableQuery ( query , { errorPolicy : "none" } ) ,
595614 { wrapper : createClientWrapper ( client ) }
596615 ) ;
@@ -601,7 +620,7 @@ test("serializes scalar fields in the error with a `none` error policy", async (
601620 expect ( renderedComponents ) . toStrictEqual ( [ "useLoadableQuery" ] ) ;
602621 }
603622
604- getCurrentSnapshot ( ) . loadQuery ( ) ;
623+ loadQuery ( ) ;
605624
606625 {
607626 const { renderedComponents } = await takeRender ( ) ;
@@ -682,7 +701,7 @@ test("parses scalar fields in the result and serializes them in the error with a
682701 } ) ;
683702
684703 using _disabledAct = disableActEnvironment ( ) ;
685- const { takeRender, getCurrentSnapshot } = await renderHook (
704+ const { takeRender, loadQuery } = await renderHook (
686705 ( ) => useLoadableQuery ( query , { errorPolicy : "all" } ) ,
687706 { wrapper : createClientWrapper ( client ) }
688707 ) ;
@@ -693,7 +712,7 @@ test("parses scalar fields in the result and serializes them in the error with a
693712 expect ( renderedComponents ) . toStrictEqual ( [ "useLoadableQuery" ] ) ;
694713 }
695714
696- getCurrentSnapshot ( ) . loadQuery ( ) ;
715+ loadQuery ( ) ;
697716
698717 {
699718 const { renderedComponents } = await takeRender ( ) ;
@@ -786,7 +805,7 @@ test("parses custom scalar fields with an `ignore` error policy", async () => {
786805 } ) ;
787806
788807 using _disabledAct = disableActEnvironment ( ) ;
789- const { takeRender, getCurrentSnapshot } = await renderHook (
808+ const { takeRender, loadQuery } = await renderHook (
790809 ( ) => useLoadableQuery ( query , { errorPolicy : "ignore" } ) ,
791810 { wrapper : createClientWrapper ( client ) }
792811 ) ;
@@ -797,7 +816,7 @@ test("parses custom scalar fields with an `ignore` error policy", async () => {
797816 expect ( renderedComponents ) . toStrictEqual ( [ "useLoadableQuery" ] ) ;
798817 }
799818
800- getCurrentSnapshot ( ) . loadQuery ( ) ;
819+ loadQuery ( ) ;
801820
802821 {
803822 const { renderedComponents } = await takeRender ( ) ;
0 commit comments