@@ -2,6 +2,8 @@ import { renderHook, act } from '@testing-library/react-hooks';
22import { TestUtils } from '@deephaven/utils' ;
33import useAsyncInterval from './useAsyncInterval' ;
44
5+ const { asMock } = TestUtils ;
6+
57beforeEach ( ( ) => {
68 jest . clearAllMocks ( ) ;
79 expect . hasAssertions ( ) ;
@@ -15,31 +17,50 @@ afterAll(() => {
1517
1618describe ( 'useAsyncInterval' , ( ) => {
1719 function createCallback ( ms : number ) {
18- return jest . fn (
19- async ( ) : Promise < void > =>
20- new Promise ( resolve => {
21- setTimeout ( resolve , ms ) ;
22- } )
23- ) ;
20+ return jest
21+ . fn (
22+ async ( ) : Promise < void > =>
23+ new Promise ( resolve => {
24+ setTimeout ( resolve , ms ) ;
25+
26+ // Don't track the above call to `setTimeout`
27+ asMock ( setTimeout ) . mock . calls . pop ( ) ;
28+ } )
29+ )
30+ . mockName ( 'callback' ) ;
2431 }
2532
2633 const targetIntervalMs = 1000 ;
2734
28- it ( 'should call the callback function after the target interval' , async ( ) => {
29- const callback = createCallback ( 50 ) ;
35+ it ( 'should call the callback function immediately any time the callback or target interval changes' , ( ) => {
36+ const callbackA = createCallback ( 50 ) ;
37+ const callbackB = createCallback ( 50 ) ;
3038
31- renderHook ( ( ) => useAsyncInterval ( callback , targetIntervalMs ) ) ;
32-
33- // First tick should be scheduled for target interval
34- expect ( callback ) . not . toHaveBeenCalled ( ) ;
35- expect ( window . setTimeout ) . toHaveBeenCalledWith (
36- expect . any ( Function ) ,
37- targetIntervalMs
39+ const { rerender } = renderHook (
40+ ( [ cb , target ] : [ ( ) => Promise < void > , number ] ) =>
41+ useAsyncInterval ( cb , target ) ,
42+ {
43+ initialProps : [ callbackA , targetIntervalMs ] ,
44+ }
3845 ) ;
3946
40- // Callback should be called after target interval
41- act ( ( ) => jest . advanceTimersByTime ( targetIntervalMs ) ) ;
42- expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
47+ expect ( callbackA ) . toHaveBeenCalledTimes ( 1 ) ;
48+ jest . clearAllMocks ( ) ;
49+
50+ // Should not call callback if depedencies don't change
51+ rerender ( [ callbackA , targetIntervalMs ] ) ;
52+ expect ( callbackA ) . not . toHaveBeenCalled ( ) ;
53+ jest . clearAllMocks ( ) ;
54+
55+ // Callback change
56+ rerender ( [ callbackB , targetIntervalMs ] ) ;
57+ expect ( callbackA ) . not . toHaveBeenCalled ( ) ;
58+ expect ( callbackB ) . toHaveBeenCalledTimes ( 1 ) ;
59+ jest . clearAllMocks ( ) ;
60+
61+ // Interval change
62+ rerender ( [ callbackB , targetIntervalMs + 20 ] ) ;
63+ expect ( callbackB ) . toHaveBeenCalledTimes ( 1 ) ;
4364 } ) ;
4465
4566 it ( 'should adjust the target interval based on how long async call takes' , async ( ) => {
@@ -48,11 +69,8 @@ describe('useAsyncInterval', () => {
4869
4970 renderHook ( ( ) => useAsyncInterval ( callback , targetIntervalMs ) ) ;
5071
51- // Callback should be called after target interval
52- expect ( callback ) . not . toHaveBeenCalled ( ) ;
53- act ( ( ) => jest . advanceTimersByTime ( targetIntervalMs ) ) ;
5472 expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
55-
73+ expect ( window . setTimeout ) . not . toHaveBeenCalled ( ) ;
5674 jest . clearAllMocks ( ) ;
5775
5876 // Mimick the callback Promise resolving
@@ -79,11 +97,7 @@ describe('useAsyncInterval', () => {
7997
8098 renderHook ( ( ) => useAsyncInterval ( callback , targetIntervalMs ) ) ;
8199
82- // Callback should be called after target interval
83- expect ( callback ) . not . toHaveBeenCalled ( ) ;
84- act ( ( ) => jest . advanceTimersByTime ( targetIntervalMs ) ) ;
85100 expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
86-
87101 jest . clearAllMocks ( ) ;
88102
89103 // Mimick the callback Promise resolving
@@ -99,12 +113,22 @@ describe('useAsyncInterval', () => {
99113 } ) ;
100114
101115 it ( 'should stop calling the callback function after unmounting' , async ( ) => {
102- const callback = createCallback ( 50 ) ;
116+ const callbackDelayMs = 50 ;
117+ const callback = createCallback ( callbackDelayMs ) ;
103118
104119 const { unmount } = renderHook ( ( ) =>
105120 useAsyncInterval ( callback , targetIntervalMs )
106121 ) ;
107122
123+ expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
124+ jest . clearAllMocks ( ) ;
125+
126+ // Mimick the callback Promise resolving
127+ act ( ( ) => jest . advanceTimersByTime ( callbackDelayMs ) ) ;
128+ await TestUtils . flushPromises ( ) ;
129+
130+ expect ( window . setTimeout ) . toHaveBeenCalledTimes ( 1 ) ;
131+
108132 unmount ( ) ;
109133
110134 act ( ( ) => jest . advanceTimersByTime ( targetIntervalMs ) ) ;
@@ -120,7 +144,6 @@ describe('useAsyncInterval', () => {
120144 useAsyncInterval ( callback , targetIntervalMs )
121145 ) ;
122146
123- act ( ( ) => jest . advanceTimersByTime ( targetIntervalMs ) ) ;
124147 expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
125148 jest . clearAllMocks ( ) ;
126149
0 commit comments