@@ -2723,6 +2723,111 @@ describe('useQuery', () => {
27232723 consoleMock . mockRestore ( )
27242724 } )
27252725
2726+ it ( 'should continue retries when observers unmount and remount while waiting for a retry (#3031)' , async ( ) => {
2727+ const key = queryKey ( )
2728+ const consoleMock = mockConsoleError ( )
2729+ let count = 0
2730+
2731+ function Page ( ) {
2732+ const result = useQuery (
2733+ key ,
2734+ async ( ) => {
2735+ count ++
2736+ await sleep ( 10 )
2737+ return Promise . reject ( 'some error' )
2738+ } ,
2739+ {
2740+ retry : 2 ,
2741+ retryDelay : 100 ,
2742+ }
2743+ )
2744+
2745+ return (
2746+ < div >
2747+ < div > error: { result . error ?? 'null' } </ div >
2748+ < div > failureCount: { result . failureCount } </ div >
2749+ </ div >
2750+ )
2751+ }
2752+
2753+ function App ( ) {
2754+ const [ show , toggle ] = React . useReducer ( x => ! x , true )
2755+
2756+ return (
2757+ < div >
2758+ < button onClick = { toggle } > { show ? 'hide' : 'show' } </ button >
2759+ { show && < Page /> }
2760+ </ div >
2761+ )
2762+ }
2763+
2764+ const rendered = renderWithClient ( queryClient , < App /> )
2765+
2766+ await waitFor ( ( ) => rendered . getByText ( 'failureCount: 1' ) )
2767+ rendered . getByRole ( 'button' , { name : / h i d e / i } ) . click ( )
2768+ rendered . getByRole ( 'button' , { name : / s h o w / i } ) . click ( )
2769+ await waitFor ( ( ) => rendered . getByText ( 'error: some error' ) )
2770+
2771+ expect ( count ) . toBe ( 3 )
2772+
2773+ consoleMock . mockRestore ( )
2774+ } )
2775+
2776+ it ( 'should restart when observers unmount and remount while waiting for a retry when query was cancelled in between (#3031)' , async ( ) => {
2777+ const key = queryKey ( )
2778+ const consoleMock = mockConsoleError ( )
2779+ let count = 0
2780+
2781+ function Page ( ) {
2782+ const result = useQuery (
2783+ key ,
2784+ async ( ) => {
2785+ count ++
2786+ await sleep ( 10 )
2787+ return Promise . reject ( 'some error' )
2788+ } ,
2789+ {
2790+ retry : 2 ,
2791+ retryDelay : 100 ,
2792+ }
2793+ )
2794+
2795+ return (
2796+ < div >
2797+ < div > error: { result . error ?? 'null' } </ div >
2798+ < div > failureCount: { result . failureCount } </ div >
2799+ </ div >
2800+ )
2801+ }
2802+
2803+ function App ( ) {
2804+ const [ show , toggle ] = React . useReducer ( x => ! x , true )
2805+
2806+ return (
2807+ < div >
2808+ < button onClick = { toggle } > { show ? 'hide' : 'show' } </ button >
2809+ < button onClick = { ( ) => queryClient . cancelQueries ( { queryKey : key } ) } >
2810+ cancel
2811+ </ button >
2812+ { show && < Page /> }
2813+ </ div >
2814+ )
2815+ }
2816+
2817+ const rendered = renderWithClient ( queryClient , < App /> )
2818+
2819+ await waitFor ( ( ) => rendered . getByText ( 'failureCount: 1' ) )
2820+ rendered . getByRole ( 'button' , { name : / h i d e / i } ) . click ( )
2821+ rendered . getByRole ( 'button' , { name : / c a n c e l / i } ) . click ( )
2822+ rendered . getByRole ( 'button' , { name : / s h o w / i } ) . click ( )
2823+ await waitFor ( ( ) => rendered . getByText ( 'error: some error' ) )
2824+
2825+ // initial fetch (1), which will be cancelled, followed by new mount(2) + 2 retries = 4
2826+ expect ( count ) . toBe ( 4 )
2827+
2828+ consoleMock . mockRestore ( )
2829+ } )
2830+
27262831 it ( 'should always fetch if refetchOnMount is set to always' , async ( ) => {
27272832 const key = queryKey ( )
27282833 const states : UseQueryResult < string > [ ] = [ ]
0 commit comments