Testing Guide
This document describes the testing structure for @gabriel-sisjr/react-native-background-location. Tests are organized in a modular way and cover both Android and iOS platforms, focusing on basic functionality, library types, and cross-platform behavior.
Running Tests
All Tests
yarn test
With Coverage
yarn test --coverage
Verbose Output
yarn test --verbose
Single Test File
yarn test -- src/__tests__/hooks/useBackgroundLocation.test.ts
iOS-Specific Tests Only
yarn test -- src/__tests__/hooks/useLocationPermissions.ios.test.ts
yarn test -- src/__tests__/ios-tracking.test.ts
Test Structure
Configuration Files
| File | Purpose |
|---|---|
setup-minimal.ts | Minimal Jest configuration with basic React Native mocks |
package.json | Jest configuration with specific test patterns |
Test Files
Type Tests (types-basic.test.ts)
Covers all TypeScript types in the library:
- Structure and validation of
Coordstype - Structure and validation of
TrackingStatustype - Values and usage of
LocationPermissionStatusenum - Structure and validation of
PermissionStatetype - Structure and validation of
UseLocationPermissionsResulttype - Structure and validation of
UseBackgroundLocationResulttype - Structure and validation of
UseLocationTrackingOptionstype
Permission Hook Tests (useLocationPermissions-simple.test.ts)
Cross-platform useLocationPermissions hook:
- Initialization with correct default state
- iOS platform compatibility
- Existence and type of
checkPermissionsandrequestPermissionsfunctions
iOS Permission Tests (useLocationPermissions.ios.test.ts)
iOS-specific permission flow:
- Uses native
checkLocationPermission()instead ofPermissionsAndroid - Uses native
requestLocationPermission()via TurboModule bridge - Handles
WHEN_IN_USEstatus correctly (hasPermission = true) - Maps iOS authorization statuses to
LocationPermissionStatusenum - Handles permission downgrade scenarios
iOS Tracking Tests (ios-tracking.test.ts)
iOS-specific tracking behavior:
- Notification options are silently ignored on iOS
startTrackingworks without notification configuration- iOS warning types (
PERMISSION_REVOKED,PERMISSION_DOWNGRADED) - Platform detection and conditional behavior
Basic Module Tests (BackgroundLocation-basic.test.ts)
Basic React Native functionality:
- Platform detection (Android/iOS)
- Native
BackgroundLocationmodule availability - Simulator mode (when native module is not available)
PermissionsAndroidavailability and constantsLinkingmodule availability
Jest Configuration
{
"jest": {
"preset": "react-native",
"setupFilesAfterEnv": ["<rootDir>/src/__tests__/setup-minimal.ts"],
"testMatch": [
"<rootDir>/src/__tests__/**/*-simple.test.{js,ts,tsx}",
"<rootDir>/src/__tests__/**/*-basic.test.{js,ts,tsx}",
"<rootDir>/src/__tests__/**/*.ios.test.{js,ts,tsx}",
"<rootDir>/src/__tests__/**/*.test.{js,ts,tsx}"
],
"coverageThreshold": {
"global": {
"branches": 0,
"functions": 0,
"lines": 0,
"statements": 0
}
}
}
}
Testing Patterns
Mocking Platform.OS for iOS
jest.mock('react-native/Libraries/Utilities/Platform', () => ({
OS: 'ios',
select: jest.fn((obj: Record<string, unknown>) => obj.ios),
}));
Mocking the Native Module for iOS
jest.mock('../../NativeBackgroundLocation', () => ({
__esModule: true,
default: {
checkLocationPermission: jest.fn().mockResolvedValue('granted'),
requestLocationPermission: jest.fn().mockResolvedValue('granted'),
startTracking: jest.fn().mockResolvedValue('trip-123'),
stopTracking: jest.fn().mockResolvedValue(undefined),
isTracking: jest.fn().mockResolvedValue({ active: false }),
getLocations: jest.fn().mockResolvedValue([]),
clearTrip: jest.fn().mockResolvedValue(undefined),
addListener: jest.fn(),
removeListeners: jest.fn(),
},
}));
Testing WHEN_IN_USE Permission Status
it('should treat WHEN_IN_USE as hasPermission = true', () => {
// On iOS, WhenInUse is sufficient for basic tracking
const state = mapPermissionStatus('whenInUse');
expect(state.hasPermission).toBe(true);
expect(state.status).toBe('whenInUse');
});
Testing Strategy
Current Approach
- Basic Tests -- Focus on fundamental functionality without complex dependencies
- Minimal Mocks -- Use simple mocks to avoid configuration problems
- Type Coverage -- Complete validation of TypeScript types
- Compatibility -- Tests for different platforms and scenarios
Current Limitations
- Integration Tests -- Not implemented due to mock complexity
- Complex Hook Tests -- Limited to basic functionality
- Native Module Tests -- Focused on availability, not functionality
Planned Improvements
- Integration tests that validate component interaction
- Complete hook tests for all scenarios
- Native module tests that validate real functionality
- Performance tests for critical operations
Adding New Tests
- Create a file with the suffix
-simple.test.ts,-basic.test.ts, or.ios.test.ts - Follow existing naming patterns
- Use minimal mocks to avoid configuration problems
- Focus on basic functionality and types
Updating Existing Tests
- Maintain compatibility with current configuration
- Use simple and direct mocks
- Avoid complex dependencies
- Focus on real use cases
Manual Testing on iOS
Simulator Testing
- Run the example app:
yarn example ios - Use Features > Location in the Simulator menu to simulate location
- Grant permissions when prompted
- Start tracking and verify locations appear
- Test background by pressing Home, then returning
Device Testing
- Build and run on a physical iOS device
- Walk around outdoors with the device
- Test the full permission flow (WhenInUse to Always)
- Verify background tracking (blue bar indicator should appear)
- Test crash recovery by force-killing the app, then reopening
Permission Scenarios
| Scenario | How to Test | Expected Result |
|---|---|---|
| WhenInUse only | Grant "While Using" only | status: 'whenInUse', tracking works in foreground |
| Always | Grant "Always" | status: 'granted', full background tracking |
| Denied | Deny permission | status: 'denied', tracking fails gracefully |
| Revoked while tracking | Start tracking, then revoke in Settings | PERMISSION_REVOKED warning emitted |
| Downgraded while tracking | Start with Always, downgrade to WhenInUse in Settings | PERMISSION_DOWNGRADED warning emitted |
Manual Testing on Android
Emulator Testing
- Run the example app:
yarn example android - Open Extended Controls (three dots
...on the emulator side panel) - Go to Location and set a specific coordinate or play a route
- Grant all location permissions including "Allow all the time"
- Start tracking and verify locations appear
Device Testing
- Build and run on a physical Android device
- Grant all location and notification permissions
- Test with the "High Accuracy" preset for 2-second updates
- Background the app and verify the foreground service notification appears
- Test crash recovery by force-stopping the app in Settings