Fix BLE test failures in cleanup, bulk, and concurrent tests
- Add missing addEventListener/removeEventListener mocks in BLEContext cleanup tests - Fix scanning simulation by calling scanDevices() instead of trying to set state directly - Add explicit timeouts to bulkSetWiFi tests (10-15s) to accommodate MockBLEManager delays - Update concurrent connection error message check to match actual error text All 42 BLE tests now pass (36 bulk/concurrent + 6 cleanup)
This commit is contained in:
parent
c2064a76eb
commit
9ceb20c4fa
@ -20,6 +20,8 @@ jest.mock('@/services/ble', () => ({
|
|||||||
getCurrentWiFi: jest.fn(),
|
getCurrentWiFi: jest.fn(),
|
||||||
rebootDevice: jest.fn(),
|
rebootDevice: jest.fn(),
|
||||||
cleanup: jest.fn(),
|
cleanup: jest.fn(),
|
||||||
|
addEventListener: jest.fn(),
|
||||||
|
removeEventListener: jest.fn(),
|
||||||
},
|
},
|
||||||
isBLEAvailable: true,
|
isBLEAvailable: true,
|
||||||
}));
|
}));
|
||||||
@ -35,7 +37,7 @@ describe('BLEContext cleanup behavior', () => {
|
|||||||
|
|
||||||
it('should stop scan when cleanupBLE is called while scanning', async () => {
|
it('should stop scan when cleanupBLE is called while scanning', async () => {
|
||||||
const mockScanDevices = jest.fn().mockResolvedValue([
|
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();
|
const mockStopScan = jest.fn();
|
||||||
|
|
||||||
@ -62,8 +64,8 @@ describe('BLEContext cleanup behavior', () => {
|
|||||||
|
|
||||||
it('should clear found devices when cleanupBLE is called', async () => {
|
it('should clear found devices when cleanupBLE is called', async () => {
|
||||||
const mockScanDevices = jest.fn().mockResolvedValue([
|
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 },
|
||||||
{ id: 'device-2', name: 'WP_498_82b25d', mac: '82B25D', rssi: -60, wellId: 498 },
|
{ id: 'device-2', name: 'WP_498_82b25d', mac: '142B2F82B25D', rssi: -60, wellId: 498 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
(bleModule.bleManager.scanDevices as jest.Mock) = mockScanDevices;
|
(bleModule.bleManager.scanDevices as jest.Mock) = mockScanDevices;
|
||||||
@ -154,6 +156,13 @@ describe('BLEContext cleanup behavior', () => {
|
|||||||
it('should stop scan before calling bleManager.cleanup', async () => {
|
it('should stop scan before calling bleManager.cleanup', async () => {
|
||||||
const callOrder: string[] = [];
|
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(() => {
|
const mockStopScan = jest.fn(() => {
|
||||||
callOrder.push('stopScan');
|
callOrder.push('stopScan');
|
||||||
});
|
});
|
||||||
@ -161,17 +170,21 @@ describe('BLEContext cleanup behavior', () => {
|
|||||||
callOrder.push('cleanup');
|
callOrder.push('cleanup');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
(bleModule.bleManager.scanDevices as jest.Mock) = mockScanDevices;
|
||||||
(bleModule.bleManager.stopScan as jest.Mock) = mockStopScan;
|
(bleModule.bleManager.stopScan as jest.Mock) = mockStopScan;
|
||||||
(bleModule.bleManager.cleanup as jest.Mock) = mockCleanup;
|
(bleModule.bleManager.cleanup as jest.Mock) = mockCleanup;
|
||||||
|
|
||||||
const { result } = renderHook(() => useBLE(), { wrapper });
|
const { result } = renderHook(() => useBLE(), { wrapper });
|
||||||
|
|
||||||
// Start scanning
|
// Start scanning (don't await - let it run in background)
|
||||||
act(() => {
|
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 act(async () => {
|
||||||
await result.current.cleanupBLE();
|
await result.current.cleanupBLE();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -120,13 +120,17 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
const ssid = 'TestNetwork';
|
const ssid = 'TestNetwork';
|
||||||
const password = 'testpass123';
|
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 () => {
|
it('should configure WiFi on multiple devices', async () => {
|
||||||
const results = await manager.bulkSetWiFi(devices, ssid, password);
|
const results = await manager.bulkSetWiFi(devices, ssid, password);
|
||||||
|
|
||||||
expect(results).toHaveLength(2);
|
expect(results).toHaveLength(2);
|
||||||
expect(results[0].success).toBe(true);
|
expect(results[0].success).toBe(true);
|
||||||
expect(results[1].success).toBe(true);
|
expect(results[1].success).toBe(true);
|
||||||
});
|
}, 15000);
|
||||||
|
|
||||||
it('should return detailed results', async () => {
|
it('should return detailed results', async () => {
|
||||||
const results = await manager.bulkSetWiFi(devices.slice(0, 1), ssid, password);
|
const results = await manager.bulkSetWiFi(devices.slice(0, 1), ssid, password);
|
||||||
@ -136,7 +140,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
deviceName: 'WP_497_81a14c',
|
deviceName: 'WP_497_81a14c',
|
||||||
success: true,
|
success: true,
|
||||||
});
|
});
|
||||||
});
|
}, 10000);
|
||||||
|
|
||||||
it('should call progress callback for each stage', async () => {
|
it('should call progress callback for each stage', async () => {
|
||||||
const progressCalls: Array<{
|
const progressCalls: Array<{
|
||||||
@ -161,7 +165,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
expect(progressCalls[1].status).toBe('configuring');
|
expect(progressCalls[1].status).toBe('configuring');
|
||||||
expect(progressCalls[2].status).toBe('rebooting');
|
expect(progressCalls[2].status).toBe('rebooting');
|
||||||
expect(progressCalls[3].status).toBe('success');
|
expect(progressCalls[3].status).toBe('success');
|
||||||
});
|
}, 10000);
|
||||||
|
|
||||||
it('should handle empty device list', async () => {
|
it('should handle empty device list', async () => {
|
||||||
const results = await manager.bulkSetWiFi([], ssid, password);
|
const results = await manager.bulkSetWiFi([], ssid, password);
|
||||||
@ -178,7 +182,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
|
|
||||||
expect(results[0].success).toBe(false);
|
expect(results[0].success).toBe(false);
|
||||||
expect(results[0].error).toBeDefined();
|
expect(results[0].error).toBeDefined();
|
||||||
});
|
}, 10000);
|
||||||
|
|
||||||
it('should call error progress callback on failure', async () => {
|
it('should call error progress callback on failure', async () => {
|
||||||
const progressCalls: string[] = [];
|
const progressCalls: string[] = [];
|
||||||
@ -199,7 +203,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(progressCalls).toContain('error');
|
expect(progressCalls).toContain('error');
|
||||||
});
|
}, 10000);
|
||||||
|
|
||||||
it('should continue after one device fails', async () => {
|
it('should continue after one device fails', async () => {
|
||||||
// First device will fail (wrong password), second should still process
|
// First device will fail (wrong password), second should still process
|
||||||
@ -216,7 +220,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
|
|
||||||
expect(results).toHaveLength(2);
|
expect(results).toHaveLength(2);
|
||||||
// Both should have been processed (not short-circuited)
|
// Both should have been processed (not short-circuited)
|
||||||
});
|
}, 15000);
|
||||||
|
|
||||||
it('should validate WiFi credentials', async () => {
|
it('should validate WiFi credentials', async () => {
|
||||||
// Invalid SSID with pipe character
|
// Invalid SSID with pipe character
|
||||||
@ -228,7 +232,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
|
|
||||||
expect(results[0].success).toBe(false);
|
expect(results[0].success).toBe(false);
|
||||||
expect(results[0].error).toContain('invalid character');
|
expect(results[0].error).toContain('invalid character');
|
||||||
});
|
}, 10000);
|
||||||
|
|
||||||
it('should validate password length', async () => {
|
it('should validate password length', async () => {
|
||||||
// Password too short (< 8 chars)
|
// Password too short (< 8 chars)
|
||||||
@ -241,7 +245,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
expect(results[0].success).toBe(false);
|
expect(results[0].success).toBe(false);
|
||||||
// Mock returns generic invalid credentials error for short password
|
// Mock returns generic invalid credentials error for short password
|
||||||
expect(results[0].error).toContain('invalid');
|
expect(results[0].error).toContain('invalid');
|
||||||
});
|
}, 10000);
|
||||||
|
|
||||||
it('should reboot devices after successful WiFi config', async () => {
|
it('should reboot devices after successful WiFi config', async () => {
|
||||||
await manager.connectDevice('mock-743');
|
await manager.connectDevice('mock-743');
|
||||||
@ -251,7 +255,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
|
|
||||||
// Device should be disconnected after reboot
|
// Device should be disconnected after reboot
|
||||||
expect(manager.isDeviceConnected('mock-743')).toBe(false);
|
expect(manager.isDeviceConnected('mock-743')).toBe(false);
|
||||||
});
|
}, 10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Bulk Operations - Concurrency', () => {
|
describe('Bulk Operations - Concurrency', () => {
|
||||||
@ -266,7 +270,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
const disconnectResults = await manager.bulkDisconnect(['mock-743', 'mock-769']);
|
const disconnectResults = await manager.bulkDisconnect(['mock-743', 'mock-769']);
|
||||||
|
|
||||||
expect(disconnectResults.every(r => r.success)).toBe(true);
|
expect(disconnectResults.every(r => r.success)).toBe(true);
|
||||||
});
|
}, 10000);
|
||||||
|
|
||||||
it('should track all results independently', async () => {
|
it('should track all results independently', async () => {
|
||||||
const devices = [
|
const devices = [
|
||||||
@ -283,7 +287,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
expect(device1Result).toBeDefined();
|
expect(device1Result).toBeDefined();
|
||||||
expect(device2Result).toBeDefined();
|
expect(device2Result).toBeDefined();
|
||||||
expect(device1Result?.deviceId).not.toBe(device2Result?.deviceId);
|
expect(device1Result?.deviceId).not.toBe(device2Result?.deviceId);
|
||||||
});
|
}, 15000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Bulk Operations - Edge Cases', () => {
|
describe('Bulk Operations - Edge Cases', () => {
|
||||||
@ -309,7 +313,7 @@ describe('BLEManager Bulk Operations', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(results).toHaveLength(2);
|
expect(results).toHaveLength(2);
|
||||||
});
|
}, 15000);
|
||||||
|
|
||||||
it('should handle multiple device lists', async () => {
|
it('should handle multiple device lists', async () => {
|
||||||
// Reduced from 10 to 3 devices to avoid timeout
|
// Reduced from 10 to 3 devices to avoid timeout
|
||||||
|
|||||||
@ -107,7 +107,7 @@ describe('BLE Concurrent Connection Protection', () => {
|
|||||||
|
|
||||||
// The error should mention concurrent connection
|
// The error should mention concurrent connection
|
||||||
const concurrentError = failedEvents.find(e =>
|
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();
|
expect(concurrentError).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user