1import Constants from 'expo-constants'; 2import * as ImagePicker from 'expo-image-picker'; 3import { Platform } from 'react-native'; 4 5import { alertAndWaitForResponse } from './helpers'; 6import * as TestUtils from '../TestUtils'; 7import { isDeviceFarm } from '../utils/Environment'; 8 9export const name = 'ImagePicker'; 10 11export async function test({ it, beforeAll, expect, jasmine, describe, afterAll }) { 12 function testMediaObjectShape(shape, type) { 13 expect(shape).toBeDefined(); 14 15 expect(typeof shape.uri).toBe('string'); 16 expect(typeof shape.width).toBe('number'); 17 expect(typeof shape.height).toBe('number'); 18 expect(typeof shape.type).toBe('string'); 19 20 expect(shape.uri).not.toBe(''); 21 expect(shape.width).toBeGreaterThan(0); 22 expect(shape.height).toBeGreaterThan(0); 23 24 expect(typeof shape.type).toBe('string'); 25 26 if (type) { 27 expect(shape.type).toBe(type); 28 } 29 30 if (shape.type === 'video') { 31 expect(typeof shape.duration).toBe('number'); 32 expect(shape.duration).toBeGreaterThan(0); 33 } 34 } 35 function testResultShape(result, type) { 36 expect(result.canceled).toBe(false); 37 38 for (const asset of result.assets) { 39 testMediaObjectShape(asset, type); 40 } 41 } 42 43 describe(name, () => { 44 if (isDeviceFarm()) return; 45 46 let originalTimeout; 47 48 beforeAll(async () => { 49 await TestUtils.acceptPermissionsAndRunCommandAsync(() => { 50 return ImagePicker.requestMediaLibraryPermissionsAsync(); 51 }); 52 await TestUtils.acceptPermissionsAndRunCommandAsync(() => { 53 return ImagePicker.requestCameraPermissionsAsync(); 54 }); 55 originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; 56 jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout * 10; 57 }); 58 59 describe('launchCameraAsync', () => { 60 if (Constants.isDevice) { 61 it('launches the camera', async () => { 62 await alertAndWaitForResponse('Please take a picture for this test to pass.'); 63 const result = await ImagePicker.launchCameraAsync(); 64 65 testResultShape(result); 66 }); 67 68 it('cancels the camera', async () => { 69 await alertAndWaitForResponse('Please cancel the camera for this test to pass.'); 70 const result = await ImagePicker.launchCameraAsync(); 71 expect(result.canceled).toBe(true); 72 expect(result.assets).toBe(null); 73 }); 74 } else { 75 it('natively prevents the camera from launching on a simulator', async () => { 76 let err; 77 try { 78 await ImagePicker.launchCameraAsync(); 79 } catch ({ code }) { 80 err = code; 81 } 82 expect(err).toBe('CAMERA_MISSING'); 83 }); 84 } 85 }); 86 87 describe('launchImageLibraryAsync', async () => { 88 it('mediaType: image', async () => { 89 await alertAndWaitForResponse('Please choose an image.'); 90 const result = await ImagePicker.launchImageLibraryAsync({ 91 mediaTypes: ImagePicker.MediaTypeOptions.Images, 92 }); 93 testResultShape(result, 'image'); 94 }); 95 96 it('mediaType: video', async () => { 97 await alertAndWaitForResponse('Please choose a video.'); 98 const result = await ImagePicker.launchImageLibraryAsync({ 99 mediaTypes: ImagePicker.MediaTypeOptions.Videos, 100 }); 101 testResultShape(result, 'video'); 102 }); 103 104 it('allows editing', async () => { 105 await alertAndWaitForResponse('Please choose an image to crop.'); 106 const result = await ImagePicker.launchImageLibraryAsync({ 107 mediaTypes: ImagePicker.MediaTypeOptions.Images, 108 allowsEditing: true, 109 }); 110 testResultShape(result, 'image'); 111 }); 112 113 it('allows editing and returns base64', async () => { 114 await alertAndWaitForResponse('Please choose an image to crop.'); 115 const result = await ImagePicker.launchImageLibraryAsync({ 116 mediaTypes: ImagePicker.MediaTypeOptions.Images, 117 allowsEditing: true, 118 base64: true, 119 }); 120 121 testResultShape(result, 'image'); 122 123 for (const image of result.assets) { 124 expect(typeof image.base64).toBe('string'); 125 expect(image.base64).not.toBe(''); 126 expect(image.base64).not.toContain('\n'); 127 expect(image.base64).not.toContain('\r'); 128 } 129 }); 130 131 if (Platform.OS === 'ios' && parseInt(Platform.Version, 10) > 10) { 132 it('videoExportPreset should affect video dimensions', async () => { 133 const result = await ImagePicker.launchImageLibraryAsync({ 134 mediaTypes: ImagePicker.MediaTypeOptions.Videos, 135 videoExportPreset: ImagePicker.VideoExportPreset.H264_640x480, 136 }); 137 138 testResultShape(result, 'video'); 139 140 for (const video of result.assets) { 141 expect(Math.max(video.width, video.height)).toBeLessThanOrEqual(640); 142 expect(Math.min(video.width, video.height)).toBeLessThanOrEqual(480); 143 } 144 }); 145 } 146 }); 147 148 afterAll(() => { 149 jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; 150 }); 151 }); 152} 153