mattermost-mobile/app/utils/file/file_picker/index.test.ts
Elias Nahum d1d3fda83a
Request metrics improvements (#8420)
* Network metrics

* update network-client ref

* fix unit tests

* missing catch error parsing

* Replace API's to fetch all teams and channels for a user
Update groupLabel to use a type definition
Include effective Latency and Average Speed in the metrics
Include parallel and sequential request counts

* update network library and fix tests

* feat(MM-61865): send network request telemetry data to the server (#8436)

* feat(MM-61865): send network info telemetry data

* unit testing

* fix latency vs effectiveLatency

* cleanup test

* fix failing tests

* fix spelling error

* fix failing test

* more cleanup

* fix: improve parallel requests calculation (#8439)

* fix: improve parallel requests calculation

* fix test issue

* multiple parallelGroups testing

* calculateAverageSpeedWithCategories test

* categorizedRequests in it's own describe

* clean up duplicate tests

* check for when groupLabel is non-existent

* a case when groupLabel is non-existent

* more testing with effective latency.

* resolveAndFlattenModels with a capital F

* add try..catch within resolveAndFlattenModels

* update groupLabel to fix failing lint

* fix linting issue due to unknown group label

* forgot to push changes

* fix the indentation problem again

* add env var option for COLLECT_NETWORK_METRICS

---------

Co-authored-by: Rahim Rahman <rahim.rahman@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2025-01-16 13:55:29 -07:00

718 lines
29 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable max-lines */
import RNUtils from '@mattermost/rnutils';
import {applicationName} from 'expo-application';
import {Alert, Platform} from 'react-native';
import DocumentPicker, {type DocumentPickerResponse} from 'react-native-document-picker';
import {launchCamera, launchImageLibrary, type Asset, type ImagePickerResponse} from 'react-native-image-picker';
import Permissions from 'react-native-permissions';
import {dismissBottomSheet} from '@screens/navigation';
import TestHelper from '@test/test_helper';
import {extractFileInfo, lookupMimeType} from '@utils/file';
import {getIntlShape} from '@utils/general';
import {logWarning} from '@utils/log';
import FilePickerUtil from '.';
jest.mock('expo-file-system');
jest.mock('react-native-image-picker');
jest.mock('react-native-document-picker', () => ({
pick: jest.fn(async () => []),
}));
jest.mock('@screens/navigation', () => ({
dismissBottomSheet: jest.fn(),
}));
jest.mock('@utils/file', () => ({
extractFileInfo: jest.fn(),
lookupMimeType: jest.fn(),
}));
jest.mock('@utils/log', () => ({
logWarning: jest.fn(),
}));
jest.mock('@mattermost/rnutils', () => ({
getRealFilePath: jest.fn(),
isRunningInSplitView: jest.fn().mockReturnValue({isSplit: false, isTablet: false}),
getConstants: jest.fn().mockReturnValue({
appGroupIdentifier: 'group.mattermost.rnbeta',
appGroupSharedDirectory: {
sharedDirectory: '',
databasePath: '',
},
}),
}));
describe('FilePickerUtil', () => {
const mockUploadFiles = jest.fn();
const intl = getIntlShape();
const originalSelect = Platform.select;
let filePickerUtil: FilePickerUtil;
beforeAll(() => {
Platform.select = ({android, ios, default: dft}: any) => {
if (Platform.OS === 'android' && android) {
return android;
} else if (Platform.OS === 'ios' && ios) {
return ios;
}
return dft;
};
});
afterAll(() => {
Platform.select = originalSelect;
});
beforeEach(() => {
Platform.OS = 'ios';
filePickerUtil = new FilePickerUtil(intl, mockUploadFiles);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('private functions', () => {
test('should assign intl and uploadFiles correctly in the constructor', () => {
// @ts-expect-error intl is private
expect(filePickerUtil.intl).toBe(intl);
// @ts-expect-error uploadFiles is private
expect(filePickerUtil.uploadFiles).toBe(mockUploadFiles);
});
test('should return correct permission messages for camera', () => {
const camera = {
title: `${applicationName} would like to access your camera`,
text: `Take photos and upload them to your server or save them to your device. Open Settings to grant ${applicationName} read and write access to your camera.`,
};
// @ts-expect-error getPermissionMessages is private
const result = filePickerUtil.getPermissionMessages('camera');
expect(result).toEqual(camera);
});
test('should return correct permission messages for storage', () => {
const expected = {
title: `${applicationName} would like to access your files`,
text: `Upload files to your server. Open Settings to grant ${applicationName} Read and Write access to files on this device.`,
};
// @ts-expect-error getPermissionMessages is private
const result = filePickerUtil.getPermissionMessages('storage');
expect(result).toEqual(expected);
});
test('should return correct permission messages for photo_ios', () => {
const expected = {
title: `${applicationName} would like to access your photos`,
text: `Upload photos and videos to your server or save them to your device. Open Settings to grant ${applicationName} Read and Write access to your photo and video library.`,
};
// @ts-expect-error getPermissionMessages is private
const result = filePickerUtil.getPermissionMessages('photo_ios');
expect(result).toEqual(expected);
});
test('should return correct permission messages for photo_android', () => {
const expected = {
title: `${applicationName} would like to access your photos`,
text: `Upload photos to your server or save them to your device. Open Settings to grant ${applicationName} Read and Write access to your photo library.`,
};
// @ts-expect-error getPermissionMessages is private
const result = filePickerUtil.getPermissionMessages('photo_android');
expect(result).toEqual(expected);
});
test('should prepare file upload correctly', async () => {
const mockFiles = [{uri: 'file://test'}] as Array<Asset | DocumentPickerResponse>;
const mockExtractedFiles = [{uri: 'file://test', name: 'test'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
// @ts-expect-error prepareFileUpload is private
await filePickerUtil.prepareFileUpload(mockFiles);
expect(extractFileInfo).toHaveBeenCalledWith(mockFiles);
expect(dismissBottomSheet).toHaveBeenCalled();
expect(mockUploadFiles).toHaveBeenCalledWith(mockExtractedFiles);
});
test('should not upload files if extraction returns an empty array', async () => {
const mockFiles = [{uri: 'file://test'}] as Array<Asset | DocumentPickerResponse>;
(extractFileInfo as jest.Mock).mockResolvedValue([]);
// @ts-expect-error prepareFileUpload is private
await filePickerUtil.prepareFileUpload(mockFiles);
expect(extractFileInfo).toHaveBeenCalledWith(mockFiles);
expect(dismissBottomSheet).not.toHaveBeenCalled();
expect(mockUploadFiles).not.toHaveBeenCalled();
});
test('should return correct permission denied message with source', () => {
const expected = {
title: `${applicationName} would like to access your files`,
text: `Upload files to your server. Open Settings to grant ${applicationName} Read and Write access to files on this device.`,
};
// @ts-expect-error getPermissionDeniedMessage is private
const result = filePickerUtil.getPermissionDeniedMessage('storage');
expect(result).toEqual(expected);
});
test('should return correct permission denied message without source', () => {
Platform.OS = 'android';
const expected = {
title: `${applicationName} would like to access your photos`,
text: `Upload photos to your server or save them to your device. Open Settings to grant ${applicationName} Read and Write access to your photo library.`,
};
// @ts-expect-error getPermissionDeniedMessage is private
const result = filePickerUtil.getPermissionDeniedMessage();
expect(result).toEqual(expected);
});
test('should return files from response correctly on iOS', async () => {
const mockResponse = {
assets: [{uri: 'file://test', type: 'image/jpeg'}],
} as ImagePickerResponse;
// @ts-expect-error getFilesFromResponse is private
const result = await filePickerUtil.getFilesFromResponse(mockResponse);
expect(result).toEqual(mockResponse.assets);
expect(logWarning).not.toHaveBeenCalled();
});
test('should return files from response correctly on Android', async () => {
Platform.OS = 'android';
const mockResponse = {
assets: [{uri: 'file://test', type: 'image/jpeg', fileName: 'test.jpg'}],
} as ImagePickerResponse;
(RNUtils.getRealFilePath as jest.Mock).mockResolvedValue('file://real_path');
(lookupMimeType as jest.Mock).mockReturnValue('image/jpeg');
// @ts-expect-error getFilesFromResponse is private
const result = await filePickerUtil.getFilesFromResponse(mockResponse);
expect(result).toEqual([{...mockResponse.assets![0], uri: 'file://real_path'}]);
expect(RNUtils.getRealFilePath).toHaveBeenCalledWith('file://test');
});
test('should log warning if no assets in response', async () => {
const mockResponse = {} as ImagePickerResponse;
// @ts-expect-error getFilesFromResponse is private
const result = await filePickerUtil.getFilesFromResponse(mockResponse);
expect(result).toEqual([]);
expect(logWarning).toHaveBeenCalledWith('no assets in response');
});
test('should log warning if attaching file returns empty uri on Android', async () => {
Platform.OS = 'android';
const mockResponse = {
assets: [{uri: 'file://test', type: 'image/jpeg', fileName: 'test.jpg'}],
} as ImagePickerResponse;
(RNUtils.getRealFilePath as jest.Mock).mockResolvedValue('');
// @ts-expect-error getFilesFromResponse is private
const result = await filePickerUtil.getFilesFromResponse(mockResponse);
expect(result).toEqual([]);
expect(logWarning).toHaveBeenCalledWith('attaching file reponse return empty uri', mockResponse.assets![0]);
});
test('should check and request photo permission correctly', async () => {
Platform.OS = 'ios';
const source = 'camera';
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
// @ts-expect-error hasPhotoPermission is private
const result = await filePickerUtil.hasPhotoPermission(source);
expect(Permissions.check).toHaveBeenCalledWith(Permissions.PERMISSIONS.IOS.CAMERA);
expect(Permissions.request).toHaveBeenCalledWith(Permissions.PERMISSIONS.IOS.CAMERA);
expect(result).toBe(true);
});
test('should handle blocked photo permission correctly on iOS', async () => {
const source = 'camera';
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.BLOCKED);
const alertSpy = jest.spyOn(Alert, 'alert');
// @ts-expect-error hasPhotoPermission is private
const result = await filePickerUtil.hasPhotoPermission(source);
expect(Permissions.check).toHaveBeenCalledWith(Permissions.PERMISSIONS.IOS.CAMERA);
expect(alertSpy).toHaveBeenCalled();
expect(result).toBe(false);
});
test('should check and request storage permission correctly on Android', async () => {
Platform.OS = 'android';
Platform.Version = 31;
const storagePermission = Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE;
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
// @ts-expect-error hasStoragePermission is private
const result = await filePickerUtil.hasStoragePermission();
expect(Permissions.check).toHaveBeenCalledWith(storagePermission);
expect(Permissions.request).toHaveBeenCalledWith(storagePermission);
expect(result).toBe(true);
});
test('should handle blocked storage permission correctly on Android', async () => {
Platform.OS = 'android';
Platform.Version = 31;
const storagePermission = Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE;
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.BLOCKED);
const alertSpy = jest.spyOn(Alert, 'alert');
// @ts-expect-error hasStoragePermission is private
const result = await filePickerUtil.hasStoragePermission();
expect(Permissions.check).toHaveBeenCalledWith(storagePermission);
expect(alertSpy).toHaveBeenCalled();
expect(result).toBe(false);
});
test('should check and request write storage permission correctly on Android', async () => {
Platform.OS = 'android';
Platform.Version = 28;
const storagePermission = Permissions.PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE;
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
// @ts-expect-error hasWriteStoragePermission is private
const result = await filePickerUtil.hasWriteStoragePermission();
expect(Permissions.check).toHaveBeenCalledWith(storagePermission);
expect(Permissions.request).toHaveBeenCalledWith(storagePermission);
expect(result).toBe(true);
});
test('should handle blocked write storage permission correctly on Android', async () => {
Platform.OS = 'android';
Platform.Version = 28;
const storagePermission = Permissions.PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE;
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.BLOCKED);
const alertSpy = jest.spyOn(Alert, 'alert');
// @ts-expect-error hasWriteStoragePermission is private
const result = await filePickerUtil.hasWriteStoragePermission();
expect(Permissions.check).toHaveBeenCalledWith(storagePermission);
expect(alertSpy).toHaveBeenCalled();
expect(result).toBe(false);
});
test('should build URI correctly on Android', async () => {
Platform.OS = 'android';
const doc = {uri: 'file://test', fileCopyUri: 'file://copy_test'} as DocumentPickerResponse;
// @ts-expect-error buildUri is private
const result = await filePickerUtil.buildUri(doc);
expect(result).toEqual({doc: {uri: 'file://copy_test', fileCopyUri: 'file://copy_test'}});
});
test('should handle undefined new URI on Android', async () => {
Platform.OS = 'android';
const doc = {uri: 'file://test'} as DocumentPickerResponse;
(RNUtils.getRealFilePath as jest.Mock).mockResolvedValue(null);
// @ts-expect-error buildUri is private
const result = await filePickerUtil.buildUri(doc);
expect(result).toEqual({doc: undefined});
});
});
describe('attachFileFromCamera', () => {
test('should build URI correctly when fileCopyUri is undefined on Android', async () => {
Platform.OS = 'android';
const doc = {uri: 'file://test'} as DocumentPickerResponse;
(RNUtils.getRealFilePath as jest.Mock).mockResolvedValue('file://real_path');
// @ts-expect-error buildUri is private
const result = await filePickerUtil.buildUri(doc);
expect(result).toEqual({doc: {uri: 'file://real_path'}});
});
test('should not launch camera if permission is denied', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
const launchCameraMock = launchCamera as jest.Mock;
await filePickerUtil.attachFileFromCamera();
expect(Permissions.check).toHaveBeenCalledWith(expect.any(String));
expect(launchCameraMock).not.toHaveBeenCalled();
});
test('should launch camera if permission is granted', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const launchCameraMock = launchCamera as jest.Mock;
launchCameraMock.mockImplementation((options, callback) => {
callback({assets: [{uri: 'file://camera_photo.jpg', type: 'image/jpeg', fileName: 'photo.jpg'}]});
});
const mockExtractedFiles = [{fileName: 'photo.jpg', type: 'image/jpeg', uri: 'file://real_camera_photo.jpg'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
await filePickerUtil.attachFileFromCamera();
expect(launchCameraMock).toHaveBeenCalled();
await TestHelper.wait(100);
expect(mockUploadFiles).toHaveBeenCalledWith([{
uri: 'file://real_camera_photo.jpg',
type: 'image/jpeg',
fileName: 'photo.jpg',
}]);
});
test('should handle cancelled camera response', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const launchCameraMock = launchCamera as jest.Mock;
launchCameraMock.mockImplementation((options, callback) => {
callback({didCancel: true});
});
await filePickerUtil.attachFileFromCamera();
expect(launchCameraMock).toHaveBeenCalled();
expect(mockUploadFiles).not.toHaveBeenCalled();
});
test('should handle camera error response', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const launchCameraMock = launchCamera as jest.Mock;
launchCameraMock.mockImplementation((options, callback) => {
callback({errorCode: 'camera_unavailable'});
});
await filePickerUtil.attachFileFromCamera();
expect(launchCameraMock).toHaveBeenCalled();
expect(mockUploadFiles).not.toHaveBeenCalled();
});
test('should request write storage permission for Android API <= 28', async () => {
Platform.OS = 'android';
Platform.Version = 28;
(Permissions.check as jest.Mock).mockImplementation((permission) => {
if (permission === Permissions.PERMISSIONS.ANDROID.CAMERA) {
return Permissions.RESULTS.GRANTED;
}
return Permissions.RESULTS.DENIED;
});
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const mockExtractedFiles = [{fileName: 'photo.jpg', type: 'image/jpeg', uri: 'file://real_camera_photo.jpg'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
const launchCameraMock = launchCamera as jest.Mock;
launchCameraMock.mockImplementation((options, callback) => {
callback({assets: [{uri: 'file://camera_photo.jpg', type: 'image/jpeg', fileName: 'photo.jpg'}]});
});
await filePickerUtil.attachFileFromCamera();
expect(Permissions.check).toHaveBeenCalledWith(Permissions.PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
expect(launchCameraMock).toHaveBeenCalled();
await TestHelper.wait(100);
expect(mockUploadFiles).toHaveBeenCalledWith([{
uri: 'file://real_camera_photo.jpg',
type: 'image/jpeg',
fileName: 'photo.jpg',
}]);
});
test('should not launch camera if write storage permission is denied on Android API <= 28', async () => {
Platform.OS = 'android';
Platform.Version = 28;
(Permissions.check as jest.Mock).mockImplementation((permission) => {
if (permission === Permissions.PERMISSIONS.ANDROID.CAMERA) {
return Permissions.RESULTS.GRANTED;
}
return Permissions.RESULTS.DENIED;
});
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
const launchCameraMock = launchCamera as jest.Mock;
await filePickerUtil.attachFileFromCamera();
expect(Permissions.check).toHaveBeenCalledWith(Permissions.PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
expect(launchCameraMock).not.toHaveBeenCalled();
});
});
describe('attachFileFromFiles', () => {
test('should not pick files if permission is denied', async () => {
Platform.OS = 'android';
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
const result = await filePickerUtil.attachFileFromFiles();
expect(DocumentPicker.pick).not.toHaveBeenCalled();
expect(result).toEqual({error: 'no permission'});
});
test('should pick files if permission is granted', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const docResponse: DocumentPickerResponse[] = [
{
uri: 'file://document.pdf',
fileCopyUri: 'file://copy_document.pdf',
name: 'document',
type: 'pdf',
size: 10,
},
];
(DocumentPicker.pick as jest.Mock).mockResolvedValue(docResponse);
const mockExtractedFiles = [{uri: 'file://real_document.pdf'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
const result = await filePickerUtil.attachFileFromFiles();
expect(DocumentPicker.pick).toHaveBeenCalledWith({
allowMultiSelection: false,
type: ['public.item'],
copyTo: 'cachesDirectory',
});
await TestHelper.wait(100);
expect(mockUploadFiles).toHaveBeenCalledWith([
{uri: 'file://real_document.pdf'},
]);
expect(result).toEqual({error: undefined});
});
test('should return error on DocumentPicker failure', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const pickerError = new Error('Picker failed');
(DocumentPicker.pick as jest.Mock).mockRejectedValue(pickerError);
const result = await filePickerUtil.attachFileFromFiles();
expect(DocumentPicker.pick).toHaveBeenCalled();
expect(result).toEqual({error: pickerError});
});
test('should allow multi-selection when specified', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const mockExtractedFiles = [
{uri: 'file://real_document1.pdf'},
{uri: 'file://real_document2.pdf'},
];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
const docResponse = [
{uri: 'file://document1.pdf'},
{uri: 'file://document2.pdf'},
];
(DocumentPicker.pick as jest.Mock).mockResolvedValue(docResponse);
const result = await filePickerUtil.attachFileFromFiles(undefined, true);
expect(DocumentPicker.pick).toHaveBeenCalledWith({
allowMultiSelection: true,
type: ['public.item'],
copyTo: 'cachesDirectory',
});
expect(mockUploadFiles).toHaveBeenCalledWith([
{uri: 'file://real_document1.pdf'},
{uri: 'file://real_document2.pdf'},
]);
expect(result).toEqual({error: undefined});
});
test('should use specified file type', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const mockExtractedFiles = [{uri: 'file://real_image.jpg'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
const docResponse = [{uri: 'file://image.jpg', fileCopyUri: 'file://copy_image.jpg'}];
(DocumentPicker.pick as jest.Mock).mockResolvedValue(docResponse);
const result = await filePickerUtil.attachFileFromFiles('image/*');
expect(DocumentPicker.pick).toHaveBeenCalledWith({
allowMultiSelection: false,
type: ['image/*'],
copyTo: 'cachesDirectory',
});
expect(mockUploadFiles).toHaveBeenCalledWith([
{uri: 'file://real_image.jpg'},
]);
expect(result).toEqual({error: undefined});
});
test('should default to Android file type if specified', async () => {
Platform.OS = 'android';
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const docResponse = [{uri: 'file://document.pdf'}];
const mockExtractedFiles = [{uri: 'file://real_document.pdf'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
(DocumentPicker.pick as jest.Mock).mockResolvedValue(docResponse);
const result = await filePickerUtil.attachFileFromFiles();
expect(DocumentPicker.pick).toHaveBeenCalledWith({
allowMultiSelection: false,
type: ['*/*'],
copyTo: 'cachesDirectory',
});
expect(mockUploadFiles).toHaveBeenCalledWith([
{uri: 'file://real_document.pdf'},
]);
expect(result).toEqual({error: undefined});
});
});
describe('attachFileFromPhotoGallery', () => {
test('should not open the image library if permission is denied', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
(Permissions.request as jest.Mock).mockResolvedValue(Permissions.RESULTS.DENIED);
await filePickerUtil.attachFileFromPhotoGallery();
expect(launchImageLibrary).not.toHaveBeenCalled();
});
test('should open the image library if permission is granted', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const response: ImagePickerResponse = {
assets: [{uri: 'file://image1.jpg'}],
};
(launchImageLibrary as jest.Mock).mockImplementation((options, callback) => callback(response));
const mockExtractedFiles = [{uri: 'file://real_image1.jpg'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
await filePickerUtil.attachFileFromPhotoGallery();
expect(launchImageLibrary).toHaveBeenCalledWith({
quality: 1,
mediaType: 'mixed',
includeBase64: false,
selectionLimit: 1,
}, expect.any(Function));
await TestHelper.wait(100);
expect(mockUploadFiles).toHaveBeenCalledWith([
{uri: 'file://real_image1.jpg'},
]);
});
test('should handle error or cancellation in image library response', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const response: ImagePickerResponse = {
errorMessage: 'An error occurred',
didCancel: false,
};
(launchImageLibrary as jest.Mock).mockImplementation((options, callback) => callback(response));
await filePickerUtil.attachFileFromPhotoGallery();
expect(logWarning).toHaveBeenCalledWith('Attach failed', 'An error occurred');
const cancelledResponse: ImagePickerResponse = {
errorMessage: '',
didCancel: true,
};
(launchImageLibrary as jest.Mock).mockImplementation((options, callback) => callback(cancelledResponse));
await filePickerUtil.attachFileFromPhotoGallery();
expect(logWarning).toHaveBeenCalledWith('Attach failed', 'cancelled');
});
test('should handle selection limit parameter', async () => {
(Permissions.check as jest.Mock).mockResolvedValue(Permissions.RESULTS.GRANTED);
const response: ImagePickerResponse = {
assets: [{uri: 'file://image1.jpg'}, {uri: 'file://image2.jpg'}],
};
(launchImageLibrary as jest.Mock).mockImplementation((options, callback) => callback(response));
const mockExtractedFiles = [{uri: 'file://real_image1.jpg'}, {uri: 'file://real_image2.jpg'}];
(extractFileInfo as jest.Mock).mockResolvedValue(mockExtractedFiles);
await filePickerUtil.attachFileFromPhotoGallery(2);
expect(launchImageLibrary).toHaveBeenCalledWith({
quality: 1,
mediaType: 'mixed',
includeBase64: false,
selectionLimit: 2,
}, expect.any(Function));
});
});
});