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