WellNuo/jest.setup.js
Sergei 48ceaeda35 Fix avatar caching issues
- Add bustImageCache() at API layer to ensure avatars always have cache-busting timestamps
- Remove redundant bustImageCache() calls from UI components (already handled at API level)
- Add key prop to Image components using avatar URL to force re-render on avatar change
- Add expo-image-manipulator mock to jest.setup.js

This ensures that when users upload new avatars, React Native's Image component
displays the updated image immediately instead of showing cached old versions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-29 12:51:37 -08:00

97 lines
2.3 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-crypto', () => {
return {
getRandomBytesAsync: jest.fn((size) => {
const bytes = new Uint8Array(size);
for (let i = 0; i < size; i++) {
bytes[i] = (i * 7 + 13) % 256;
}
return Promise.resolve(bytes);
}),
digestStringAsync: jest.fn((algorithm, data) => {
const hash = Buffer.from(data).toString('base64').substring(0, 64).padEnd(64, '0');
return Promise.resolve(hash);
}),
CryptoDigestAlgorithm: {
SHA256: 'SHA256',
},
};
}, { virtual: true });
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' }],
})
),
}));
jest.mock('expo-image-manipulator', () => ({
manipulateAsync: jest.fn((uri, actions, options) =>
Promise.resolve({ uri: uri })
),
SaveFormat: {
JPEG: 'jpeg',
PNG: 'png',
},
}));
// Mock AsyncStorage
jest.mock('@react-native-async-storage/async-storage', () => ({
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn(),
clear: jest.fn(),
getAllKeys: jest.fn(() => Promise.resolve([])),
multiGet: jest.fn(() => Promise.resolve([])),
multiSet: jest.fn(() => Promise.resolve()),
multiRemove: jest.fn(() => Promise.resolve()),
}));
// 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(),
};