expo-popcore-app/jest.setup.js

391 lines
9.7 KiB
JavaScript

// Mock react-native-css-interop FIRST to avoid appearance listener issues
jest.mock('react-native-css-interop', () => ({
__esModule: true,
}))
// Mock react-native BEFORE any other imports to avoid flow type issues
jest.mock('react-native', () => {
const React = require('react')
return {
RefreshControl: 'RefreshControl',
ScrollView: 'ScrollView',
FlatList: 'FlatList',
View: 'View',
Text: 'Text',
Image: 'Image',
Pressable: 'Pressable',
TouchableOpacity: 'TouchableOpacity',
TextInput: 'TextInput',
ActivityIndicator: 'ActivityIndicator',
Platform: {
OS: 'web',
select: (obj) => obj.web || obj.default,
},
Animated: {
View: 'Animated.View',
Text: 'Animated.Text',
Image: 'Animated.Image',
Value: class MockValue {
constructor(v) { this._value = v }
setValue(v) { this._value = v }
__getValue() { return this._value }
interpolate() { return this }
},
timing: () => ({ start: jest.fn() }),
spring: () => ({ start: jest.fn() }),
event: () => jest.fn(),
},
PanResponder: {
create: () => ({ panHandlers: {} }),
},
ActivityIndicator: 'ActivityIndicator',
StyleSheet: { create: (styles) => styles },
Dimensions: { get: () => ({ width: 375, height: 812 }) },
StatusBar: 'StatusBar',
SafeAreaView: 'SafeAreaView',
useSafeAreaInsets: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
NativeModules: {
DevMenu: {},
SettingsManager: {},
},
Settings: {
get: jest.fn(),
set: jest.fn(),
},
Alert: {
alert: jest.fn(),
},
Linking: {
openURL: jest.fn(),
},
Appearance: {
getColorScheme: jest.fn(() => 'light'),
addChangeListener: jest.fn(),
removeChangeListener: jest.fn(),
},
BackHandler: {
addEventListener: jest.fn(() => ({ remove: jest.fn() })),
removeEventListener: jest.fn(),
},
}
})
require('@testing-library/jest-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 { View } = require('react-native')
return {
GestureDetector: View,
Gesture: {
Tap: () => ({}),
Pan: () => ({}),
LongPress: () => ({}),
Pinch: () => ({}),
Rotation: () => ({}),
Fling: () => ({}),
NativeViewGesture: () => ({}),
ForceTouch: () => ({}),
ManualGesture: () => ({}),
},
GestureHandlerRootView: View,
RawButton: View,
BaseButton: View,
RectButton: View,
BorderlessButton: View,
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(() => ({})),
}
})