import { act , fireEvent , screen } from '@testing-library/react' ; import React , { useState } from 'react' ; import useSWR from 'swr' ; import { sleep , nextTick as waitForNextTick , focusOn , renderWithConfig , createKey } from './utils' ; const focusWindow = ( ) => focusOn ( window ) ; describe ( 'useSWR - focus' , ( ) => { it ( 'should revalidate on focus by default' , async ( ) => { let value = 0 ; const key = createKey ( ) ; function Page ( ) { const { data } = useSWR ( key , ( ) => value ++ , { dedupingInterval : 0 } ) ; return < div > data : { data } < /div>; } renderWithConfig ( < Page />); screen . getByText ( 'data:' ) ; await screen . findByText ( 'data: 0' ) ; await waitForNextTick ( ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 1' ) ; } ) ; it ( "shouldn't revalidate on focus when revalidateOnFocus is false" , async ( ) => { let value = 0 ; const key = createKey ( ) ; function Page ( ) { const { data } = useSWR ( key , ( ) => value ++ , { dedupingInterval : 0 , revalidateOnFocus : false } ) ; return < div > data : { data } < /div>; } renderWithConfig ( < Page />); screen . getByText ( 'data:' ) ; await screen . findByText ( 'data: 0' ) ; await waitForNextTick ( ) ; await focusWindow ( ) ; screen . getByText ( 'data: 0' ) ; } ) ; it ( 'revalidateOnFocus should be stateful' , async ( ) => { let value = 0 ; const key = createKey ( ) ; function Page ( ) { const [ revalidateOnFocus , toggle ] = useState ( false ) ; const { data } = useSWR ( key , ( ) => value ++ , { dedupingInterval : 0 , revalidateOnFocus , focusThrottleInterval : 0 } ) ; return < div onClick = { ( ) => toggle ( s => ! s ) } > data : { data } < /div>; } renderWithConfig ( < Page />); screen . getByText ( 'data:' ) ; await screen . findByText ( 'data: 0' ) ; await waitForNextTick ( ) ; await focusWindow ( ) ; screen . getByText ( 'data: 0' ) ; fireEvent . click ( screen . getByText ( 'data: 0' ) ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 1' ) ; await waitForNextTick ( ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 2' ) ; await waitForNextTick ( ) ; fireEvent . click ( screen . getByText ( 'data: 2' ) ) ; await focusWindow ( ) ; screen . getByText ( 'data: 2' ) ; } ) ; it ( 'focusThrottleInterval should work' , async ( ) => { let value = 0 ; const key = createKey ( ) ; function Page ( ) { const { data } = useSWR ( key , ( ) => value ++ , { dedupingInterval : 0 , revalidateOnFocus : true , focusThrottleInterval : 50 } ) ; return < div > data : { data } < /div>; } renderWithConfig ( < Page />); screen . getByText ( 'data:' ) ; await screen . findByText ( 'data: 0' ) ; await waitForNextTick ( ) ; await focusWindow ( ) ; await act ( ( ) => sleep ( 20 ) ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 1' ) ; await act ( ( ) => sleep ( 100 ) ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 2' ) ; } ) ; it ( 'focusThrottleInterval should be stateful' , async ( ) => { let value = 0 ; const key = createKey ( ) ; function Page ( ) { const [ focusThrottleInterval , setInterval ] = useState ( 50 ) ; const { data } = useSWR ( key , ( ) => value ++ , { dedupingInterval : 0 , revalidateOnFocus : true , focusThrottleInterval } ) ; return < div onClick = { ( ) => setInterval ( s => s + 100 ) } > data : { data } < /div>; } renderWithConfig ( < Page />); screen . getByText ( 'data:' ) ; await screen . findByText ( 'data: 0' ) ; await waitForNextTick ( ) ; await focusWindow ( ) ; await act ( ( ) => sleep ( 100 ) ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 2' ) ; await waitForNextTick ( ) ; fireEvent . click ( screen . getByText ( 'data: 2' ) ) ; await act ( ( ) => sleep ( 100 ) ) ; await focusWindow ( ) ; await act ( ( ) => sleep ( 100 ) ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 3' ) ; await act ( ( ) => sleep ( 150 ) ) ; await focusWindow ( ) ; await act ( ( ) => sleep ( 150 ) ) ; await screen . findByText ( 'data: 4' ) ; } ) ; it ( 'should revalidate on focus even with custom cache' , async ( ) => { let value = 0 ; const key = createKey ( ) ; function Page ( ) { const { data } = useSWR ( key , ( ) => value ++ , { revalidateOnFocus : true , dedupingInterval : 0 } ) ; return < div > data : { data } < /div>; } renderWithConfig ( < Page />); screen . getByText ( 'data:' ) ; await screen . findByText ( 'data: 0' ) ; await waitForNextTick ( ) ; await focusWindow ( ) ; await screen . findByText ( 'data: 1' ) ; } ) ; it ( 'should not revalidate on focus when key changes in the same tick' , async ( ) => { const fetchLogs = [ ] ; function Page ( ) { const [ key , setKey ] = useState ( ( ) => createKey ( ) ) ; useSWR ( key , k => fetchLogs . push ( k ) , { revalidateOnFocus : true , dedupingInterval : 0 } ) ; return < div onClick = { ( ) => setKey ( createKey ( ) ) } > change key < /div>; } renderWithConfig ( < Page />); await waitForNextTick ( ) ; fireEvent . focus ( window ) ; fireEvent . click ( screen . getByText ( 'change key' ) ) ; await waitForNextTick ( ) ; expect ( fetchLogs . length ) . toBe ( 2 ) ; expect ( fetchLogs [ 0 ] ) . not . toEqual ( fetchLogs [ 1 ] ) ; } ) ; } ) ;