1import nock from 'nock'; 2 3import { getExpoApiBaseUrl } from '../../../api/endpoint'; 4import * as ProjectDevices from '../../project/devices'; 5import { DevelopmentSession } from '../DevelopmentSession'; 6 7const asMock = (fn: any): jest.Mock => fn as jest.Mock; 8 9jest.mock('../../../api/settings', () => ({ 10 APISettings: { 11 isOffline: false, 12 }, 13})); 14jest.mock('../../project/devices', () => ({ 15 getDevicesInfoAsync: jest.fn(), 16})); 17jest.mock('../../../api/user/user'); 18 19describe(`startAsync`, () => { 20 it(`starts a dev session`, async () => { 21 const err = jest.fn(); 22 const session = new DevelopmentSession('/', 'http://localhost:19001/', err); 23 24 asMock(ProjectDevices.getDevicesInfoAsync).mockResolvedValue({ 25 devices: [{ installationId: '123' }, { installationId: '456' }], 26 }); 27 28 const exp = { 29 name: 'my-app', 30 slug: 'my-app', 31 description: 'my-foo-bar', 32 primaryColor: '#4630eb', 33 }; 34 const runtime = 'native'; 35 const startScope = nock(getExpoApiBaseUrl()) 36 .post('/v2/development-sessions/notify-alive?deviceId=123&deviceId=456') 37 .reply(200, ''); 38 const closeScope = nock(getExpoApiBaseUrl()) 39 .post('/v2/development-sessions/notify-close?deviceId=123&deviceId=456') 40 .reply(200, ''); 41 42 await session.startAsync({ 43 exp, 44 runtime, 45 }); 46 47 await session.closeAsync(); 48 49 expect(ProjectDevices.getDevicesInfoAsync).toHaveBeenCalledTimes(2); 50 expect(startScope.isDone()).toBe(true); 51 expect(closeScope.isDone()).toBe(true); 52 expect(err).not.toBeCalled(); 53 }); 54 55 it(`surfaces exceptions that would otherwise be uncaught`, async () => { 56 const err = jest.fn(); 57 const session = new DevelopmentSession('/', 'http://localhost:19001/', err); 58 59 asMock(ProjectDevices.getDevicesInfoAsync).mockRejectedValueOnce(new Error('predefined error')); 60 61 const exp = { 62 name: 'my-app', 63 slug: 'my-app', 64 description: 'my-foo-bar', 65 primaryColor: '#4630eb', 66 }; 67 const runtime = 'native'; 68 69 // Does not throw directly 70 await session.startAsync({ 71 exp, 72 runtime, 73 }); 74 75 expect(err).toBeCalled(); 76 77 // Did not repeat the cycle 78 expect(session['timeout']).toBe(null); 79 }); 80 81 it(`gracefully handles server outages`, async () => { 82 const err = jest.fn(); 83 const session = new DevelopmentSession('/', 'http://localhost:19001/', err); 84 85 asMock(ProjectDevices.getDevicesInfoAsync).mockResolvedValue({ 86 devices: [{ installationId: '123' }, { installationId: '456' }], 87 }); 88 89 const exp = { 90 name: 'my-app', 91 slug: 'my-app', 92 description: 'my-foo-bar', 93 primaryColor: '#4630eb', 94 }; 95 const runtime = 'native'; 96 97 // Server is down 98 nock(getExpoApiBaseUrl()) 99 .post('/v2/development-sessions/notify-alive?deviceId=123&deviceId=456') 100 .reply(500, ''); 101 102 // Does not throw directly 103 await session.startAsync({ 104 exp, 105 runtime, 106 }); 107 108 expect(err).toBeCalled(); 109 110 // Did not repeat the cycle 111 expect(session['timeout']).toBe(null); 112 }); 113}); 114