1import { vol } from 'memfs'; 2import nock from 'nock'; 3 4import { getExpoApiBaseUrl } from '../../api/endpoint'; 5import { downloadAppAsync } from '../downloadAppAsync'; 6import { downloadExpoGoAsync } from '../downloadExpoGoAsync'; 7import { extractAsync } from '../tar'; 8 9const asMock = (fn: any): jest.Mock => fn; 10 11jest.mock('../../log'); 12 13jest.mock(`../downloadAppAsync`, () => ({ 14 downloadAppAsync: jest.fn(), 15})); 16 17jest.mock(`../tar`, () => ({ 18 extractAsync: jest.fn(), 19})); 20 21describe(downloadExpoGoAsync, () => { 22 beforeEach(() => { 23 asMock(extractAsync).mockImplementationOnce(jest.fn()); 24 asMock(downloadAppAsync).mockImplementationOnce( 25 jest.fn(jest.requireActual('../downloadAppAsync').downloadAppAsync) 26 ); 27 vol.reset(); 28 }); 29 it('downloads the Expo Go app on iOS', async () => { 30 vol.fromJSON({ tmp: '' }, '/tmp'); 31 const scope = nock(getExpoApiBaseUrl()) 32 .get('/v2/versions/latest') 33 .reply(200, require('../../api/__tests__/fixtures/versions-latest.json')); 34 const scopeClient = nock('https://dpq5q02fu5f55.cloudfront.net') 35 .get('/Exponent-2.23.2.tar.gz') 36 .reply(200, '...'); 37 38 await downloadExpoGoAsync('ios'); 39 40 const generatedOutput = '/home/.expo/ios-simulator-app-cache/Exponent-2.23.2.tar.app'; 41 42 // Endpoints were called 43 expect(scope.isDone()).toBe(true); 44 expect(scopeClient.isDone()).toBe(true); 45 46 // Platform options were parsed 47 expect(downloadAppAsync).toHaveBeenCalledWith({ 48 cacheDirectory: 'expo-go', 49 extract: true, 50 onProgress: expect.anything(), 51 outputPath: generatedOutput, 52 url: 'https://dpq5q02fu5f55.cloudfront.net/Exponent-2.23.2.tar.gz', 53 }); 54 55 // File won't be written because we mock the tar extraction. 56 // expect(vol.toJSON()[generatedOutput]).toBeDefined(); 57 58 // Did extract tar 59 expect(extractAsync).toHaveBeenCalledWith('/tmp/Exponent-2.23.2.tar.app', generatedOutput); 60 }); 61 62 it('downloads the Expo Go app on Android', async () => { 63 vol.fromJSON({}, ''); 64 65 const scope = nock(getExpoApiBaseUrl()) 66 .get('/v2/versions/latest') 67 .reply(200, require('../../api/__tests__/fixtures/versions-latest.json')); 68 const scopeClient = nock('https://d1ahtucjixef4r.cloudfront.net') 69 .get('/Exponent-2.23.2.apk') 70 .reply(200, '...'); 71 72 await downloadExpoGoAsync('android'); 73 74 const generatedOutput = '/home/.expo/android-apk-cache/Exponent-2.23.2.apk'; 75 76 // Endpoints were called 77 expect(scope.isDone()).toBe(true); 78 expect(scopeClient.isDone()).toBe(true); 79 80 // Platform options were parsed 81 expect(downloadAppAsync).toHaveBeenCalledWith({ 82 cacheDirectory: 'expo-go', 83 extract: false, 84 onProgress: expect.anything(), 85 outputPath: generatedOutput, 86 url: 'https://d1ahtucjixef4r.cloudfront.net/Exponent-2.23.2.apk', 87 }); 88 89 expect(vol.toJSON()[generatedOutput]).toBeDefined(); 90 // Did not extract Android APK 91 expect(extractAsync).toHaveBeenCalledTimes(0); 92 }); 93 94 it('fails when the servers are down', async () => { 95 vol.fromJSON({}, ''); 96 97 const scope = nock(getExpoApiBaseUrl()) 98 .get('/v2/versions/latest') 99 .reply(200, require('../../api/__tests__/fixtures/versions-latest.json')); 100 101 // Mock a server failure when fetching from cloudfront. 102 const scopeClient = nock('https://d1ahtucjixef4r.cloudfront.net') 103 .get('/Exponent-2.23.2.apk') 104 .reply(500, 'something went wrong'); 105 106 await expect(downloadExpoGoAsync('android')).rejects.toThrow( 107 /Unexpected response: Internal Server Error\. From url: https:\/\/d1ahtucjixef4r\.cloudfront\.net\/Exponent-2\.23\.2\.apk/ 108 ); 109 const generatedOutput = '/home/.expo/android-apk-cache/Exponent-2.23.2.apk'; 110 111 // Endpoints were called 112 expect(scope.isDone()).toBe(true); 113 expect(scopeClient.isDone()).toBe(true); 114 115 // Platform options were parsed 116 expect(downloadAppAsync).toHaveBeenCalled(); 117 118 // FS was not modified 119 expect(vol.toJSON()[generatedOutput]).not.toBeDefined(); 120 }); 121}); 122