@@ -7,6 +7,10 @@ jest.mock('good-env', () => ({
77 if ( key === 'HUE_MOTION_STOP_BUFFER' ) return 90 ;
88 if ( key === 'HUE_MOTION_POLLING_INTERVAL' ) return 2 ;
99 return defaultValue ;
10+ } ) ,
11+ get : jest . fn ( ) . mockImplementation ( ( key ) => {
12+ if ( key === 'NODE_ENV' ) return 'TEST' ;
13+ return undefined ;
1014 } )
1115} ) ) ;
1216
@@ -23,9 +27,15 @@ const mockBridge = jest.fn().mockReturnValue({
2327 user : mockUser
2428} ) ;
2529
26- jest . mock ( 'jshue' , ( ) => ( {
27- bridge : mockBridge
28- } ) ) ;
30+ const mockBridgeFn = jest . fn ( ) . mockReturnValue ( {
31+ user : mockUser
32+ } ) ;
33+
34+ jest . mock ( 'jshue' , ( ) => {
35+ return jest . fn ( ) . mockReturnValue ( {
36+ bridge : mockBridgeFn
37+ } ) ;
38+ } ) ;
2939
3040// Mock log
3141jest . mock ( '../../src/lib/log.js' , ( ) => ( {
@@ -36,24 +46,46 @@ jest.mock('../../src/lib/log.js', () => ({
3646import env from 'good-env' ;
3747import jsHue from 'jshue' ;
3848import log from '../../src/lib/log.js' ;
39- import Sensor from '../../src/lib/sensor.js' ;
4049
41- describe . skip ( 'sensor.js' , ( ) => {
50+ describe ( 'sensor.js' , ( ) => {
4251 let sensor ;
52+ let Sensor ;
4353 const mockConfig = {
4454 bridgeIp : '192.168.1.100' ,
4555 sensorId : '123' ,
4656 username : 'testuser'
4757 } ;
48-
49- beforeEach ( ( ) => {
58+
59+ // Synchronous setInterval mock for testing
60+ function createManualInterval ( ) {
61+ let callback ;
62+ return {
63+ setInterval : ( fn , interval ) => {
64+ callback = fn ;
65+ return 1 ;
66+ } ,
67+ tick : async ( ) => {
68+ if ( callback ) await callback ( ) ;
69+ }
70+ } ;
71+ }
72+
73+ let manualInterval ;
74+
75+ // Helper to flush all pending promises
76+ async function flushPromises ( ) {
77+ for ( let i = 0 ; i < 5 ; i ++ ) {
78+ await Promise . resolve ( ) ;
79+ await new Promise ( r => setImmediate ( r ) ) ;
80+ }
81+ }
82+
83+ beforeEach ( async ( ) => {
5084 jest . clearAllMocks ( ) ;
51- jest . useFakeTimers ( ) ;
52- sensor = new Sensor ( mockConfig ) ;
53- } ) ;
54-
55- afterEach ( ( ) => {
56- jest . useRealTimers ( ) ;
85+ jest . resetModules ( ) ;
86+ Sensor = ( await import ( '../../src/lib/sensor.js' ) ) . default ;
87+ manualInterval = createManualInterval ( ) ;
88+ sensor = new Sensor ( { ...mockConfig , setIntervalFn : manualInterval . setInterval } ) ;
5789 } ) ;
5890
5991 describe ( 'constructor' , ( ) => {
@@ -66,20 +98,21 @@ describe.skip('sensor.js', () => {
6698 } ) ;
6799
68100 it ( 'should set up bridge and user correctly' , ( ) => {
69- expect ( mockBridge ) . toHaveBeenCalledWith ( '192.168.1.100' ) ;
101+ expect ( mockBridgeFn ) . toHaveBeenCalledWith ( '192.168.1.100' ) ;
70102 expect ( mockUser ) . toHaveBeenCalledWith ( 'testuser' ) ;
71103 } ) ;
72104 } ) ;
73105
74106 describe ( 'monitor' , ( ) => {
75107 it ( 'should start monitoring the sensor' , async ( ) => {
76108 const monitorPromise = sensor . monitor ( ) ;
77- expect ( sensor . _lastKnownState ) . toBe ( false ) ;
78109 await monitorPromise ;
110+ expect ( sensor . _lastKnownState ) . toBe ( false ) ;
79111 expect ( mockGetSensor ) . toHaveBeenCalledWith ( '123' ) ;
80112 } ) ;
81113
82114 it ( 'should emit motion_start when presence changes to true' , async ( ) => {
115+ jest . setTimeout ( 10000 ) ;
83116 const motionStartSpy = jest . fn ( ) ;
84117 sensor . on ( 'motion_start' , motionStartSpy ) ;
85118
@@ -94,8 +127,8 @@ describe.skip('sensor.js', () => {
94127 } ) ;
95128
96129 await sensor . monitor ( ) ;
97- jest . advanceTimersByTime ( 2000 ) ; // Advance past polling interval
98-
130+ await manualInterval . tick ( ) ;
131+ await flushPromises ( ) ;
99132 expect ( motionStartSpy ) . toHaveBeenCalled ( ) ;
100133 } ) ;
101134
@@ -114,21 +147,26 @@ describe.skip('sensor.js', () => {
114147 } ) ;
115148
116149 await sensor . monitor ( ) ;
117- jest . advanceTimersByTime ( 2000 ) ; // Advance past polling interval
118- jest . advanceTimersByTime ( 90000 ) ; // Advance past buffer period
119-
150+ await manualInterval . tick ( ) ; // First interval: presence changes to false
151+ // Simulate time passage for buffer
152+ sensor . _lastMotionStop = Date . now ( ) - 90000 ;
153+ await manualInterval . tick ( ) ; // Second interval: should emit motion_stop
154+ await flushPromises ( ) ;
120155 expect ( motionStopSpy ) . toHaveBeenCalled ( ) ;
121156 } ) ;
122157
123158 it ( 'should emit error when sensor polling fails' , async ( ) => {
124159 const errorSpy = jest . fn ( ) ;
125160 sensor . on ( 'error' , errorSpy ) ;
126161
162+ mockGetSensor . mockResolvedValueOnce ( {
163+ state : { presence : false }
164+ } ) ;
127165 mockGetSensor . mockRejectedValueOnce ( new Error ( 'Test error' ) ) ;
128166
129167 await sensor . monitor ( ) ;
130- jest . advanceTimersByTime ( 2000 ) ; // Advance past polling interval
131-
168+ await manualInterval . tick ( ) ;
169+ await flushPromises ( ) ;
132170 expect ( errorSpy ) . toHaveBeenCalledWith ( expect . any ( Error ) ) ;
133171 } ) ;
134172 } ) ;
0 commit comments