1+ import ForegroundTimeTracker from '../../src/foregroundTimeTracker' ;
2+
3+ describe ( 'ForegroundTimeTracker' , ( ) => {
4+ let foregroundTimeTracker : ForegroundTimeTracker ;
5+ const apiKey = 'test-key' ;
6+ const mockStorageKey = `mp-time-${ apiKey } ` ;
7+
8+ beforeEach ( ( ) => {
9+ Object . defineProperty ( document , 'hidden' , { value : false , configurable : true } ) ;
10+ jest . useFakeTimers ( ) ;
11+ localStorage . clear ( ) ;
12+ } ) ;
13+
14+ afterEach ( ( ) => {
15+ jest . clearAllTimers ( ) ;
16+ jest . restoreAllMocks ( ) ;
17+ } ) ;
18+
19+ // in Jest, document.hidden by default is false
20+ it ( 'should initialize with correct localStorage key' , ( ) => {
21+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
22+ expect ( foregroundTimeTracker [ 'localStorageName' ] ) . toBe ( mockStorageKey ) ;
23+ } ) ;
24+
25+ it ( 'should load time from localStorage on initialization' , ( ) => {
26+ localStorage . setItem ( mockStorageKey , '1000' ) ;
27+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
28+ expect ( foregroundTimeTracker [ 'totalTime' ] ) . toBe ( 1000 ) ;
29+ } ) ;
30+
31+ it ( 'should start tracking when the page is visible' , ( ) => {
32+ Object . defineProperty ( document , 'hidden' , { value : false , configurable : true } ) ;
33+ jest . spyOn ( global . performance , 'now' )
34+ . mockReturnValueOnce ( 1000 ) ;
35+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
36+
37+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( true ) ;
38+ expect ( foregroundTimeTracker [ 'startTime' ] ) . toBe ( 1000 ) ;
39+ } ) ;
40+
41+ it ( 'should not start tracking if the page is hidden' , ( ) => {
42+ Object . defineProperty ( document , 'hidden' , { value : true } ) ;
43+ jest . spyOn ( global . performance , 'now' )
44+ . mockReturnValueOnce ( 1000 ) ;
45+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
46+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( false ) ;
47+
48+ // since the page is hidden, it does not call performance.now
49+ expect ( foregroundTimeTracker [ 'startTime' ] ) . toBe ( 0 ) ;
50+ } ) ;
51+
52+ it ( 'should stop tracking when the page becomes hidden' , ( ) => {
53+ jest . spyOn ( global . performance , 'now' )
54+ . mockReturnValueOnce ( 1000 )
55+ . mockReturnValueOnce ( 2000 )
56+ . mockReturnValueOnce ( 3000 ) ;
57+
58+ Object . defineProperty ( document , 'hidden' , { value : false , configurable : true } ) ;
59+
60+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
61+
62+ expect ( foregroundTimeTracker [ 'totalTime' ] ) . toBe ( 0 ) ;
63+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( true ) ;
64+ foregroundTimeTracker [ 'handleVisibilityChange' ] ( ) ;
65+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( true ) ;
66+
67+ Object . defineProperty ( document , 'hidden' , { value : true , configurable : true } ) ;
68+ foregroundTimeTracker [ 'handleVisibilityChange' ] ( ) ;
69+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( false ) ;
70+ } ) ;
71+
72+ it ( 'should resume tracking when the page becomes visible again' , ( ) => {
73+ Object . defineProperty ( document , 'hidden' , { value : false , configurable : true } ) ;
74+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
75+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( true ) ;
76+
77+ Object . defineProperty ( document , 'hidden' , { value : true , configurable : true } ) ;
78+ foregroundTimeTracker [ 'handleVisibilityChange' ] ( ) ;
79+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( false ) ;
80+
81+ Object . defineProperty ( document , 'hidden' , { value : false , configurable : true } ) ;
82+ foregroundTimeTracker [ 'handleVisibilityChange' ] ( ) ;
83+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( true ) ;
84+ } ) ;
85+
86+ it ( 'should correctly calculate time in foreground' , ( ) => {
87+ jest . spyOn ( global . performance , 'now' )
88+ . mockReturnValueOnce ( 10 )
89+ . mockReturnValueOnce ( 50 )
90+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
91+
92+ expect ( foregroundTimeTracker . getTimeInForeground ( ) ) . toBe ( 40 ) ;
93+ } ) ;
94+
95+ it ( 'should update time in localStorage and totalTimewhen the page is hidden' , ( ) => {
96+ jest . spyOn ( global . performance , 'now' )
97+ . mockReturnValueOnce ( 10 )
98+ . mockReturnValueOnce ( 50 )
99+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
100+ foregroundTimeTracker [ 'totalTime' ] = 1000 ;
101+
102+ Object . defineProperty ( document , 'hidden' , { value : true , configurable : true } ) ;
103+ foregroundTimeTracker [ 'handleVisibilityChange' ] ( ) ;
104+ expect ( foregroundTimeTracker [ 'isTrackerActive' ] ) . toBe ( false ) ;
105+ expect ( localStorage . getItem ( mockStorageKey ) ) . toBe ( '1040' ) ;
106+ expect ( foregroundTimeTracker [ 'totalTime' ] ) . toBe ( 1040 ) ;
107+ } ) ;
108+
109+ it ( 'should set startTime to the last performance.now call when stopping tracking' , ( ) => {
110+ jest . spyOn ( global . performance , 'now' )
111+ . mockReturnValueOnce ( 10 )
112+ . mockReturnValueOnce ( 50 )
113+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
114+ foregroundTimeTracker [ 'stopTracking' ] ( ) ;
115+ expect ( foregroundTimeTracker [ 'startTime' ] ) . toBe ( 50 ) ;
116+ } ) ;
117+
118+ it ( 'should update totalTime from localStorage when storage event occurs' , ( ) => {
119+ localStorage . setItem ( mockStorageKey , '7000' ) ;
120+ const event = new StorageEvent ( 'storage' , {
121+ key : mockStorageKey ,
122+ newValue : '7000' ,
123+ } ) ;
124+
125+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
126+
127+ foregroundTimeTracker [ 'syncAcrossTabs' ] ( event ) ;
128+ expect ( foregroundTimeTracker [ 'totalTime' ] ) . toBe ( 7000 ) ;
129+ } ) ;
130+
131+ it ( 'should not overwrite totalTime if the new value is smaller' , ( ) => {
132+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
133+
134+ foregroundTimeTracker [ 'totalTime' ] = 8000 ;
135+ const event = new StorageEvent ( 'storage' , {
136+ key : mockStorageKey ,
137+ newValue : '3000' ,
138+ } ) ;
139+
140+ foregroundTimeTracker [ 'syncAcrossTabs' ] ( event ) ;
141+ expect ( foregroundTimeTracker [ 'totalTime' ] ) . toBe ( 8000 ) ;
142+ } ) ;
143+
144+ it ( 'should reset totalTime and update localStorage' , ( ) => {
145+ foregroundTimeTracker = new ForegroundTimeTracker ( apiKey ) ;
146+
147+ foregroundTimeTracker [ 'totalTime' ] = 5000 ;
148+ foregroundTimeTracker . resetTimer ( ) ;
149+ expect ( foregroundTimeTracker [ 'totalTime' ] ) . toBe ( 0 ) ;
150+ expect ( localStorage . getItem ( mockStorageKey ) ) . toBe ( '0' ) ;
151+ } ) ;
152+ } ) ;
0 commit comments