/// // Environment variables are set in setupEnv.js (runs before modules load) // Some modules rely on this global existing in RN. (global as any).__DEV__ = true; jest.mock('@supabase/supabase-js', () => { const makeChannel = () => { const channel: any = { on: jest.fn(() => channel), subscribe: jest.fn(() => channel), send: jest.fn(async () => ({ data: null, error: null })), }; return channel; }; return { createClient: jest.fn(() => ({ auth: { getSession: jest.fn(async () => ({ data: { session: null }, error: null })), getUser: jest.fn(async () => ({ data: { user: null }, error: null })), signOut: jest.fn(async () => ({ error: null })), }, from: jest.fn(() => ({ select: jest.fn(), eq: jest.fn(), neq: jest.fn(), is: jest.fn(), in: jest.fn(), order: jest.fn(), range: jest.fn(), update: jest.fn(), upsert: jest.fn(), insert: jest.fn(), maybeSingle: jest.fn(), })), channel: jest.fn(() => makeChannel()), removeChannel: jest.fn(), storage: { from: jest.fn(() => ({ upload: jest.fn(async () => ({ data: null, error: null })), createSignedUrl: jest.fn(async () => ({ data: { signedUrl: 'https://example.com' }, error: null })), })), }, functions: { invoke: jest.fn(async () => ({ data: null, error: null })), }, })), }; }); jest.mock('react-native-reanimated', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const Reanimated = require('react-native-reanimated/mock'); // The mock is missing `call` in some versions. Reanimated.default.call = () => {}; return Reanimated; }); // Reanimated 3 sometimes requires this when running in Jest. // eslint-disable-next-line no-undef (global as any).__reanimatedWorkletInit = () => {}; jest.mock('expo-linear-gradient', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); // eslint-disable-next-line @typescript-eslint/no-var-requires const { View } = require('react-native'); return { LinearGradient: ({ children, ...props }: any) => React.createElement(View, props, children), }; }); jest.mock('@expo/vector-icons', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); // eslint-disable-next-line @typescript-eslint/no-var-requires const { Text } = require('react-native'); const Icon = ({ name, ...props }: any) => React.createElement(Text, props, name); return { Ionicons: Icon }; }); jest.mock('@react-native-async-storage/async-storage', () => // eslint-disable-next-line @typescript-eslint/no-var-requires require('@react-native-async-storage/async-storage/jest/async-storage-mock') ); jest.mock('expo-image-picker', () => ({ getCameraPermissionsAsync: jest.fn(async () => ({ status: 'undetermined', canAskAgain: true })), requestCameraPermissionsAsync: jest.fn(async () => ({ status: 'granted' })), launchImageLibraryAsync: jest.fn(async () => ({ canceled: true, assets: [] })), launchCameraAsync: jest.fn(async () => ({ canceled: true, assets: [] })), MediaTypeOptions: { All: 'All', Videos: 'Videos', }, })); jest.mock('expo-media-library', () => ({ usePermissions: jest.fn(() => [{ granted: true }, jest.fn(async () => ({ granted: true }))]), createAssetAsync: jest.fn(async () => ({ id: 'mock-asset-id' })), })); jest.mock('expo-file-system/legacy', () => ({ readAsStringAsync: jest.fn(async () => ''), EncodingType: { Base64: 'base64', }, })); jest.mock('expo-video', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const React = require('react'); // eslint-disable-next-line @typescript-eslint/no-var-requires const { View } = require('react-native'); const createPlayer = () => ({ play: jest.fn(), pause: jest.fn(), replay: jest.fn(), replace: jest.fn(), replaceAsync: jest.fn(async () => undefined), seekBy: jest.fn(), addListener: jest.fn(() => ({ remove: jest.fn() })), removeListener: jest.fn(), playing: false, muted: false, loop: false, currentTime: 0, duration: 0, status: 'idle', }); return { useVideoPlayer: jest.fn((source: unknown, setup?: (player: unknown) => void) => { const player = createPlayer(); if (setup) setup(player); return player; }), createVideoPlayer: jest.fn(() => createPlayer()), VideoView: React.forwardRef((props: any, ref: any) => React.createElement(View, { ...props, ref }) ), }; }); jest.mock('expo-audio', () => ({ AudioModule: { AudioRecorder: jest.fn(), }, RecordingPresets: { HIGH_QUALITY: {}, LOW_QUALITY: {}, }, requestRecordingPermissionsAsync: jest.fn(async () => ({ status: 'granted', granted: true })), getRecordingPermissionsAsync: jest.fn(async () => ({ status: 'granted', granted: true })), setAudioModeAsync: jest.fn(async () => undefined), setIsAudioActiveAsync: jest.fn(async () => undefined), useAudioPlayer: jest.fn(), useAudioPlayerStatus: jest.fn(() => ({})), createAudioPlayer: jest.fn(() => ({ play: jest.fn(), pause: jest.fn(), remove: jest.fn(), seekTo: jest.fn(async () => undefined), addListener: jest.fn(() => ({ remove: jest.fn() })), currentTime: 0, duration: 0, playing: false, })), })); jest.mock('react-native-compressor', () => ({ Video: { compress: jest.fn(async (uri: string) => uri), }, })); jest.mock('base64-arraybuffer', () => ({ decode: jest.fn(() => new ArrayBuffer(0)), })); jest.mock('@react-native-firebase/app', () => ({ getApp: jest.fn(() => ({})), })); jest.mock('@react-native-firebase/analytics', () => ({ getAnalytics: jest.fn(() => ({})), logEvent: jest.fn(), setUserId: jest.fn(), setUserProperty: jest.fn(), setAnalyticsCollectionEnabled: jest.fn(() => Promise.resolve()), resetAnalyticsData: jest.fn(), }));