Implemented a reusable useDebounce hook to prevent rapid-fire clicks on refresh buttons throughout the application. Changes: - Created hooks/useDebounce.ts with configurable delay and leading/trailing edge options - Added comprehensive unit tests in hooks/__tests__/useDebounce.test.ts - Applied debouncing to dashboard WebView refresh button (app/(tabs)/dashboard.tsx) - Applied debouncing to beneficiary detail pull-to-refresh (app/(tabs)/beneficiaries/[id]/index.tsx) - Applied debouncing to equipment screen refresh (app/(tabs)/beneficiaries/[id]/equipment.tsx) - Applied debouncing to all error retry buttons (components/ui/ErrorMessage.tsx) - Fixed jest.setup.js to properly mock React Native modules - Added implementation documentation in docs/DEBOUNCE_IMPLEMENTATION.md Technical details: - Default 1-second debounce delay - Leading edge execution (immediate first call, then debounce) - Type-safe with TypeScript generics - Automatic cleanup on component unmount 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
56 lines
1.2 KiB
JavaScript
56 lines
1.2 KiB
JavaScript
// Setup testing library
|
|
// Note: extend-expect is automatically loaded by @testing-library/react-native
|
|
|
|
// Mock expo modules
|
|
jest.mock('expo', () => ({
|
|
// Add any expo mocks here if needed
|
|
}));
|
|
|
|
// Mock Expo modules
|
|
jest.mock('expo-router', () => ({
|
|
router: {
|
|
push: jest.fn(),
|
|
replace: jest.fn(),
|
|
back: jest.fn(),
|
|
setParams: jest.fn(),
|
|
},
|
|
useLocalSearchParams: jest.fn(() => ({})),
|
|
useRouter: jest.fn(() => ({
|
|
push: jest.fn(),
|
|
replace: jest.fn(),
|
|
back: jest.fn(),
|
|
})),
|
|
useSegments: jest.fn(() => []),
|
|
usePathname: jest.fn(() => '/'),
|
|
}));
|
|
|
|
jest.mock('expo-secure-store', () => ({
|
|
getItemAsync: jest.fn(),
|
|
setItemAsync: jest.fn(),
|
|
deleteItemAsync: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('expo-image-picker', () => ({
|
|
requestMediaLibraryPermissionsAsync: jest.fn(() =>
|
|
Promise.resolve({ status: 'granted' })
|
|
),
|
|
launchImageLibraryAsync: jest.fn(() =>
|
|
Promise.resolve({
|
|
canceled: false,
|
|
assets: [{ uri: 'file://test-image.jpg' }],
|
|
})
|
|
),
|
|
}));
|
|
|
|
// Mock native modules
|
|
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper', () => ({
|
|
default: {},
|
|
}), { virtual: true });
|
|
|
|
// Silence console warnings in tests
|
|
global.console = {
|
|
...console,
|
|
warn: jest.fn(),
|
|
error: jest.fn(),
|
|
};
|