1import { vol } from 'memfs';
2
3import { getConfig, getProjectConfigDescriptionWithPaths } from '../Config';
4
5jest.mock('fs');
6
7describe(getProjectConfigDescriptionWithPaths, () => {
8  it(`describes a project using both a static and dynamic config`, () => {
9    const message = getProjectConfigDescriptionWithPaths('/', {
10      dynamicConfigPath: '/app.config.js',
11      staticConfigPath: '/app.config.json',
12    });
13    expect(message).toMatch(`app.config.js`);
14    expect(message).toMatch(`app.config.json`);
15  });
16  it(`describes a project using only a static config`, () => {
17    const message = getProjectConfigDescriptionWithPaths('/', {
18      dynamicConfigPath: null,
19      staticConfigPath: '/app.json',
20    });
21    expect(message).toMatch(`app.json`);
22  });
23  it(`describes a project using only a dynamic config`, () => {
24    const message = getProjectConfigDescriptionWithPaths('/', {
25      dynamicConfigPath: '/app.config.ts',
26      staticConfigPath: null,
27    });
28    expect(message).toMatch(`app.config.ts`);
29  });
30  it(`describes a project with no configs using a default value`, () => {
31    const message = getProjectConfigDescriptionWithPaths('/', {
32      dynamicConfigPath: null,
33      staticConfigPath: null,
34    });
35    expect(message).toBe('app.json');
36  });
37});
38
39describe('getConfig public config', () => {
40  const appJsonWithPrivateData = {
41    name: 'testing 123',
42    version: '0.1.0',
43    slug: 'testing-123',
44    sdkVersion: '100.0.0',
45    hooks: {
46      postPublish: [],
47    },
48    android: {
49      config: {
50        googleMaps: {
51          apiKey: 'test-key',
52        },
53      },
54      versionCode: 1,
55    },
56    ios: {
57      config: {
58        googleMapsApiKey: 'test-key',
59      },
60      buildNumber: '1.0',
61    },
62  };
63
64  const appJsonNoPrivateData = {
65    name: 'testing 123',
66    version: '0.1.0',
67    slug: 'testing-123',
68    sdkVersion: '100.0.0',
69    ios: {
70      buildNumber: '1.0',
71    },
72  };
73
74  beforeAll(() => {
75    const packageJson = JSON.stringify(
76      {
77        name: 'testing123',
78        version: '0.1.0',
79        description: 'fake description',
80        main: 'index.js',
81      },
82      null,
83      2
84    );
85
86    vol.fromJSON({
87      '/private-data/package.json': packageJson,
88      '/private-data/app.json': JSON.stringify({ expo: appJsonWithPrivateData }),
89      '/no-private-data/package.json': packageJson,
90      '/no-private-data/app.json': JSON.stringify({ expo: appJsonNoPrivateData }),
91    });
92  });
93
94  afterAll(() => vol.reset());
95
96  it('removes only private data from the config', () => {
97    const { exp } = getConfig('/private-data', { isPublicConfig: true });
98
99    expect(exp.hooks).toBeUndefined();
100
101    expect(exp.ios).toBeDefined();
102    expect(exp.ios!.buildNumber).toEqual(appJsonWithPrivateData.ios.buildNumber);
103    expect(exp.ios!.config).toBeUndefined();
104
105    expect(exp.android).toBeDefined();
106    expect(exp.android!.versionCode).toEqual(appJsonWithPrivateData.android.versionCode);
107    expect(exp.android!.config).toBeUndefined();
108    expect(exp._internal).toBeUndefined();
109  });
110
111  it('does not remove properties from a config with no private data', () => {
112    const { exp } = getConfig('/no-private-data', { isPublicConfig: true });
113    expect(exp).toMatchObject(appJsonNoPrivateData);
114  });
115});
116
117describe('readConfigJson', () => {
118  describe('sdkVersion', () => {
119    beforeAll(() => {
120      const packageJson = JSON.stringify(
121        {
122          name: 'testing123',
123          version: '0.1.0',
124          description: 'fake description',
125          main: 'index.js',
126        },
127        null,
128        2
129      );
130
131      const appJson = {
132        name: 'testing 123',
133        version: '0.1.0',
134        slug: 'testing-123',
135        sdkVersion: '100.0.0',
136      };
137
138      const expoPackageJson = JSON.stringify({
139        name: 'expo',
140        version: '650.x.x',
141      });
142
143      vol.fromJSON({
144        '/from-config/package.json': packageJson,
145        '/from-config/app.json': JSON.stringify({ expo: appJson }),
146        '/from-config/node_modules/expo/package.json': expoPackageJson,
147
148        '/from-package/package.json': packageJson,
149        '/from-package/app.json': JSON.stringify({ expo: { ...appJson, sdkVersion: undefined } }),
150        '/from-package/node_modules/expo/package.json': expoPackageJson,
151
152        '/no-version/package.json': packageJson,
153        '/no-version/app.json': JSON.stringify({ expo: { ...appJson, sdkVersion: undefined } }),
154      });
155    });
156    afterAll(() => vol.reset());
157
158    it('reads the SDK version from the config', () => {
159      const { exp } = getConfig('/from-config');
160      expect(exp.sdkVersion).toBe('100.0.0');
161    });
162
163    it('reads the SDK version from the installed version of expo', () => {
164      const { exp } = getConfig('/from-package');
165      expect(exp.sdkVersion).toBe('650.0.0');
166    });
167  });
168
169  describe('validation', () => {
170    beforeAll(() => {
171      const packageJson = JSON.stringify({
172        name: 'testing123',
173        version: '0.1.0',
174        main: 'index.js',
175      });
176
177      const expoPackageJson = JSON.stringify({
178        name: 'expo',
179        version: '650.x.x',
180      });
181
182      vol.fromJSON({
183        '/no-config/package.json': packageJson,
184        '/no-config/node_modules/expo/package.json': expoPackageJson,
185
186        '/no-package/package.json': packageJson,
187      });
188    });
189    afterAll(() => vol.reset());
190
191    it(`can skip throwing when the app.json is missing and expo isn't installed`, () => {
192      const { exp, pkg } = getConfig('/no-package', { skipSDKVersionRequirement: true });
193      expect(exp.name).toBe(pkg.name);
194      expect(exp.description).toBe(pkg.description);
195    });
196
197    it(`will not throw if the app.json is missing`, () => {
198      // No config is required for new method
199      expect(() => getConfig('/no-config')).not.toThrow();
200    });
201
202    it(`will not throw if the expo package is missing when skipSDKVersionRequirement is enabled`, () => {
203      expect(() => getConfig('/no-package', { skipSDKVersionRequirement: false })).toThrow(
204        /Cannot determine which native SDK version your project uses/
205      );
206    });
207  });
208});
209