- Replace simple icon-based signal display with WiFiSignalIndicator bars - Add human-readable signal strength labels (Excellent, Good, Fair, Weak) - Display dBm values in parentheses for technical reference - Add comprehensive tests for signal strength UI integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
276 lines
7.5 KiB
TypeScript
276 lines
7.5 KiB
TypeScript
/**
|
|
* Add Sensor Screen - Signal Strength UI Tests
|
|
* Tests the WiFiSignalIndicator integration and signal strength display
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { render } from '@testing-library/react-native';
|
|
import { useLocalSearchParams } 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((callback) => callback()),
|
|
}));
|
|
|
|
jest.mock('@/contexts/BLEContext', () => ({
|
|
useBLE: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('@/contexts/BeneficiaryContext', () => ({
|
|
useBeneficiary: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('expo-device', () => ({
|
|
isDevice: true,
|
|
}));
|
|
|
|
jest.mock('@/services/analytics', () => ({
|
|
analytics: {
|
|
trackSensorScanStart: jest.fn(),
|
|
trackSensorScanComplete: jest.fn(),
|
|
trackSensorSetupStart: jest.fn(),
|
|
},
|
|
}));
|
|
|
|
describe('AddSensorScreen - Signal Strength UI', () => {
|
|
const mockStopScan = jest.fn();
|
|
const mockScanDevices = jest.fn();
|
|
const mockClearError = jest.fn();
|
|
|
|
const createMockDevice = (rssi: number, id: string = 'device-1') => ({
|
|
id,
|
|
name: `WP_497_${id}`,
|
|
mac: id.toUpperCase(),
|
|
rssi,
|
|
wellId: 497,
|
|
});
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
|
|
(useLocalSearchParams as jest.Mock).mockReturnValue({ id: '1' });
|
|
|
|
(useBeneficiary as jest.Mock).mockReturnValue({
|
|
currentBeneficiary: {
|
|
id: 1,
|
|
name: 'Maria',
|
|
},
|
|
});
|
|
});
|
|
|
|
const setupMockBLE = (devices: any[] = [], isScanning = false) => {
|
|
(useBLE as jest.Mock).mockReturnValue({
|
|
foundDevices: devices,
|
|
isScanning,
|
|
connectedDevices: new Set(),
|
|
isBLEAvailable: true,
|
|
error: null,
|
|
permissionError: false,
|
|
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: mockClearError,
|
|
});
|
|
};
|
|
|
|
describe('Signal strength labels', () => {
|
|
it('displays "Excellent" for strong signals (>= -50 dBm)', () => {
|
|
const devices = [createMockDevice(-45)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Excellent')).toBeTruthy();
|
|
expect(getByText('(-45 dBm)')).toBeTruthy();
|
|
});
|
|
|
|
it('displays "Good" for good signals (-51 to -60 dBm)', () => {
|
|
const devices = [createMockDevice(-55)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Good')).toBeTruthy();
|
|
expect(getByText('(-55 dBm)')).toBeTruthy();
|
|
});
|
|
|
|
it('displays "Fair" for fair signals (-61 to -70 dBm)', () => {
|
|
const devices = [createMockDevice(-65)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Fair')).toBeTruthy();
|
|
expect(getByText('(-65 dBm)')).toBeTruthy();
|
|
});
|
|
|
|
it('displays "Weak" for weak signals (< -70 dBm)', () => {
|
|
const devices = [createMockDevice(-75)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Weak')).toBeTruthy();
|
|
expect(getByText('(-75 dBm)')).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('Multiple devices with different signal strengths', () => {
|
|
it('displays correct labels for each device', () => {
|
|
const devices = [
|
|
createMockDevice(-45, 'dev1'),
|
|
createMockDevice(-55, 'dev2'),
|
|
createMockDevice(-65, 'dev3'),
|
|
createMockDevice(-80, 'dev4'),
|
|
];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Excellent')).toBeTruthy();
|
|
expect(getByText('Good')).toBeTruthy();
|
|
expect(getByText('Fair')).toBeTruthy();
|
|
expect(getByText('Weak')).toBeTruthy();
|
|
});
|
|
|
|
it('displays dBm values for each device', () => {
|
|
const devices = [
|
|
createMockDevice(-50, 'dev1'),
|
|
createMockDevice(-60, 'dev2'),
|
|
];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('(-50 dBm)')).toBeTruthy();
|
|
expect(getByText('(-60 dBm)')).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('Device count display', () => {
|
|
it('shows correct device count in section header', () => {
|
|
const devices = [
|
|
createMockDevice(-50, 'dev1'),
|
|
createMockDevice(-60, 'dev2'),
|
|
createMockDevice(-70, 'dev3'),
|
|
];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Found Sensors (3)')).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('Device selection with signal info', () => {
|
|
it('can select device with signal info displayed', () => {
|
|
const devices = [createMockDevice(-55, 'dev1')];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
// Signal info should be visible
|
|
expect(getByText('Good')).toBeTruthy();
|
|
expect(getByText('(-55 dBm)')).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('Boundary RSSI values', () => {
|
|
it('handles exact -50 dBm boundary (Excellent)', () => {
|
|
const devices = [createMockDevice(-50)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Excellent')).toBeTruthy();
|
|
});
|
|
|
|
it('handles exact -60 dBm boundary (Good)', () => {
|
|
const devices = [createMockDevice(-60)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Good')).toBeTruthy();
|
|
});
|
|
|
|
it('handles exact -70 dBm boundary (Fair)', () => {
|
|
const devices = [createMockDevice(-70)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Fair')).toBeTruthy();
|
|
});
|
|
|
|
it('handles -71 dBm (Weak)', () => {
|
|
const devices = [createMockDevice(-71)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Weak')).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('Extreme RSSI values', () => {
|
|
it('handles very strong signal (-30 dBm)', () => {
|
|
const devices = [createMockDevice(-30)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Excellent')).toBeTruthy();
|
|
expect(getByText('(-30 dBm)')).toBeTruthy();
|
|
});
|
|
|
|
it('handles very weak signal (-100 dBm)', () => {
|
|
const devices = [createMockDevice(-100)];
|
|
setupMockBLE(devices);
|
|
|
|
const { getByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Weak')).toBeTruthy();
|
|
expect(getByText('(-100 dBm)')).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('Empty state', () => {
|
|
it('does not show signal UI when no devices found', () => {
|
|
setupMockBLE([]);
|
|
|
|
const { queryByText } = render(<AddSensorScreen />);
|
|
|
|
expect(queryByText('Excellent')).toBeNull();
|
|
expect(queryByText('Good')).toBeNull();
|
|
expect(queryByText('Fair')).toBeNull();
|
|
expect(queryByText('Weak')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('Scanning state', () => {
|
|
it('does not show signal UI while scanning', () => {
|
|
setupMockBLE([], true);
|
|
|
|
const { getByText, queryByText } = render(<AddSensorScreen />);
|
|
|
|
expect(getByText('Scanning for WP sensors...')).toBeTruthy();
|
|
expect(queryByText('Excellent')).toBeNull();
|
|
});
|
|
});
|
|
});
|