import { describe, expect, test, vi } from 'vitest'; import { HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES, HOST_BRIDGE_METHODS, HOST_BRIDGE_PROTOCOL, HOST_BRIDGE_VERSION, type HostBridgeMethod, type HostBridgeRequest, } from '../../../../packages/shared/src/contracts/hostBridge'; import { dispatchMobileHostBridgeRequest, resetMobileHostBridgeDispatchForTest, } from './dispatch'; vi.mock('expo-clipboard', () => ({ getStringAsync: vi.fn(), setStringAsync: vi.fn(), })); vi.mock('expo-document-picker', () => ({ getDocumentAsync: vi.fn(), })); vi.mock('expo-file-system', () => ({ File: class TestFile {}, Paths: { cache: 'file:///cache/', }, })); vi.mock('expo-haptics', () => ({ ImpactFeedbackStyle: { Heavy: 'heavy', Light: 'light', Medium: 'medium', }, impactAsync: vi.fn(), })); vi.mock('expo-image-picker', () => ({ PermissionStatus: { DENIED: 'denied', GRANTED: 'granted', }, launchCameraAsync: vi.fn(), launchImageLibraryAsync: vi.fn(), requestCameraPermissionsAsync: vi.fn(), requestMediaLibraryPermissionsAsync: vi.fn(), })); vi.mock('expo-linking', () => ({ canOpenURL: vi.fn(), openURL: vi.fn(), })); vi.mock('expo-network', () => ({ getNetworkStateAsync: vi.fn(), NetworkStateType: { CELLULAR: 'CELLULAR', ETHERNET: 'ETHERNET', NONE: 'NONE', WIFI: 'WIFI', }, })); vi.mock('expo-notifications', () => ({ AndroidImportance: { DEFAULT: 'default', }, getPermissionsAsync: vi.fn(), IosAuthorizationStatus: { PROVISIONAL: 3, }, requestPermissionsAsync: vi.fn(), scheduleNotificationAsync: vi.fn(), setNotificationChannelAsync: vi.fn(), setNotificationHandler: vi.fn(), })); vi.mock('expo-sharing', () => ({ isAvailableAsync: vi.fn(), shareAsync: vi.fn(), })); vi.mock('react-native', () => ({ Appearance: { getColorScheme: vi.fn(), }, Platform: { OS: 'android', }, })); function request(method: HostBridgeMethod): HostBridgeRequest { return { bridge: HOST_BRIDGE_PROTOCOL, version: HOST_BRIDGE_VERSION, id: `dispatch-${method}`, method, }; } const IOS_UNDECLARED_HOST_BRIDGE_METHODS = HOST_BRIDGE_METHODS.filter( (method) => !HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES.includes(method), ); describe('mobile HostBridge dispatch', () => { test.each(IOS_UNDECLARED_HOST_BRIDGE_METHODS)( '%s 未被移动壳声明时明确返回 unsupported', async (method) => { resetMobileHostBridgeDispatchForTest(); const response = await dispatchMobileHostBridgeRequest(request(method)); expect(response.ok).toBe(false); if (response.ok) { throw new Error(`${method} unexpectedly succeeded`); } expect(response.error.code).toBe('unsupported_method'); expect(response.error.message).toContain(method); }, ); });