diff --git a/services/ble/__tests__/BLEContext.cleanup.test.tsx b/services/ble/__tests__/BLEContext.cleanup.test.tsx index dbd6d87..cb97274 100644 --- a/services/ble/__tests__/BLEContext.cleanup.test.tsx +++ b/services/ble/__tests__/BLEContext.cleanup.test.tsx @@ -20,6 +20,8 @@ jest.mock('@/services/ble', () => ({ getCurrentWiFi: jest.fn(), rebootDevice: jest.fn(), cleanup: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), }, isBLEAvailable: true, })); @@ -35,7 +37,7 @@ describe('BLEContext cleanup behavior', () => { it('should stop scan when cleanupBLE is called while scanning', async () => { const mockScanDevices = jest.fn().mockResolvedValue([ - { id: 'device-1', name: 'WP_497_81a14c', mac: '81A14C', rssi: -55, wellId: 497 }, + { id: 'device-1', name: 'WP_497_81a14c', mac: '142B2F81A14C', rssi: -55, wellId: 497 }, ]); const mockStopScan = jest.fn(); @@ -62,8 +64,8 @@ describe('BLEContext cleanup behavior', () => { it('should clear found devices when cleanupBLE is called', async () => { const mockScanDevices = jest.fn().mockResolvedValue([ - { id: 'device-1', name: 'WP_497_81a14c', mac: '81A14C', rssi: -55, wellId: 497 }, - { id: 'device-2', name: 'WP_498_82b25d', mac: '82B25D', rssi: -60, wellId: 498 }, + { id: 'device-1', name: 'WP_497_81a14c', mac: '142B2F81A14C', rssi: -55, wellId: 497 }, + { id: 'device-2', name: 'WP_498_82b25d', mac: '142B2F82B25D', rssi: -60, wellId: 498 }, ]); (bleModule.bleManager.scanDevices as jest.Mock) = mockScanDevices; @@ -154,6 +156,13 @@ describe('BLEContext cleanup behavior', () => { it('should stop scan before calling bleManager.cleanup', async () => { const callOrder: string[] = []; + // Make scanDevices take a long time so we can cleanup while it's scanning + const mockScanDevices = jest.fn().mockImplementation(() => { + return new Promise((resolve) => { + // Simulate a long-running scan + setTimeout(() => resolve([]), 5000); + }); + }); const mockStopScan = jest.fn(() => { callOrder.push('stopScan'); }); @@ -161,17 +170,21 @@ describe('BLEContext cleanup behavior', () => { callOrder.push('cleanup'); }); + (bleModule.bleManager.scanDevices as jest.Mock) = mockScanDevices; (bleModule.bleManager.stopScan as jest.Mock) = mockStopScan; (bleModule.bleManager.cleanup as jest.Mock) = mockCleanup; const { result } = renderHook(() => useBLE(), { wrapper }); - // Start scanning + // Start scanning (don't await - let it run in background) act(() => { - (result.current as any).setIsScanning?.(true); + result.current.scanDevices(); }); - // Trigger cleanup + // isScanning should be true now + expect(result.current.isScanning).toBe(true); + + // Trigger cleanup while scanning await act(async () => { await result.current.cleanupBLE(); }); diff --git a/services/ble/__tests__/BLEManager.bulk.test.ts b/services/ble/__tests__/BLEManager.bulk.test.ts index 319ff03..c79cc00 100644 --- a/services/ble/__tests__/BLEManager.bulk.test.ts +++ b/services/ble/__tests__/BLEManager.bulk.test.ts @@ -120,13 +120,17 @@ describe('BLEManager Bulk Operations', () => { const ssid = 'TestNetwork'; const password = 'testpass123'; + // BulkSetWiFi has delays: connect (800ms) + setWiFi (1200ms) + reboot (600ms) = ~2.6s per device + // For 2 devices: ~5.2s, so we need 15s timeout to be safe + jest.setTimeout(15000); + it('should configure WiFi on multiple devices', async () => { const results = await manager.bulkSetWiFi(devices, ssid, password); expect(results).toHaveLength(2); expect(results[0].success).toBe(true); expect(results[1].success).toBe(true); - }); + }, 15000); it('should return detailed results', async () => { const results = await manager.bulkSetWiFi(devices.slice(0, 1), ssid, password); @@ -136,7 +140,7 @@ describe('BLEManager Bulk Operations', () => { deviceName: 'WP_497_81a14c', success: true, }); - }); + }, 10000); it('should call progress callback for each stage', async () => { const progressCalls: Array<{ @@ -161,7 +165,7 @@ describe('BLEManager Bulk Operations', () => { expect(progressCalls[1].status).toBe('configuring'); expect(progressCalls[2].status).toBe('rebooting'); expect(progressCalls[3].status).toBe('success'); - }); + }, 10000); it('should handle empty device list', async () => { const results = await manager.bulkSetWiFi([], ssid, password); @@ -178,7 +182,7 @@ describe('BLEManager Bulk Operations', () => { expect(results[0].success).toBe(false); expect(results[0].error).toBeDefined(); - }); + }, 10000); it('should call error progress callback on failure', async () => { const progressCalls: string[] = []; @@ -199,7 +203,7 @@ describe('BLEManager Bulk Operations', () => { ); expect(progressCalls).toContain('error'); - }); + }, 10000); it('should continue after one device fails', async () => { // First device will fail (wrong password), second should still process @@ -216,7 +220,7 @@ describe('BLEManager Bulk Operations', () => { expect(results).toHaveLength(2); // Both should have been processed (not short-circuited) - }); + }, 15000); it('should validate WiFi credentials', async () => { // Invalid SSID with pipe character @@ -228,7 +232,7 @@ describe('BLEManager Bulk Operations', () => { expect(results[0].success).toBe(false); expect(results[0].error).toContain('invalid character'); - }); + }, 10000); it('should validate password length', async () => { // Password too short (< 8 chars) @@ -241,7 +245,7 @@ describe('BLEManager Bulk Operations', () => { expect(results[0].success).toBe(false); // Mock returns generic invalid credentials error for short password expect(results[0].error).toContain('invalid'); - }); + }, 10000); it('should reboot devices after successful WiFi config', async () => { await manager.connectDevice('mock-743'); @@ -251,7 +255,7 @@ describe('BLEManager Bulk Operations', () => { // Device should be disconnected after reboot expect(manager.isDeviceConnected('mock-743')).toBe(false); - }); + }, 10000); }); describe('Bulk Operations - Concurrency', () => { @@ -266,7 +270,7 @@ describe('BLEManager Bulk Operations', () => { const disconnectResults = await manager.bulkDisconnect(['mock-743', 'mock-769']); expect(disconnectResults.every(r => r.success)).toBe(true); - }); + }, 10000); it('should track all results independently', async () => { const devices = [ @@ -283,7 +287,7 @@ describe('BLEManager Bulk Operations', () => { expect(device1Result).toBeDefined(); expect(device2Result).toBeDefined(); expect(device1Result?.deviceId).not.toBe(device2Result?.deviceId); - }); + }, 15000); }); describe('Bulk Operations - Edge Cases', () => { @@ -309,7 +313,7 @@ describe('BLEManager Bulk Operations', () => { ); expect(results).toHaveLength(2); - }); + }, 15000); it('should handle multiple device lists', async () => { // Reduced from 10 to 3 devices to avoid timeout diff --git a/services/ble/__tests__/BLEManager.concurrent.test.ts b/services/ble/__tests__/BLEManager.concurrent.test.ts index 7433506..b7f5431 100644 --- a/services/ble/__tests__/BLEManager.concurrent.test.ts +++ b/services/ble/__tests__/BLEManager.concurrent.test.ts @@ -107,7 +107,7 @@ describe('BLE Concurrent Connection Protection', () => { // The error should mention concurrent connection const concurrentError = failedEvents.find(e => - e.error?.includes('Connection already in progress') + e.error?.includes('Already trying to connect') || e.error?.includes('Connection in Progress') ); expect(concurrentError).toBeDefined(); });