xref: /expo/apps/test-suite/tests/ImagePicker.js (revision 8a424beb)
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