1717 *
1818 */
1919
20+ import assert from 'node:assert' ;
2021import { ReactElement } from 'react' ;
2122
2223import { render } from '@testing-library/react' ;
2324
2425import { usePrimaryModalState } from 'Components/Modals/PrimaryModal' ;
25- import { createFakeWallClock } from 'src/script/clock/fakeWallClock' ;
26+ import { createFakeWallClock , FakeWallClock } from 'src/script/clock/fakeWallClock' ;
2627import { MainViewModel } from 'src/script/view_model/MainViewModel' ;
2728import { t } from 'Util/LocalizerUtil' ;
29+ import { TIME_IN_MILLIS } from 'Util/TimeUtil' ;
2830
2931import { RootProvider } from '../../RootProvider' ;
3032import { ForceReloadModal } from './ForceReloadModal' ;
3133
3234interface ForceReloadModalTestContextValue {
3335 readonly doesApplicationNeedForceReload : boolean ;
3436 readonly reloadApplication : ( ) => void ;
37+ readonly wallClock ?: FakeWallClock ;
3538}
3639
3740function isFeatureFlagDisabledForTest ( ) : boolean {
@@ -65,22 +68,28 @@ function resetPrimaryModalState(): void {
6568function createForceReloadModalTestElement (
6669 contextValue : ForceReloadModalTestContextValue ,
6770) : ReactElement {
68- const { doesApplicationNeedForceReload, reloadApplication} = contextValue ;
71+ const {
72+ doesApplicationNeedForceReload,
73+ reloadApplication,
74+ wallClock = createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 1_111 } ) ,
75+ } = contextValue ;
6976
7077 return (
7178 < RootProvider
7279 value = { {
7380 doesApplicationNeedForceReload,
7481 isFeatureFlagEnabled : isFeatureFlagDisabledForTest ,
7582 mainViewModel : createMainViewModelForTest ( ) ,
76- wallClock : createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 1_111 } ) ,
83+ wallClock,
7784 } }
7885 >
7986 < ForceReloadModal reloadApplication = { reloadApplication } />
8087 </ RootProvider >
8188 ) ;
8289}
8390
91+ const forceReloadDelayInMilliseconds = TIME_IN_MILLIS . SECOND * 60 ;
92+
8493describe ( 'ForceReloadModal' , ( ) => {
8594 beforeEach ( ( ) => {
8695 resetPrimaryModalState ( ) ;
@@ -94,32 +103,53 @@ describe('ForceReloadModal', () => {
94103 } ) ;
95104
96105 it ( 'opens the modal when force reload becomes required' , ( ) => {
106+ const fakeWallClock = createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 0 } ) ;
97107 const reloadApplication = jest . fn ( ) ;
98- const { rerender} = render ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : false , reloadApplication} ) ) ;
108+ const { rerender} = render (
109+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : false , reloadApplication, wallClock : fakeWallClock } ) ,
110+ ) ;
99111
100- rerender ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication} ) ) ;
112+ rerender (
113+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication, wallClock : fakeWallClock } ) ,
114+ ) ;
101115
102116 expect ( usePrimaryModalState . getState ( ) . currentModalId ) . not . toBeNull ( ) ;
103117 expect ( usePrimaryModalState . getState ( ) . queue ) . toHaveLength ( 0 ) ;
104118 } ) ;
105119
106120 it ( 'does not open the modal repeatedly while force reload remains required' , ( ) => {
121+ const fakeWallClock = createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 0 } ) ;
107122 const reloadApplication = jest . fn ( ) ;
108- const { rerender} = render ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication} ) ) ;
123+ const { rerender} = render (
124+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication, wallClock : fakeWallClock } ) ,
125+ ) ;
109126
110- rerender ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication} ) ) ;
111- rerender ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication} ) ) ;
127+ rerender (
128+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication, wallClock : fakeWallClock } ) ,
129+ ) ;
130+ rerender (
131+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication, wallClock : fakeWallClock } ) ,
132+ ) ;
112133
113134 expect ( usePrimaryModalState . getState ( ) . queue ) . toHaveLength ( 0 ) ;
114135 } ) ;
115136
116137 it ( 'opens the modal again after force reload status returns to false and then true' , ( ) => {
138+ const fakeWallClock = createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 0 } ) ;
117139 const reloadApplication = jest . fn ( ) ;
118- const { rerender} = render ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : false , reloadApplication} ) ) ;
119-
120- rerender ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication} ) ) ;
121- rerender ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : false , reloadApplication} ) ) ;
122- rerender ( createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication} ) ) ;
140+ const { rerender} = render (
141+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : false , reloadApplication, wallClock : fakeWallClock } ) ,
142+ ) ;
143+
144+ rerender (
145+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication, wallClock : fakeWallClock } ) ,
146+ ) ;
147+ rerender (
148+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : false , reloadApplication, wallClock : fakeWallClock } ) ,
149+ ) ;
150+ rerender (
151+ createForceReloadModalTestElement ( { doesApplicationNeedForceReload : true , reloadApplication, wallClock : fakeWallClock } ) ,
152+ ) ;
123153
124154 expect ( usePrimaryModalState . getState ( ) . currentModalId ) . not . toBeNull ( ) ;
125155 expect ( usePrimaryModalState . getState ( ) . queue ) . toHaveLength ( 1 ) ;
@@ -141,11 +171,82 @@ describe('ForceReloadModal', () => {
141171 currentModalContent . onBgClick ( ) ;
142172 expect ( usePrimaryModalState . getState ( ) . currentModalId ) . toBe ( currentModalIdentifierBeforeBackgroundClick ) ;
143173
144- if ( ! currentModalContent . primaryAction ?. action ) {
145- throw new Error ( 'Primary reload action is missing' ) ;
146- }
174+ assert ( currentModalContent . primaryAction ?. action ) ;
175+ currentModalContent . primaryAction . action ( ) ;
176+
177+ expect ( reloadApplication ) . toHaveBeenCalledTimes ( 1 ) ;
178+ } ) ;
179+
180+ it ( 'reloads automatically after 60 seconds when no user action is performed' , ( ) => {
181+ const fakeWallClock = createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 0 } ) ;
182+ const reloadApplication = jest . fn ( ) ;
183+
184+ render (
185+ createForceReloadModalTestElement ( {
186+ doesApplicationNeedForceReload : true ,
187+ reloadApplication,
188+ wallClock : fakeWallClock ,
189+ } ) ,
190+ ) ;
191+
192+ fakeWallClock . advanceByMilliseconds ( forceReloadDelayInMilliseconds - 1 ) ;
193+ expect ( reloadApplication ) . not . toHaveBeenCalled ( ) ;
194+
195+ fakeWallClock . advanceByMilliseconds ( 1 ) ;
196+ expect ( reloadApplication ) . toHaveBeenCalledTimes ( 1 ) ;
197+
198+ fakeWallClock . advanceByMilliseconds ( forceReloadDelayInMilliseconds ) ;
199+ expect ( reloadApplication ) . toHaveBeenCalledTimes ( 1 ) ;
200+ } ) ;
201+
202+ it ( 'cancels automatic reload if force reload requirement is removed before timeout' , ( ) => {
203+ const fakeWallClock = createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 0 } ) ;
204+ const reloadApplication = jest . fn ( ) ;
205+ const { rerender} = render (
206+ createForceReloadModalTestElement ( {
207+ doesApplicationNeedForceReload : false ,
208+ reloadApplication,
209+ wallClock : fakeWallClock ,
210+ } ) ,
211+ ) ;
212+
213+ rerender (
214+ createForceReloadModalTestElement ( {
215+ doesApplicationNeedForceReload : true ,
216+ reloadApplication,
217+ wallClock : fakeWallClock ,
218+ } ) ,
219+ ) ;
220+ rerender (
221+ createForceReloadModalTestElement ( {
222+ doesApplicationNeedForceReload : false ,
223+ reloadApplication,
224+ wallClock : fakeWallClock ,
225+ } ) ,
226+ ) ;
227+
228+ fakeWallClock . advanceByMilliseconds ( forceReloadDelayInMilliseconds ) ;
229+
230+ expect ( reloadApplication ) . not . toHaveBeenCalled ( ) ;
231+ } ) ;
232+
233+ it ( 'does not trigger reload twice if the user clicks reload before timeout' , ( ) => {
234+ const fakeWallClock = createFakeWallClock ( { initialCurrentTimestampInMilliseconds : 0 } ) ;
235+ const reloadApplication = jest . fn ( ) ;
236+
237+ render (
238+ createForceReloadModalTestElement ( {
239+ doesApplicationNeedForceReload : true ,
240+ reloadApplication,
241+ wallClock : fakeWallClock ,
242+ } ) ,
243+ ) ;
244+
245+ const { currentModalContent} = usePrimaryModalState . getState ( ) ;
147246
247+ assert ( currentModalContent . primaryAction ?. action ) ;
148248 currentModalContent . primaryAction . action ( ) ;
249+ fakeWallClock . advanceByMilliseconds ( forceReloadDelayInMilliseconds ) ;
149250
150251 expect ( reloadApplication ) . toHaveBeenCalledTimes ( 1 ) ;
151252 } ) ;
0 commit comments