@@ -87,5 +87,41 @@ describe('element align', () => {
8787 jest . runAllTimers ( ) ;
8888 expect ( onAlign ) . toHaveBeenCalled ( ) ;
8989 } ) ;
90+
91+ it ( 'should switch to the correct align callback after starting the timers' , ( ) => {
92+ // This test case is tricky. An error occurs if the following things happen
93+ // exactly in this order:
94+ // * Render <Align> with `onAlign1`.
95+ // * The callback in useBuffer is queued using setTimeout, to trigger after
96+ // `monitorBufferTime` ms (which even when it's set to 0 is queued and
97+ // not synchronously executed).
98+ // * The onAlign prop is changed to `onAlign2`.
99+ // * The callback from useBuffer is called. The now correct onAlign
100+ // callback would be `onAlign2`, and `onAlign1` should not be called.
101+ // This changing of the prop in between a 0 ms timeout is extremely rare.
102+ // It does however occur more often in real-world applications with
103+ // react-component/trigger, when its requestAnimationFrame and this timeout
104+ // race against each other.
105+
106+ const onAlign1 = jest . fn ( ) ;
107+ const onAlign2 = jest . fn ( ) ;
108+
109+ const wrapper = mount ( < Test onAlign = { onAlign1 } /> ) ;
110+
111+ // Make sure the initial render's call to onAlign does not matter.
112+ onAlign1 . mockReset ( ) ;
113+ onAlign2 . mockReset ( ) ;
114+
115+ // Re-render the component with the new callback. Expect from here on all
116+ // callbacks to call the new onAlign2.
117+ wrapper . setProps ( { onAlign : onAlign2 } ) ;
118+
119+ // Now the timeout is executed, and we expect the onAlign2 callback to
120+ // receive the call, not onAlign1.
121+ jest . runAllTimers ( ) ;
122+
123+ expect ( onAlign1 ) . not . toHaveBeenCalled ( ) ;
124+ expect ( onAlign2 ) . toHaveBeenCalled ( ) ;
125+ } ) ;
90126} ) ;
91127/* eslint-enable */
0 commit comments