18d307f52SEvan Baconimport nock from 'nock';
28d307f52SEvan Bacon
38d307f52SEvan Baconimport { getExpoApiBaseUrl } from '../../../api/endpoint';
48d307f52SEvan Baconimport * as ProjectDevices from '../../project/devices';
58d307f52SEvan Baconimport { DevelopmentSession } from '../DevelopmentSession';
68d307f52SEvan Bacon
78d307f52SEvan Baconconst asMock = (fn: any): jest.Mock => fn as jest.Mock;
88d307f52SEvan Bacon
98d307f52SEvan Baconjest.mock('../../project/devices', () => ({
108d307f52SEvan Bacon  getDevicesInfoAsync: jest.fn(),
118d307f52SEvan Bacon}));
128d307f52SEvan Baconjest.mock('../../../api/user/user');
138d307f52SEvan Bacon
148d307f52SEvan Bacondescribe(`startAsync`, () => {
15*e32ccf9fSEvan Bacon  beforeEach(() => {
16*e32ccf9fSEvan Bacon    delete process.env.EXPO_OFFLINE;
17*e32ccf9fSEvan Bacon  });
188d307f52SEvan Bacon  it(`starts a dev session`, async () => {
1981e9e3beSEvan Bacon    const err = jest.fn();
2081e9e3beSEvan Bacon    const session = new DevelopmentSession('/', 'http://localhost:19001/', err);
218d307f52SEvan Bacon
228d307f52SEvan Bacon    asMock(ProjectDevices.getDevicesInfoAsync).mockResolvedValue({
238d307f52SEvan Bacon      devices: [{ installationId: '123' }, { installationId: '456' }],
248d307f52SEvan Bacon    });
258d307f52SEvan Bacon
268d307f52SEvan Bacon    const exp = {
278d307f52SEvan Bacon      name: 'my-app',
288d307f52SEvan Bacon      slug: 'my-app',
298d307f52SEvan Bacon      description: 'my-foo-bar',
308d307f52SEvan Bacon      primaryColor: '#4630eb',
318d307f52SEvan Bacon    };
328d307f52SEvan Bacon    const runtime = 'native';
33edc92349SJuwan Wheatley    const startScope = nock(getExpoApiBaseUrl())
348d307f52SEvan Bacon      .post('/v2/development-sessions/notify-alive?deviceId=123&deviceId=456')
358d307f52SEvan Bacon      .reply(200, '');
36edc92349SJuwan Wheatley    const closeScope = nock(getExpoApiBaseUrl())
37edc92349SJuwan Wheatley      .post('/v2/development-sessions/notify-close?deviceId=123&deviceId=456')
38edc92349SJuwan Wheatley      .reply(200, '');
398d307f52SEvan Bacon
408d307f52SEvan Bacon    await session.startAsync({
418d307f52SEvan Bacon      exp,
428d307f52SEvan Bacon      runtime,
438d307f52SEvan Bacon    });
44edc92349SJuwan Wheatley
45edc92349SJuwan Wheatley    await session.closeAsync();
46edc92349SJuwan Wheatley
47edc92349SJuwan Wheatley    expect(ProjectDevices.getDevicesInfoAsync).toHaveBeenCalledTimes(2);
48edc92349SJuwan Wheatley    expect(startScope.isDone()).toBe(true);
49edc92349SJuwan Wheatley    expect(closeScope.isDone()).toBe(true);
5081e9e3beSEvan Bacon    expect(err).not.toBeCalled();
5181e9e3beSEvan Bacon  });
5281e9e3beSEvan Bacon
5381e9e3beSEvan Bacon  it(`surfaces exceptions that would otherwise be uncaught`, async () => {
5481e9e3beSEvan Bacon    const err = jest.fn();
5581e9e3beSEvan Bacon    const session = new DevelopmentSession('/', 'http://localhost:19001/', err);
5681e9e3beSEvan Bacon
5781e9e3beSEvan Bacon    asMock(ProjectDevices.getDevicesInfoAsync).mockRejectedValueOnce(new Error('predefined error'));
5881e9e3beSEvan Bacon
5981e9e3beSEvan Bacon    const exp = {
6081e9e3beSEvan Bacon      name: 'my-app',
6181e9e3beSEvan Bacon      slug: 'my-app',
6281e9e3beSEvan Bacon      description: 'my-foo-bar',
6381e9e3beSEvan Bacon      primaryColor: '#4630eb',
6481e9e3beSEvan Bacon    };
6581e9e3beSEvan Bacon    const runtime = 'native';
6681e9e3beSEvan Bacon
6781e9e3beSEvan Bacon    // Does not throw directly
6881e9e3beSEvan Bacon    await session.startAsync({
6981e9e3beSEvan Bacon      exp,
7081e9e3beSEvan Bacon      runtime,
7181e9e3beSEvan Bacon    });
7281e9e3beSEvan Bacon
7381e9e3beSEvan Bacon    expect(err).toBeCalled();
7481e9e3beSEvan Bacon
7581e9e3beSEvan Bacon    // Did not repeat the cycle
7681e9e3beSEvan Bacon    expect(session['timeout']).toBe(null);
7781e9e3beSEvan Bacon  });
7881e9e3beSEvan Bacon
7981e9e3beSEvan Bacon  it(`gracefully handles server outages`, async () => {
8081e9e3beSEvan Bacon    const err = jest.fn();
8181e9e3beSEvan Bacon    const session = new DevelopmentSession('/', 'http://localhost:19001/', err);
8281e9e3beSEvan Bacon
8381e9e3beSEvan Bacon    asMock(ProjectDevices.getDevicesInfoAsync).mockResolvedValue({
8481e9e3beSEvan Bacon      devices: [{ installationId: '123' }, { installationId: '456' }],
8581e9e3beSEvan Bacon    });
8681e9e3beSEvan Bacon
8781e9e3beSEvan Bacon    const exp = {
8881e9e3beSEvan Bacon      name: 'my-app',
8981e9e3beSEvan Bacon      slug: 'my-app',
9081e9e3beSEvan Bacon      description: 'my-foo-bar',
9181e9e3beSEvan Bacon      primaryColor: '#4630eb',
9281e9e3beSEvan Bacon    };
9381e9e3beSEvan Bacon    const runtime = 'native';
9481e9e3beSEvan Bacon
9581e9e3beSEvan Bacon    // Server is down
9681e9e3beSEvan Bacon    nock(getExpoApiBaseUrl())
9781e9e3beSEvan Bacon      .post('/v2/development-sessions/notify-alive?deviceId=123&deviceId=456')
9881e9e3beSEvan Bacon      .reply(500, '');
9981e9e3beSEvan Bacon
10081e9e3beSEvan Bacon    // Does not throw directly
10181e9e3beSEvan Bacon    await session.startAsync({
10281e9e3beSEvan Bacon      exp,
10381e9e3beSEvan Bacon      runtime,
10481e9e3beSEvan Bacon    });
10581e9e3beSEvan Bacon
10681e9e3beSEvan Bacon    expect(err).toBeCalled();
10781e9e3beSEvan Bacon
10881e9e3beSEvan Bacon    // Did not repeat the cycle
10981e9e3beSEvan Bacon    expect(session['timeout']).toBe(null);
1108d307f52SEvan Bacon  });
1118d307f52SEvan Bacon});
112