锁定移动图片权限请求失败边界
移动文件桥接把相册权限请求失败转为结构化 host_error 移动文件桥接把相机权限请求失败转为结构化 host_error 移动文件单测覆盖权限请求失败不启动原生选择器 移动壳配置检查反查权限请求失败边界
This commit is contained in:
@@ -2079,9 +2079,14 @@ for (const snippet of [
|
||||
"code: 'unsupported_capability'",
|
||||
"code: 'cancelled'",
|
||||
'rejects image import before picker launch when library permission is denied',
|
||||
'rejects image import before picker launch when library permission request fails',
|
||||
'rejects image capture before camera launch when camera permission request fails',
|
||||
"message: 'photo library permission denied'",
|
||||
"message: 'photo library permission unavailable'",
|
||||
'expect(imageLibraryMock).not.toHaveBeenCalled()',
|
||||
"message: 'camera permission denied'",
|
||||
"message: 'camera permission unavailable'",
|
||||
'expect(cameraMock).not.toHaveBeenCalled()',
|
||||
"mediaTypes: ['images']",
|
||||
"options: { encoding: 'base64' }",
|
||||
]) {
|
||||
|
||||
@@ -303,6 +303,26 @@ describe('mobile HostBridge file actions', () => {
|
||||
expect(imageLibraryMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('rejects image import before picker launch when library permission request fails', async () => {
|
||||
libraryPermissionMock.mockRejectedValueOnce(new Error('native permission failed'));
|
||||
|
||||
await expect(importImageFile()).rejects.toMatchObject({
|
||||
code: 'host_error',
|
||||
message: 'photo library permission unavailable',
|
||||
});
|
||||
expect(imageLibraryMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('rejects image capture before camera launch when camera permission request fails', async () => {
|
||||
cameraPermissionMock.mockRejectedValueOnce(new Error('native permission failed'));
|
||||
|
||||
await expect(captureImageFile()).rejects.toMatchObject({
|
||||
code: 'host_error',
|
||||
message: 'camera permission unavailable',
|
||||
});
|
||||
expect(cameraMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('imports audio and exports binary files through controlled payloads', async () => {
|
||||
fileBase64Data.set('file:///picked/voice.mp3', MP3_BASE64);
|
||||
fileSizes.set('file:///picked/voice.mp3', Buffer.byteLength('ID3\x04\x00\x00\x00\x00\x00\x10'));
|
||||
|
||||
@@ -270,7 +270,15 @@ export async function exportMobileHostBridgeImageFile(
|
||||
}
|
||||
|
||||
export async function importImageFile(): Promise<FileImportImageResult> {
|
||||
const permission = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
let permission: ImagePicker.MediaLibraryPermissionResponse;
|
||||
try {
|
||||
permission = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
} catch {
|
||||
throw {
|
||||
code: 'host_error',
|
||||
message: 'photo library permission unavailable',
|
||||
} satisfies HostBridgeError;
|
||||
}
|
||||
if (permission.status !== ImagePicker.PermissionStatus.GRANTED) {
|
||||
throw {
|
||||
code: 'host_error',
|
||||
@@ -301,7 +309,15 @@ export async function importMobileHostBridgeImageFile(
|
||||
}
|
||||
|
||||
export async function captureImageFile(): Promise<FileImportImageResult> {
|
||||
const permission = await ImagePicker.requestCameraPermissionsAsync();
|
||||
let permission: ImagePicker.CameraPermissionResponse;
|
||||
try {
|
||||
permission = await ImagePicker.requestCameraPermissionsAsync();
|
||||
} catch {
|
||||
throw {
|
||||
code: 'host_error',
|
||||
message: 'camera permission unavailable',
|
||||
} satisfies HostBridgeError;
|
||||
}
|
||||
if (permission.status !== ImagePicker.PermissionStatus.GRANTED) {
|
||||
throw {
|
||||
code: 'host_error',
|
||||
|
||||
Reference in New Issue
Block a user