@@ -56,6 +56,7 @@ describe("setupActivityIdleWatcher", () => {
5656
5757 afterEach ( ( ) => {
5858 jest . clearAllMocks ( ) ;
59+ jest . restoreAllMocks ( ) ;
5960 jest . useRealTimers ( ) ;
6061 delete global . createjs ;
6162 delete global . debugLog ;
@@ -162,6 +163,58 @@ describe("setupActivityIdleWatcher", () => {
162163
163164 expect ( mockActivity . isAppIdle ) . toBe ( false ) ;
164165 expect ( global . createjs . Ticker . framerate ) . toBe ( 60 ) ;
166+ expect ( mockActivity . stageDirty ) . toBe ( true ) ;
167+ } ) ;
168+
169+ it ( "does not accumulate listeners or intervals when called twice" , ( ) => {
170+ setupActivityIdleWatcher ( mockActivity ) ;
171+ mockActivity . _initIdleWatcher ( ) ;
172+
173+ const firstListenerCount = mockActivity . addEventListener . mock . calls . length ;
174+ const firstInterval = mockActivity . _idleWatcherInterval ;
175+
176+ const clearIntervalSpy = jest . spyOn ( global , "clearInterval" ) ;
177+
178+ // Call _initIdleWatcher again (double init)
179+ mockActivity . _initIdleWatcher ( ) ;
180+
181+ // The old interval should have been cleared by _stopIdleWatcher
182+ expect ( clearIntervalSpy ) . toHaveBeenCalledWith ( firstInterval ) ;
183+
184+ // Listeners should be re-added, not accumulated
185+ // The second init should have removed old listeners then added new ones
186+ expect ( mockActivity . removeEventListener ) . toHaveBeenCalledWith (
187+ window ,
188+ "mousemove" ,
189+ expect . any ( Function )
190+ ) ;
191+ expect ( mockActivity . removeEventListener ) . toHaveBeenCalledWith (
192+ window ,
193+ "mousedown" ,
194+ expect . any ( Function )
195+ ) ;
196+ expect ( mockActivity . removeEventListener ) . toHaveBeenCalledWith (
197+ window ,
198+ "keydown" ,
199+ expect . any ( Function )
200+ ) ;
201+ expect ( mockActivity . removeEventListener ) . toHaveBeenCalledWith (
202+ window ,
203+ "touchstart" ,
204+ expect . any ( Function )
205+ ) ;
206+ expect ( mockActivity . removeEventListener ) . toHaveBeenCalledWith (
207+ window ,
208+ "wheel" ,
209+ expect . any ( Function )
210+ ) ;
211+
212+ // New interval should be a different handle
213+ expect ( mockActivity . _idleWatcherInterval ) . not . toBe ( firstInterval ) ;
214+
215+ // addEventListener should have been called same number of times each init
216+ // (5 listeners per init, so 10 total)
217+ expect ( mockActivity . addEventListener ) . toHaveBeenCalledTimes ( firstListenerCount * 2 ) ;
165218 } ) ;
166219 } ) ;
167220
@@ -240,6 +293,17 @@ describe("setupActivityIdleWatcher", () => {
240293 operation : "autoSave"
241294 } ) ;
242295 } ) ;
296+
297+ it ( "does not throw when saveLocally is null" , ( ) => {
298+ setupActivityIdleWatcher ( mockActivity ) ;
299+ mockActivity . saveLocally = null ;
300+ mockActivity . _initAutoSave ( ) ;
301+
302+ jest . advanceTimersByTime ( 5 * 60 * 1000 ) ;
303+
304+ // Should not crash and ErrorHandler should not be called
305+ expect ( global . ErrorHandler . recoverable ) . not . toHaveBeenCalled ( ) ;
306+ } ) ;
243307 } ) ;
244308
245309 describe ( "_stopAutoSave" , ( ) => {
0 commit comments