1
1
import set from 'lodash/set'
2
- import { waitFor } from '@testing-library/react'
3
- import { startActivityMonitor , stopActivityMonitor } from 'uiSrc/components/main-router/activityMonitor'
2
+ import { renderHook } from '@testing-library/react-hooks'
4
3
import { getConfig } from 'uiSrc/config'
4
+ import { mockWindowLocation } from 'uiSrc/utils/test-utils'
5
+ import { useActivityMonitor } from './useActivityMonitor'
5
6
6
7
const addEventListenerSpy = jest . spyOn ( window , 'addEventListener' )
7
8
const removeEventListenerSpy = jest . spyOn ( window , 'removeEventListener' )
@@ -21,67 +22,136 @@ const mockWindowOpener = (postMessage = jest.fn()) => {
21
22
}
22
23
}
23
24
25
+ jest . useFakeTimers ( )
26
+
27
+ const browserUrl = 'http://localhost/123/browser'
28
+ const logoutUrl = 'http://localhost/#/logout'
29
+
30
+ let setHrefMock : typeof jest . fn
24
31
beforeEach ( ( ) => {
25
32
jest . resetAllMocks ( )
33
+
34
+ const mockDate = new Date ( '2024-11-22T12:00:00Z' )
35
+ jest . setSystemTime ( mockDate )
36
+
26
37
mockConfig ( )
38
+ setHrefMock = mockWindowLocation ( browserUrl )
27
39
mockWindowOpener ( )
28
40
} )
29
41
30
- describe ( 'Activity monitor' , ( ) => {
31
- it ( 'should start and stop activity monitor if window.opener and monitor origin are defined' , ( ) => {
32
- startActivityMonitor ( )
42
+ describe ( 'useActivityMonitor' , ( ) => {
43
+ it ( 'should register event handlers on mount and unregister on unmount' , ( ) => {
44
+ const { unmount } = renderHook ( useActivityMonitor )
45
+
46
+ // Verify mount behavior
33
47
expect ( addEventListenerSpy ) . toHaveBeenCalledTimes ( 4 )
34
48
expect ( addEventListenerSpy ) . toHaveBeenNthCalledWith ( 1 , 'click' , expect . any ( Function ) , addEventListenerProps )
35
49
expect ( addEventListenerSpy ) . toHaveBeenNthCalledWith ( 2 , 'keydown' , expect . any ( Function ) , addEventListenerProps )
36
50
expect ( addEventListenerSpy ) . toHaveBeenNthCalledWith ( 3 , 'scroll' , expect . any ( Function ) , addEventListenerProps )
37
51
expect ( addEventListenerSpy ) . toHaveBeenNthCalledWith ( 4 , 'touchstart' , expect . any ( Function ) , addEventListenerProps )
38
52
39
- stopActivityMonitor ( )
53
+ // Trigger unmount
54
+ unmount ( )
55
+
56
+ // Verify unmount behavior
40
57
expect ( removeEventListenerSpy ) . toHaveBeenCalledTimes ( 4 )
41
58
expect ( removeEventListenerSpy ) . toHaveBeenNthCalledWith ( 1 , 'click' , expect . any ( Function ) , removeEventListenerProps )
42
59
expect ( removeEventListenerSpy ) . toHaveBeenNthCalledWith ( 2 , 'keydown' , expect . any ( Function ) , removeEventListenerProps )
43
60
expect ( removeEventListenerSpy ) . toHaveBeenNthCalledWith ( 3 , 'scroll' , expect . any ( Function ) , removeEventListenerProps )
44
61
expect ( removeEventListenerSpy ) . toHaveBeenNthCalledWith ( 4 , 'touchstart' , expect . any ( Function ) , removeEventListenerProps )
45
62
} )
46
63
47
- it ( 'should not start or stop activity monitor if window.opener is undefined' , ( ) => {
64
+ it ( 'should register event handlers even if window.opener is undefined' , ( ) => {
48
65
global . window . opener = undefined
49
66
50
- startActivityMonitor ( )
51
- stopActivityMonitor ( )
67
+ const { unmount } = renderHook ( useActivityMonitor )
52
68
53
- expect ( addEventListenerSpy ) . not . toHaveBeenCalled ( )
54
- expect ( removeEventListenerSpy ) . not . toHaveBeenCalled ( )
69
+ // Verify mount behavior
70
+ expect ( addEventListenerSpy ) . toHaveBeenCalledTimes ( 4 )
71
+
72
+ // Trigger unmount
73
+ unmount ( )
74
+
75
+ // Verify unmount behavior
76
+ expect ( removeEventListenerSpy ) . toHaveBeenCalledTimes ( 4 )
55
77
} )
56
78
57
- it ( 'should not start or stop activity monitor if monitor origin is falsey ' , ( ) => {
79
+ it ( 'should not register handlers if activityMonitorOrigin is not defined ' , ( ) => {
58
80
mockConfig ( '' )
59
81
60
- startActivityMonitor ( )
61
- stopActivityMonitor ( )
82
+ const { unmount } = renderHook ( useActivityMonitor )
62
83
84
+ // Verify mount behavior
63
85
expect ( addEventListenerSpy ) . not . toHaveBeenCalled ( )
86
+
87
+ // Trigger unmount
88
+ unmount ( )
89
+
90
+ // Verify unmount behavior
64
91
expect ( removeEventListenerSpy ) . not . toHaveBeenCalled ( )
65
92
} )
66
93
94
+ it ( 'should logout user after expected amount of inactivity' , async ( ) => {
95
+ renderHook ( useActivityMonitor )
96
+ jest . advanceTimersByTime ( 1900 * 1000 )
97
+ expect ( setHrefMock ) . toHaveBeenCalledWith ( logoutUrl )
98
+ } )
99
+
100
+ it ( 'should not logout user if hook unmounts' , async ( ) => {
101
+ const { unmount } = renderHook ( useActivityMonitor )
102
+ jest . advanceTimersByTime ( 1700 * 1000 )
103
+ expect ( setHrefMock ) . not . toHaveBeenCalled ( )
104
+
105
+ unmount ( )
106
+
107
+ jest . advanceTimersByTime ( 1000 * 1000 )
108
+ expect ( setHrefMock ) . not . toHaveBeenCalled ( )
109
+ } )
110
+
111
+ it ( 'should keep user logged in if they stay active' , async ( ) => {
112
+ renderHook ( useActivityMonitor )
113
+
114
+ const activityHandler = addEventListenerSpy . mock . calls [ 0 ] ?. [ 1 ] as Function
115
+
116
+ // act
117
+ jest . advanceTimersByTime ( 1700 * 1000 )
118
+ activityHandler ( )
119
+ jest . advanceTimersByTime ( 1700 * 1000 )
120
+
121
+ // assert
122
+ expect ( setHrefMock ) . not . toHaveBeenCalled ( )
123
+
124
+ // act
125
+ activityHandler ( )
126
+ jest . advanceTimersByTime ( 1700 * 1000 )
127
+
128
+ // assert
129
+ expect ( setHrefMock ) . not . toHaveBeenCalled ( )
130
+
131
+ // act
132
+ jest . advanceTimersByTime ( 1000 * 1000 )
133
+
134
+ // assert
135
+ expect ( setHrefMock ) . toHaveBeenCalledWith ( logoutUrl )
136
+ } )
137
+
67
138
it ( 'should throttle events and call window.opener.postMessage' , async ( ) => {
68
139
const mockPostMessage = jest . fn ( )
69
140
70
141
mockWindowOpener ( mockPostMessage )
71
- startActivityMonitor ( )
142
+ renderHook ( useActivityMonitor )
72
143
73
- expect ( addEventListenerSpy ) . toHaveBeenCalledTimes ( 4 )
74
-
75
- // simulate events
144
+ // act
76
145
const activityHandler = addEventListenerSpy . mock . calls [ 0 ] ?. [ 1 ] as Function
77
146
activityHandler ( )
78
147
activityHandler ( )
79
148
activityHandler ( )
80
149
activityHandler ( )
81
150
82
- await waitFor ( ( ) => {
83
- expect ( mockPostMessage ) . toHaveBeenCalledTimes ( 1 )
84
- } )
151
+ jest . advanceTimersByTime ( 20_000 )
152
+
153
+ // assert
154
+ expect ( mockPostMessage ) . toHaveBeenCalledTimes ( 1 )
85
155
} )
86
156
87
157
it ( 'should ignore errors from activity handler function' , async ( ) => {
@@ -90,7 +160,7 @@ describe('Activity monitor', () => {
90
160
} )
91
161
92
162
mockWindowOpener ( mockPostMessage )
93
- startActivityMonitor ( )
163
+ renderHook ( useActivityMonitor )
94
164
95
165
expect ( addEventListenerSpy ) . toHaveBeenCalledTimes ( 4 )
96
166
@@ -106,7 +176,7 @@ describe('Activity monitor', () => {
106
176
107
177
mockWindowOpener ( )
108
178
109
- expect ( startActivityMonitor ) . not . toThrow ( )
179
+ expect ( ( ) => renderHook ( useActivityMonitor ) ) . not . toThrow ( )
110
180
expect ( addEventListenerSpy ) . toHaveBeenCalledTimes ( 1 )
111
181
} )
112
182
} )
0 commit comments