1- import { TimerListener } from '../listeners' ;
1+ import { ConstantListener , TimerListener } from '../listeners' ;
22import { Transition } from './transition' ;
33
4+ function flushPromises ( ) {
5+ return new Promise ( jest . requireActual ( 'timers' ) . setImmediate ) ;
6+ }
7+
48function coalesce ( value : number | undefined ) {
59 return value ?? 0 ;
610}
@@ -36,6 +40,8 @@ describe('Transition', () => {
3640
3741 // After 4 seconds (listener1 counter = 4, listener2 counter = 2)
3842 jest . advanceTimersByTime ( 4000 ) ;
43+ await flushPromises ( ) ;
44+
3945 await expect ( check ) . toHaveBeenCalledTimes ( 6 ) ;
4046 await expect ( onMismatch ) . toHaveBeenCalledTimes ( 5 ) ; // 4 for listener1, 2 for listener2. But last one matched
4147 await expect ( onMatch ) . toHaveBeenCalledTimes ( 1 ) ;
@@ -47,6 +53,8 @@ describe('Transition', () => {
4753
4854 // After 3 seconds (listener1 counter = 3, listener2 counter = 1)
4955 jest . advanceTimersByTime ( 3000 ) ;
56+ await flushPromises ( ) ;
57+
5058 await expect ( check ) . toHaveBeenCalledTimes ( 4 ) ;
5159 await expect ( onMismatch ) . toHaveBeenCalledTimes ( 4 ) ; // 3 for listener1, 1 for listener2
5260 await expect ( onMismatch ) . toHaveBeenCalledWith ( [ 3 , 1 ] ) ; // Last of failing values
@@ -56,8 +64,10 @@ describe('Transition', () => {
5664 it ( 'should stop calling callbacks after stopListening' , async ( ) => {
5765 await transition . startListening ( ) ;
5866
59- // After 2 seconds
67+ // After 3 seconds
6068 jest . advanceTimersByTime ( 3000 ) ;
69+ await flushPromises ( ) ;
70+
6171 await expect ( check ) . toHaveBeenCalledTimes ( 4 ) ;
6272 await expect ( onMismatch ) . toHaveBeenCalledTimes ( 4 ) ; // 3 for listener1, 1 for listener2
6373 await expect ( onMismatch ) . toHaveBeenCalledWith ( [ 3 , 1 ] ) ; // Example of checking values
@@ -91,6 +101,8 @@ describe('Transition', () => {
91101
92102 // After 2 seconds (listener1 counter = 2, listener2 counter = 1)
93103 jest . advanceTimersByTime ( 2000 ) ;
104+ await flushPromises ( ) ;
105+
94106 await expect ( onMatch ) . toHaveBeenCalledTimes ( 3 ) ; // Called for each state change
95107 await expect ( onMatch ) . toHaveBeenCalledWith ( [ 2 , 1 ] ) ;
96108 } ) ;
@@ -107,6 +119,44 @@ describe('Transition', () => {
107119 await expect ( onMatch ) . toHaveBeenCalledWith ( [ ] ) ;
108120 } ) ;
109121
122+ it ( 'should handle multiple simultaneous listener updates and call onMatch only once when it stops listeners' , async ( ) => {
123+ const listener1 = new ConstantListener ( 1000 ) ;
124+ const listener2 = new ConstantListener ( 2000 ) ;
125+ const transition = new Transition ( {
126+ listeners : [ listener1 , listener2 ] ,
127+ check,
128+ onMatch,
129+ onMismatch,
130+ } ) ;
131+ // Overload onMatch
132+ const stoppingOnMatch = jest . fn ( ( ) => {
133+ transition . stopListening ( ) ;
134+ } ) ;
135+ // @ts -expect-error overwriting a readonly property
136+ transition [ 'onMatch' ] = stoppingOnMatch ;
137+
138+ await transition . startListening ( ) ;
139+
140+ // Simulate rapid listener updates
141+ listener1 [ 'emit' ] ( 1 ) ;
142+ listener1 [ 'emit' ] ( 2 ) ;
143+ listener1 [ 'emit' ] ( 3 ) ;
144+ listener2 [ 'emit' ] ( 1 ) ;
145+ listener2 [ 'emit' ] ( 2 ) ; // This call should match. No more calls to anything after this
146+ listener2 [ 'emit' ] ( 2 ) ; // Since this event, transition doesn't call check more values
147+ listener2 [ 'emit' ] ( 2 ) ;
148+ listener1 [ 'emit' ] ( 3 ) ;
149+ listener1 [ 'emit' ] ( 3 ) ;
150+
151+ jest . runAllTimers ( ) ;
152+ await flushPromises ( ) ;
153+
154+ await expect ( check ) . toHaveBeenCalledTimes ( 5 ) ; // Check should only be called once for each queued values
155+ await expect ( onMismatch ) . toHaveBeenCalledTimes ( 4 ) ; // onMismatch should be called always until a match is found, but not more
156+ await expect ( stoppingOnMatch ) . toHaveBeenCalledTimes ( 1 ) ; // onMatch should only be called once
157+ await expect ( stoppingOnMatch ) . toHaveBeenCalledWith ( [ 3 , 2 ] ) ;
158+ } ) ;
159+
110160 afterEach ( async ( ) => {
111161 await transition . stopListening ( ) ;
112162 jest . useRealTimers ( ) ;
0 commit comments