1import fetch from 'node-fetch';
2
3import { Log } from '../../log';
4import { stripAnsi } from '../ansi';
5import { isUrlAvailableAsync } from '../url';
6import {
7  getBundleIdWarningInternalAsync,
8  getPackageNameWarningInternalAsync,
9  validateBundleId,
10  validatePackage,
11} from '../validateApplicationId';
12
13jest.mock('node-fetch');
14jest.mock('../../log');
15jest.mock('../url');
16
17function resetOfflineMode() {
18  beforeEach(() => {
19    delete process.env.EXPO_OFFLINE;
20  });
21  afterAll(() => {
22    delete process.env.EXPO_OFFLINE;
23  });
24}
25
26describe(validateBundleId, () => {
27  it(`validates`, () => {
28    expect(validateBundleId('bacon')).toBe(true);
29    expect(validateBundleId('...b.a.-c.0.n...')).toBe(true);
30    expect(validateBundleId('.')).toBe(true);
31    expect(validateBundleId('. ..')).toBe(false);
32    expect(validateBundleId('_')).toBe(false);
33    expect(validateBundleId(',')).toBe(false);
34  });
35});
36
37describe(validatePackage, () => {
38  it(`validates`, () => {
39    expect(validatePackage('bacon.com.hey')).toBe(true);
40    expect(validatePackage('bacon')).toBe(false);
41    expect(validatePackage('...b.a.-c.0.n...')).toBe(false);
42    expect(validatePackage('.')).toBe(false);
43    expect(validatePackage('. ..')).toBe(false);
44    expect(validatePackage('_')).toBe(false);
45    expect(validatePackage(',')).toBe(false);
46  });
47});
48
49describe(getBundleIdWarningInternalAsync, () => {
50  resetOfflineMode();
51  it(`returns null if the URL cannot be reached`, async () => {
52    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(false);
53    expect(await getBundleIdWarningInternalAsync('bacon')).toBe(null);
54  });
55  it(`returns null and warns if running in offline-mode`, async () => {
56    process.env.EXPO_OFFLINE = '1';
57    await expect(getBundleIdWarningInternalAsync('bacon')).resolves.toBe(null);
58    expect(Log.warn).toBeCalledWith(expect.stringMatching(/offline-mode/));
59  });
60  it(`returns warning if in use`, async () => {
61    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(true);
62
63    jest.mocked(fetch).mockResolvedValueOnce({
64      status: 200,
65      json() {
66        return Promise.resolve({
67          resultCount: 1,
68          results: [
69            {
70              trackName: 'Pillar Valley',
71              sellerName: 'Evan Bacon',
72              kind: 'software',
73              artistName: 'Evan Bacon',
74              genres: ['Games', 'Entertainment', 'Family', 'Casual'],
75            },
76          ],
77        });
78      },
79    } as any);
80
81    expect(
82      stripAnsi(await getBundleIdWarningInternalAsync('com.bacon.pillarvalley'))
83    ).toMatchInlineSnapshot(
84      `"⚠️  The app Pillar Valley by Evan Bacon is already using com.bacon.pillarvalley"`
85    );
86  });
87});
88
89describe(getPackageNameWarningInternalAsync, () => {
90  resetOfflineMode();
91
92  it(`returns null if the URL cannot be reached`, async () => {
93    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(false);
94    expect(await getPackageNameWarningInternalAsync('bacon')).toBe(null);
95  });
96  it(`returns null and warns if running in offline-mode`, async () => {
97    process.env.EXPO_OFFLINE = '1';
98    expect(await getPackageNameWarningInternalAsync('123')).toBe(null);
99    expect(Log.warn).toBeCalledWith(expect.stringMatching(/offline-mode/));
100  });
101  it(`returns warning if in use`, async () => {
102    jest.mocked(isUrlAvailableAsync).mockResolvedValueOnce(true);
103    jest.mocked(fetch).mockResolvedValueOnce({
104      status: 200,
105    } as any);
106
107    expect(
108      stripAnsi(await getPackageNameWarningInternalAsync('com.bacon.pillarvalley'))
109    ).toMatchInlineSnapshot(
110      `"⚠️  The package com.bacon.pillarvalley is already in use. Learn more: https://play.google.com/store/apps/details?id=com.bacon.pillarvalley"`
111    );
112  });
113});
114