// Mock react-native-css-interop FIRST to avoid appearance listener issues jest.mock('react-native-css-interop', () => ({ __esModule: true, })) // Import extend-expect for jest matchers import '@testing-library/react-native/extend-expect' // Mock global Appearance for react-native-css-interop global.Appearance = { getColorScheme: jest.fn(() => 'light'), addChangeListener: jest.fn(() => ({ remove: jest.fn() })), removeChangeListener: jest.fn(), } // Initialize globals for react-native-reanimated global._tagToJSPropNamesMapping = {} global._WORKLET = false global._ReanimatedModule = {} // Mock react-native modules // Note: NativeAnimatedHelper may not be needed in newer React Native versions // jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper') // Mock expo modules jest.mock('expo-constants', () => ({ default: {}, Constants: {}, })) jest.mock('expo-modules-core', () => ({ EventEmitter: class MockEventEmitter {}, requireNativeViewManager: jest.fn(() => ({})), requireOptionalNativeModule: jest.fn(() => ({})), requireNativeModule: jest.fn(() => ({})), })) // Mock expo-asset jest.mock('expo-asset', () => ({ AssetModule: {}, Asset: class MockAsset { static fromModule = jest.fn(() => ({ localUri: '' })) static fromURI = jest.fn(() => ({ localUri: '' })) }, })) // Mock expo-image jest.mock('expo-image', () => ({ Image: 'Image', })) // Mock expo-linear-gradient jest.mock('expo-linear-gradient', () => ({ LinearGradient: 'LinearGradient', })) // Mock expo-blur jest.mock('expo-blur', () => ({ BlurView: 'BlurView', })) // Mock @expo/vector-icons jest.mock('@expo/vector-icons', () => { const mockIonicons = function mockIonicons(props) { return null } return { Ionicons: mockIonicons, MaterialIcons: mockIonicons, FontAwesome: mockIonicons, Feather: mockIonicons, } }) // Mock react-native-safe-area-context jest.mock('react-native-safe-area-context', () => ({ useSafeAreaInsets: () => ({ top: 0, bottom: 0, left: 0, right: 0 }), SafeAreaProvider: ({ children }: any) => children, SafeAreaView: 'SafeAreaView', })) // Mock react-native-gesture-handler jest.mock('react-native-gesture-handler', () => { const mockReact = require('react') const mockRN = require('react-native') // Mock Swipeable component that renders children and right actions const MockSwipeable = mockReact.forwardRef(({ children, renderRightActions, testID, enabled, ...props }, ref) => { return mockReact.createElement(mockRN.View, { testID, ref, ...props }, [ children, renderRightActions && renderRightActions(), ]) }) MockSwipeable.displayName = 'Swipeable' return { GestureDetector: mockRN.View, Gesture: { Tap: () => ({}), Pan: () => ({}), LongPress: () => ({}), Pinch: () => ({}), Rotation: () => ({}), Fling: () => ({}), NativeViewGesture: () => ({}), ForceTouch: () => ({}), ManualGesture: () => ({}), }, GestureHandlerRootView: mockRN.View, RawButton: mockRN.View, BaseButton: mockRN.View, RectButton: mockRN.View, BorderlessButton: mockRN.View, Swipeable: MockSwipeable, State: {}, Directions: {}, } }) jest.mock('expo-linking', () => ({ createURL: (url) => url, parse: (url) => ({ path: url }), })) jest.mock('expo-secure-store', () => ({ getItemAsync: jest.fn(), setItemAsync: jest.fn(), deleteItemAsync: jest.fn(), })) jest.mock('expo-font', () => ({ useFonts: () => [true, null], })) jest.mock('expo-splash-screen', () => ({ preventAutoHideAsync: jest.fn(), hideAsync: jest.fn(), })) // Mock react-native-reanimated jest.mock('react-native-reanimated', () => ({ __esModule: true, default: { createAnimatedComponent: (Component) => Component, call: () => {}, }, useSharedValue: (v) => ({ value: v }), useAnimatedStyle: (fn) => fn(), withTiming: (v) => v, withSpring: (v) => v, withDecay: (v) => v, withRepeat: (v) => v, withSequence: (...args) => args[0], Easing: { linear: (v) => v, ease: (v) => v, quad: (v) => v, cubic: (v) => v, }, runOnJS: (fn) => fn, runOnUI: (fn) => fn, })) // Mock react-native-screens jest.mock('react-native-screens', () => ({ FullWindowOverlay: 'FullWindowOverlay', enableScreens: jest.fn(), })) // Mock nativewind jest.mock('nativewind', () => ({ styled: jest.fn(), })) // Mock @react-navigation/native jest.mock('@react-navigation/native', () => ({ useNavigation: () => ({ navigate: jest.fn(), goBack: jest.fn(), reset: jest.fn(), }), useRoute: () => ({ params: {}, }), NavigationContainer: ({ children }) => children, })) // Mock expo-router jest.mock('expo-router', () => ({ useRouter: () => ({ push: jest.fn(), replace: jest.fn(), back: jest.fn(), }), useLocalSearchParams: () => ({}), useSegments: () => [], usePathname: () => '/', })) // Global mock for console methods to reduce noise in tests global.console = { ...console, error: jest.fn(), warn: jest.fn(), log: jest.fn(), } // Mock @repo/core and @repo/sdk jest.mock('@repo/core', () => ({ root: { get: jest.fn(), }, })) jest.mock('@repo/sdk', () => ({ CategoryController: class MockCategoryController {}, })) // Note: The second react-native mock has been removed to avoid circular dependency issues // The first mock at the top of this file handles all necessary react-native mocking // Mock DevMenu module jest.mock('react-native/src/private/devsupport/devmenu/DevMenu', () => ({ default: {}, })) // Mock SettingsManager module jest.mock('react-native/src/private/specs_DEPRECATED/modules/NativeSettingsManager', () => ({ default: { getConstants: () => ({}), }, })) // Mock lib/auth to avoid TypeScript compilation errors jest.mock('@/lib/auth', () => ({ OWNER_ID: 'test-owner-id', })) // Mock components jest.mock('@/components/icon', () => ({ DownArrowIcon: () => null, PointsIcon: () => null, SearchIcon: () => null, LeftArrowIcon: () => null, UploadIcon: () => null, WhitePointsIcon: () => null, RightArrowIcon: () => null, })) // Mock UI components that have complex dependencies jest.mock('@/components/ui/Text', () => { const mockReact = require('react') const mockRN = require('react-native') const Text = mockReact.forwardRef(({ children, ...props }, ref) => ( mockReact.createElement(mockRN.Text, { ref, ...props }, children) )) Text.displayName = 'Text' return { __esModule: true, default: Text, } }) jest.mock('@/components/ui/Block', () => { const mockReact = require('react') const mockRN = require('react-native') const Block = mockReact.forwardRef(({ children, onClick, ...props }, ref) => { if (onClick) { return mockReact.createElement(mockRN.Pressable, { ref, onPress: onClick, ...props }, children) } return mockReact.createElement(mockRN.View, { ref, ...props }, children) }) Block.displayName = 'Block' return { __esModule: true, default: Block, } }) jest.mock('@/components/ui/button', () => { const mockReact = require('react') const mockRN = require('react-native') return { Button: mockReact.forwardRef(({ children, onPress, disabled, ...props }, ref) => ( mockReact.createElement(mockRN.Pressable, { ref, onPress, disabled, ...props }, children) )), } }) jest.mock('@/components/skeleton/HomeSkeleton', () => ({ HomeSkeleton: () => null, })) // Mock drawer components jest.mock('@/components/drawer/UploadReferenceImageDrawer', () => ({ default: () => null, })) // Mock SearchResultsGrid jest.mock('@/components/SearchResultsGrid', () => ({ default: () => null, })) // Mock FlashList to actually render items jest.mock('@shopify/flash-list', () => { const { View } = require('react-native') return { FlashList: ({ data, renderItem }) => { return data.map((item, index) => renderItem({ item, index })) }, } }) // Mock @gorhom/bottom-sheet jest.mock('@gorhom/bottom-sheet', () => { const { View } = require('react-native') return { BottomSheet: View, BottomSheetView: View, BottomSheetModal: View, BottomSheetModalProvider: ({ children }) => children, BottomSheetScrollView: ({ children }) => children, useBottomSheet: () => ({ snapTo: jest.fn(), expand: jest.fn(), collapse: jest.fn(), close: jest.fn(), }), useBottomSheetModal: () => ({ present: jest.fn(), dismiss: jest.fn(), }), useBottomSheetSpringConfigs: jest.fn(() => ({})), useBottomSheetTimingConfigs: jest.fn(() => ({})), } })