Implement proper cleanup of BLE scanning operations when users navigate away from the add-sensor screen to prevent resource waste and potential issues. Changes: - Add useFocusEffect hook to stop BLE scan when screen loses focus - Remove unused imports (Device, WPDevice, connectDevice, etc.) - Add comprehensive tests for BLE cleanup behavior - Add tests for screen unmount/blur scenarios 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
186 lines
5.0 KiB
TypeScript
186 lines
5.0 KiB
TypeScript
/**
|
|
* Add Sensor Screen - BLE Cleanup Tests
|
|
* Tests that BLE scanning stops when user navigates away from the screen
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { render, waitFor } from '@testing-library/react-native';
|
|
import { useLocalSearchParams, useFocusEffect } from 'expo-router';
|
|
import AddSensorScreen from '../[id]/add-sensor';
|
|
import { useBLE } from '@/contexts/BLEContext';
|
|
import { useBeneficiary } from '@/contexts/BeneficiaryContext';
|
|
|
|
// Mock dependencies
|
|
jest.mock('expo-router', () => ({
|
|
useLocalSearchParams: jest.fn(),
|
|
router: {
|
|
push: jest.fn(),
|
|
back: jest.fn(),
|
|
},
|
|
useFocusEffect: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('@/contexts/BLEContext', () => ({
|
|
useBLE: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('@/contexts/BeneficiaryContext', () => ({
|
|
useBeneficiary: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('expo-device', () => ({
|
|
isDevice: true,
|
|
}));
|
|
|
|
describe('AddSensorScreen - BLE cleanup', () => {
|
|
const mockStopScan = jest.fn();
|
|
const mockScanDevices = jest.fn();
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
|
|
// Mock route params
|
|
(useLocalSearchParams as jest.Mock).mockReturnValue({ id: '1' });
|
|
|
|
// Mock beneficiary context
|
|
(useBeneficiary as jest.Mock).mockReturnValue({
|
|
currentBeneficiary: {
|
|
id: 1,
|
|
name: 'Maria',
|
|
},
|
|
});
|
|
|
|
// Mock BLE context
|
|
(useBLE as jest.Mock).mockReturnValue({
|
|
foundDevices: [],
|
|
isScanning: false,
|
|
connectedDevices: new Set(),
|
|
isBLEAvailable: true,
|
|
error: null,
|
|
scanDevices: mockScanDevices,
|
|
stopScan: mockStopScan,
|
|
connectDevice: jest.fn(),
|
|
disconnectDevice: jest.fn(),
|
|
getWiFiList: jest.fn(),
|
|
setWiFi: jest.fn(),
|
|
getCurrentWiFi: jest.fn(),
|
|
rebootDevice: jest.fn(),
|
|
cleanupBLE: jest.fn(),
|
|
clearError: jest.fn(),
|
|
});
|
|
});
|
|
|
|
it('should register cleanup handler with useFocusEffect', () => {
|
|
render(<AddSensorScreen />);
|
|
|
|
expect(useFocusEffect).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should stop scan when cleanup handler is called while scanning', () => {
|
|
// Mock scanning state
|
|
(useBLE as jest.Mock).mockReturnValue({
|
|
foundDevices: [],
|
|
isScanning: true, // Scan in progress
|
|
connectedDevices: new Set(),
|
|
isBLEAvailable: true,
|
|
error: null,
|
|
scanDevices: mockScanDevices,
|
|
stopScan: mockStopScan,
|
|
connectDevice: jest.fn(),
|
|
disconnectDevice: jest.fn(),
|
|
getWiFiList: jest.fn(),
|
|
setWiFi: jest.fn(),
|
|
getCurrentWiFi: jest.fn(),
|
|
rebootDevice: jest.fn(),
|
|
cleanupBLE: jest.fn(),
|
|
clearError: jest.fn(),
|
|
});
|
|
|
|
render(<AddSensorScreen />);
|
|
|
|
// Get the cleanup function from useFocusEffect
|
|
const focusEffectCall = (useFocusEffect as jest.Mock).mock.calls[0][0];
|
|
const cleanupFn = focusEffectCall(); // Call the effect to get cleanup function
|
|
|
|
// Simulate screen blur by calling cleanup
|
|
if (cleanupFn) {
|
|
cleanupFn();
|
|
}
|
|
|
|
expect(mockStopScan).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not stop scan when cleanup handler is called and not scanning', () => {
|
|
// Mock idle state
|
|
(useBLE as jest.Mock).mockReturnValue({
|
|
foundDevices: [],
|
|
isScanning: false, // Not scanning
|
|
connectedDevices: new Set(),
|
|
isBLEAvailable: true,
|
|
error: null,
|
|
scanDevices: mockScanDevices,
|
|
stopScan: mockStopScan,
|
|
connectDevice: jest.fn(),
|
|
disconnectDevice: jest.fn(),
|
|
getWiFiList: jest.fn(),
|
|
setWiFi: jest.fn(),
|
|
getCurrentWiFi: jest.fn(),
|
|
rebootDevice: jest.fn(),
|
|
cleanupBLE: jest.fn(),
|
|
clearError: jest.fn(),
|
|
});
|
|
|
|
render(<AddSensorScreen />);
|
|
|
|
// Get the cleanup function from useFocusEffect
|
|
const focusEffectCall = (useFocusEffect as jest.Mock).mock.calls[0][0];
|
|
const cleanupFn = focusEffectCall();
|
|
|
|
// Simulate screen blur by calling cleanup
|
|
if (cleanupFn) {
|
|
cleanupFn();
|
|
}
|
|
|
|
// stopScan should not be called when not scanning
|
|
expect(mockStopScan).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should cleanup when component unmounts during active scan', () => {
|
|
(useBLE as jest.Mock).mockReturnValue({
|
|
foundDevices: [
|
|
{ id: 'device-1', name: 'WP_497_81a14c', mac: '81A14C', rssi: -55, wellId: 497 },
|
|
],
|
|
isScanning: true,
|
|
connectedDevices: new Set(),
|
|
isBLEAvailable: true,
|
|
error: null,
|
|
scanDevices: mockScanDevices,
|
|
stopScan: mockStopScan,
|
|
connectDevice: jest.fn(),
|
|
disconnectDevice: jest.fn(),
|
|
getWiFiList: jest.fn(),
|
|
setWiFi: jest.fn(),
|
|
getCurrentWiFi: jest.fn(),
|
|
rebootDevice: jest.fn(),
|
|
cleanupBLE: jest.fn(),
|
|
clearError: jest.fn(),
|
|
});
|
|
|
|
const { unmount } = render(<AddSensorScreen />);
|
|
|
|
// Get the cleanup function
|
|
const focusEffectCall = (useFocusEffect as jest.Mock).mock.calls[0][0];
|
|
const cleanupFn = focusEffectCall();
|
|
|
|
// Unmount component
|
|
unmount();
|
|
|
|
// Cleanup should have been called during unmount
|
|
if (cleanupFn) {
|
|
cleanupFn();
|
|
}
|
|
|
|
expect(mockStopScan).toHaveBeenCalled();
|
|
});
|
|
});
|