18d307f52SEvan Baconimport fetch from 'node-fetch';
28d307f52SEvan Bacon
3e32ccf9fSEvan Baconimport { Log } from '../../log';
48d307f52SEvan Baconimport { stripAnsi } from '../ansi';
58d307f52SEvan Baconimport { isUrlAvailableAsync } from '../url';
68d307f52SEvan Baconimport {
7e32ccf9fSEvan Bacon  getBundleIdWarningInternalAsync,
8e32ccf9fSEvan Bacon  getPackageNameWarningInternalAsync,
98d307f52SEvan Bacon  validateBundleId,
108d307f52SEvan Bacon  validatePackage,
1151740f69SEvan Bacon  validatePackageWithWarning,
128d307f52SEvan Bacon} from '../validateApplicationId';
138d307f52SEvan Bacon
148d307f52SEvan Baconjest.mock('node-fetch');
15e32ccf9fSEvan Baconjest.mock('../../log');
16e32ccf9fSEvan Baconjest.mock('../url');
17e32ccf9fSEvan Bacon
18e32ccf9fSEvan Baconfunction resetOfflineMode() {
19e32ccf9fSEvan Bacon  beforeEach(() => {
20e32ccf9fSEvan Bacon    delete process.env.EXPO_OFFLINE;
21e32ccf9fSEvan Bacon  });
22e32ccf9fSEvan Bacon  afterAll(() => {
23e32ccf9fSEvan Bacon    delete process.env.EXPO_OFFLINE;
24e32ccf9fSEvan Bacon  });
25e32ccf9fSEvan Bacon}
268d307f52SEvan Bacon
278d307f52SEvan Bacondescribe(validateBundleId, () => {
288d307f52SEvan Bacon  it(`validates`, () => {
298d307f52SEvan Bacon    expect(validateBundleId('bacon')).toBe(true);
308d307f52SEvan Bacon    expect(validateBundleId('...b.a.-c.0.n...')).toBe(true);
318d307f52SEvan Bacon    expect(validateBundleId('.')).toBe(true);
328d307f52SEvan Bacon    expect(validateBundleId('. ..')).toBe(false);
338d307f52SEvan Bacon    expect(validateBundleId('_')).toBe(false);
348d307f52SEvan Bacon    expect(validateBundleId(',')).toBe(false);
358d307f52SEvan Bacon  });
368d307f52SEvan Bacon});
378d307f52SEvan Bacon
3851740f69SEvan Bacondescribe(validatePackageWithWarning, () => {
3951740f69SEvan Bacon  it(`validates with warnings`, () => {
4051740f69SEvan Bacon    expect(validatePackageWithWarning('bacon.native')).toEqual(
4151740f69SEvan Bacon      `"native" is a reserved Java keyword.`
4251740f69SEvan Bacon    );
4351740f69SEvan Bacon    expect(validatePackageWithWarning('bacon')).toEqual(
4451740f69SEvan Bacon      'Package name must contain more than one segment, separated by ".", e.g. com.bacon'
4551740f69SEvan Bacon    );
4651740f69SEvan Bacon    expect(validatePackageWithWarning(',')).toEqual(
4751740f69SEvan Bacon      `Package name must contain more than one segment, separated by ".", e.g. com.,`
4851740f69SEvan Bacon    );
4951740f69SEvan Bacon  });
5051740f69SEvan Bacon});
518d307f52SEvan Bacondescribe(validatePackage, () => {
528d307f52SEvan Bacon  it(`validates`, () => {
538d307f52SEvan Bacon    expect(validatePackage('bacon.com.hey')).toBe(true);
548d307f52SEvan Bacon    expect(validatePackage('bacon')).toBe(false);
55*f4cccd85SAlan Hughes    expect(validatePackage('com.native')).toBe(false);
56*f4cccd85SAlan Hughes    expect(validatePackage('native.android')).toBe(false);
578d307f52SEvan Bacon    expect(validatePackage('...b.a.-c.0.n...')).toBe(false);
588d307f52SEvan Bacon    expect(validatePackage('.')).toBe(false);
598d307f52SEvan Bacon    expect(validatePackage('. ..')).toBe(false);
608d307f52SEvan Bacon    expect(validatePackage('_')).toBe(false);
618d307f52SEvan Bacon    expect(validatePackage(',')).toBe(false);
628d307f52SEvan Bacon  });
6351740f69SEvan Bacon  it(`prevents using reserved java keywords`, () => {
6451740f69SEvan Bacon    expect(validatePackage('bacon.native.com')).toBe(false);
6551740f69SEvan Bacon    expect(validatePackage('byte')).toBe(false);
6651740f69SEvan Bacon  });
678d307f52SEvan Bacon});
688d307f52SEvan Bacon
69e32ccf9fSEvan Bacondescribe(getBundleIdWarningInternalAsync, () => {
70e32ccf9fSEvan Bacon  resetOfflineMode();
718d307f52SEvan Bacon  it(`returns null if the URL cannot be reached`, async () => {
72e32ccf9fSEvan Bacon    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(false);
73e32ccf9fSEvan Bacon    expect(await getBundleIdWarningInternalAsync('bacon')).toBe(null);
74e32ccf9fSEvan Bacon  });
75e32ccf9fSEvan Bacon  it(`returns null and warns if running in offline-mode`, async () => {
76e32ccf9fSEvan Bacon    process.env.EXPO_OFFLINE = '1';
77e32ccf9fSEvan Bacon    await expect(getBundleIdWarningInternalAsync('bacon')).resolves.toBe(null);
78e32ccf9fSEvan Bacon    expect(Log.warn).toBeCalledWith(expect.stringMatching(/offline-mode/));
798d307f52SEvan Bacon  });
808d307f52SEvan Bacon  it(`returns warning if in use`, async () => {
81e32ccf9fSEvan Bacon    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(true);
828d307f52SEvan Bacon
83e32ccf9fSEvan Bacon    jest.mocked(fetch).mockResolvedValueOnce({
84e32ccf9fSEvan Bacon      status: 200,
858d307f52SEvan Bacon      json() {
868d307f52SEvan Bacon        return Promise.resolve({
878d307f52SEvan Bacon          resultCount: 1,
888d307f52SEvan Bacon          results: [
898d307f52SEvan Bacon            {
908d307f52SEvan Bacon              trackName: 'Pillar Valley',
918d307f52SEvan Bacon              sellerName: 'Evan Bacon',
928d307f52SEvan Bacon              kind: 'software',
938d307f52SEvan Bacon              artistName: 'Evan Bacon',
948d307f52SEvan Bacon              genres: ['Games', 'Entertainment', 'Family', 'Casual'],
958d307f52SEvan Bacon            },
968d307f52SEvan Bacon          ],
978d307f52SEvan Bacon        });
988d307f52SEvan Bacon      },
99e32ccf9fSEvan Bacon    } as any);
100e32ccf9fSEvan Bacon
1018d307f52SEvan Bacon    expect(
102e32ccf9fSEvan Bacon      stripAnsi(await getBundleIdWarningInternalAsync('com.bacon.pillarvalley'))
1038d307f52SEvan Bacon    ).toMatchInlineSnapshot(
1048d307f52SEvan Bacon      `"⚠️  The app Pillar Valley by Evan Bacon is already using com.bacon.pillarvalley"`
1058d307f52SEvan Bacon    );
1068d307f52SEvan Bacon  });
1078d307f52SEvan Bacon});
108e32ccf9fSEvan Bacon
109e32ccf9fSEvan Bacondescribe(getPackageNameWarningInternalAsync, () => {
110e32ccf9fSEvan Bacon  resetOfflineMode();
111e32ccf9fSEvan Bacon
1128d307f52SEvan Bacon  it(`returns null if the URL cannot be reached`, async () => {
113e32ccf9fSEvan Bacon    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(false);
114e32ccf9fSEvan Bacon    expect(await getPackageNameWarningInternalAsync('bacon')).toBe(null);
115e32ccf9fSEvan Bacon  });
116e32ccf9fSEvan Bacon  it(`returns null and warns if running in offline-mode`, async () => {
117e32ccf9fSEvan Bacon    process.env.EXPO_OFFLINE = '1';
118e32ccf9fSEvan Bacon    expect(await getPackageNameWarningInternalAsync('123')).toBe(null);
119e32ccf9fSEvan Bacon    expect(Log.warn).toBeCalledWith(expect.stringMatching(/offline-mode/));
1208d307f52SEvan Bacon  });
1218d307f52SEvan Bacon  it(`returns warning if in use`, async () => {
122e32ccf9fSEvan Bacon    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(true);
123e32ccf9fSEvan Bacon    jest.mocked(fetch).mockResolvedValueOnce({
1248d307f52SEvan Bacon      status: 200,
125e32ccf9fSEvan Bacon    } as any);
126e32ccf9fSEvan Bacon
1278d307f52SEvan Bacon    expect(
128e32ccf9fSEvan Bacon      stripAnsi(await getPackageNameWarningInternalAsync('com.bacon.pillarvalley'))
1298d307f52SEvan Bacon    ).toMatchInlineSnapshot(
1308d307f52SEvan Bacon      `"⚠️  The package com.bacon.pillarvalley is already in use. Learn more: https://play.google.com/store/apps/details?id=com.bacon.pillarvalley"`
1318d307f52SEvan Bacon    );
1328d307f52SEvan Bacon  });
1338d307f52SEvan Bacon});
134