1082815dcSEvan Baconimport { vol } from 'memfs';
2082815dcSEvan Bacon
3082815dcSEvan Baconimport { getConfigFilePaths, modifyConfigAsync } from '../Config';
4082815dcSEvan Baconimport { getDynamicConfig, getStaticConfig } from '../getConfig';
5082815dcSEvan Bacon
6082815dcSEvan Baconconst mockConfigContext = {} as any;
7082815dcSEvan Bacon
8082815dcSEvan Baconjest.mock('fs');
9082815dcSEvan Bacon
10082815dcSEvan Bacondescribe(modifyConfigAsync, () => {
11082815dcSEvan Bacon  beforeAll(async () => {
12082815dcSEvan Bacon    vol.fromJSON(
13082815dcSEvan Bacon      {
14082815dcSEvan Bacon        'package.json': JSON.stringify({}),
15082815dcSEvan Bacon      },
16082815dcSEvan Bacon      'no-config'
17082815dcSEvan Bacon    );
18082815dcSEvan Bacon    vol.fromJSON(
19082815dcSEvan Bacon      {
20082815dcSEvan Bacon        'package.json': JSON.stringify({}),
21082815dcSEvan Bacon        'app.config.js': 'export default {};',
22082815dcSEvan Bacon        'app.config.json': JSON.stringify({}),
23082815dcSEvan Bacon      },
24082815dcSEvan Bacon      'dynamic-and-static'
25082815dcSEvan Bacon    );
26082815dcSEvan Bacon    vol.fromJSON(
27082815dcSEvan Bacon      {
28082815dcSEvan Bacon        'app.config.json': JSON.stringify(
29082815dcSEvan Bacon          {
30082815dcSEvan Bacon            name: 'app-config-json',
31082815dcSEvan Bacon            slug: 'app-config-json',
32082815dcSEvan Bacon            version: '1.0.0',
33082815dcSEvan Bacon            platforms: [],
34082815dcSEvan Bacon          },
35082815dcSEvan Bacon          null,
36082815dcSEvan Bacon          2
37082815dcSEvan Bacon        ),
38082815dcSEvan Bacon        'app.json': JSON.stringify(
39082815dcSEvan Bacon          {
40082815dcSEvan Bacon            name: 'app-json',
41082815dcSEvan Bacon          },
42082815dcSEvan Bacon          null,
43082815dcSEvan Bacon          2
44082815dcSEvan Bacon        ),
45082815dcSEvan Bacon        'package.json': JSON.stringify({}),
46082815dcSEvan Bacon      },
47082815dcSEvan Bacon      'static-override'
48082815dcSEvan Bacon    );
49082815dcSEvan Bacon  });
50082815dcSEvan Bacon
51082815dcSEvan Bacon  afterAll(() => {
52082815dcSEvan Bacon    vol.reset();
53082815dcSEvan Bacon  });
54082815dcSEvan Bacon
55082815dcSEvan Bacon  it(`can write to a static only config`, async () => {
56082815dcSEvan Bacon    const { type, config } = await modifyConfigAsync(
57082815dcSEvan Bacon      'static-override',
58082815dcSEvan Bacon      { foo: 'bar' } as any,
59082815dcSEvan Bacon      { skipSDKVersionRequirement: true },
60082815dcSEvan Bacon      { dryRun: true }
61082815dcSEvan Bacon    );
62082815dcSEvan Bacon    expect(type).toBe('success');
63082815dcSEvan Bacon    // @ts-ignore: foo property is not defined
64082815dcSEvan Bacon    expect(config.foo).toBe('bar');
65082815dcSEvan Bacon  });
66082815dcSEvan Bacon  it(`cannot write to a dynamic config`, async () => {
67082815dcSEvan Bacon    const { type, config } = await modifyConfigAsync(
68082815dcSEvan Bacon      'dynamic-and-static',
69082815dcSEvan Bacon      {},
70082815dcSEvan Bacon      { skipSDKVersionRequirement: true },
71082815dcSEvan Bacon      { dryRun: true }
72082815dcSEvan Bacon    );
73082815dcSEvan Bacon    expect(type).toBe('warn');
74082815dcSEvan Bacon    expect(config).toBe(null);
75082815dcSEvan Bacon  });
76082815dcSEvan Bacon  it(`cannot write to a project without a config`, async () => {
77082815dcSEvan Bacon    const { type, config } = await modifyConfigAsync(
78082815dcSEvan Bacon      'no-config',
79082815dcSEvan Bacon      {},
80082815dcSEvan Bacon      { skipSDKVersionRequirement: true },
81082815dcSEvan Bacon      { dryRun: true }
82082815dcSEvan Bacon    );
83082815dcSEvan Bacon    expect(type).toBe('fail');
84082815dcSEvan Bacon    expect(config).toBe(null);
85082815dcSEvan Bacon  });
86082815dcSEvan Bacon});
87082815dcSEvan Bacon
88082815dcSEvan Baconconst invalidConfig = `/* eslint-disable */
89082815dcSEvan Baconmodule.exports = {
90082815dcSEvan Bacon  name: 'app',
91082815dcSEvan Bacon  >
92082815dcSEvan Bacon  slug: 'app',
93082815dcSEvan Bacon}`;
94082815dcSEvan Bacon
95082815dcSEvan Bacondescribe(getDynamicConfig, () => {
96082815dcSEvan Bacon  beforeAll(async () => {
97082815dcSEvan Bacon    vol.fromJSON(
98082815dcSEvan Bacon      {
99082815dcSEvan Bacon        'exports-function.app.config.js': `export default function (config) {
100082815dcSEvan Bacon          return { ...config };
101082815dcSEvan Bacon        }`,
102082815dcSEvan Bacon        'exports-object.app.config.js': `export default {};`,
103082815dcSEvan Bacon      },
104082815dcSEvan Bacon      'dynamic-export-types'
105082815dcSEvan Bacon    );
106082815dcSEvan Bacon    vol.fromJSON(
107082815dcSEvan Bacon      {
108082815dcSEvan Bacon        // This file exists to test that an invalid app.config.ts
109082815dcSEvan Bacon        // gets used instead of defaulting to a valid app.config.js
110082815dcSEvan Bacon        'app.config.js': `export default {};`,
111082815dcSEvan Bacon        // This is a syntax error:
112082815dcSEvan Bacon        'app.config.ts': invalidConfig,
113082815dcSEvan Bacon      },
114082815dcSEvan Bacon      'syntax-error'
115082815dcSEvan Bacon    );
116082815dcSEvan Bacon    vol.fromJSON(
117082815dcSEvan Bacon      {
118082815dcSEvan Bacon        // This is a missing import
119082815dcSEvan Bacon        'app.config.ts': [`import 'foobar'`, 'module.exports = {}'].join('\n'),
120082815dcSEvan Bacon      },
121082815dcSEvan Bacon      'missing-import-error'
122082815dcSEvan Bacon    );
123082815dcSEvan Bacon  });
124082815dcSEvan Bacon
125082815dcSEvan Bacon  afterAll(() => {
126082815dcSEvan Bacon    vol.reset();
127082815dcSEvan Bacon  });
128082815dcSEvan Bacon
129082815dcSEvan Bacon  it(`exports a function`, () => {
130082815dcSEvan Bacon    expect(
131082815dcSEvan Bacon      getDynamicConfig('dynamic-export-types/exports-function.app.config.js', mockConfigContext)
132082815dcSEvan Bacon        .exportedObjectType
133082815dcSEvan Bacon    ).toBe('function');
134082815dcSEvan Bacon  });
135082815dcSEvan Bacon
136082815dcSEvan Bacon  it(`exports an object`, () => {
137082815dcSEvan Bacon    expect(
138082815dcSEvan Bacon      getDynamicConfig('dynamic-export-types/exports-object.app.config.js', mockConfigContext)
139082815dcSEvan Bacon        .exportedObjectType
140082815dcSEvan Bacon    ).toBe('object');
141082815dcSEvan Bacon  });
142082815dcSEvan Bacon
143082815dcSEvan Bacon  // This tests error are thrown properly and ensures that a more specific
144082815dcSEvan Bacon  // config is used instead of defaulting to a valid substitution.
145082815dcSEvan Bacon  it(`throws a useful error for dynamic configs with a syntax error`, () => {
146082815dcSEvan Bacon    const paths = getConfigFilePaths('syntax-error');
147*97e1898cSEvan Bacon    expect(() => getDynamicConfig(paths.dynamicConfigPath!, mockConfigContext)).toThrowError(
148082815dcSEvan Bacon      /Error .* \(5:7\)/
149082815dcSEvan Bacon    );
150082815dcSEvan Bacon  });
151082815dcSEvan Bacon  // This tests error are thrown properly and ensures that a more specific
152082815dcSEvan Bacon  // config is used instead of defaulting to a valid substitution.
153082815dcSEvan Bacon  it(`throws a useful error for dynamic configs with a missing import`, () => {
154082815dcSEvan Bacon    const paths = getConfigFilePaths('missing-import-error');
155*97e1898cSEvan Bacon    expect(() => getDynamicConfig(paths.dynamicConfigPath!, mockConfigContext)).toThrowError(
156082815dcSEvan Bacon      /Require stack/
157082815dcSEvan Bacon    );
158082815dcSEvan Bacon  });
159082815dcSEvan Bacon});
160082815dcSEvan Bacon
161082815dcSEvan Bacondescribe(getStaticConfig, () => {
162082815dcSEvan Bacon  beforeAll(async () => {
163082815dcSEvan Bacon    vol.fromJSON(
164082815dcSEvan Bacon      {
165082815dcSEvan Bacon        'package.json': JSON.stringify({}),
166082815dcSEvan Bacon        'app.json': JSON.stringify(
167082815dcSEvan Bacon          {
168082815dcSEvan Bacon            name: 'app-json',
169082815dcSEvan Bacon          },
170082815dcSEvan Bacon          null,
171082815dcSEvan Bacon          2
172082815dcSEvan Bacon        ),
173082815dcSEvan Bacon        'app.config.json': JSON.stringify(
174082815dcSEvan Bacon          {
175082815dcSEvan Bacon            name: 'app-config-json',
176082815dcSEvan Bacon            slug: 'app-config-json',
177082815dcSEvan Bacon            version: '1.0.0',
178082815dcSEvan Bacon            platforms: [],
179082815dcSEvan Bacon          },
180082815dcSEvan Bacon          null,
181082815dcSEvan Bacon          2
182082815dcSEvan Bacon        ),
183082815dcSEvan Bacon      },
184082815dcSEvan Bacon      'static-override'
185082815dcSEvan Bacon    );
186082815dcSEvan Bacon  });
187082815dcSEvan Bacon
188082815dcSEvan Bacon  afterAll(() => {
189082815dcSEvan Bacon    vol.reset();
190082815dcSEvan Bacon  });
191082815dcSEvan Bacon
192082815dcSEvan Bacon  // This tests error are thrown properly and ensures that a more specific
193082815dcSEvan Bacon  // config is used instead of defaulting to a valid substitution.
194082815dcSEvan Bacon  it(`uses app.config.json instead of app.json if both exist`, () => {
195082815dcSEvan Bacon    const paths = getConfigFilePaths('static-override');
196082815dcSEvan Bacon    expect(paths.staticConfigPath).toMatch(/app\.config\.json/);
197082815dcSEvan Bacon
198*97e1898cSEvan Bacon    expect(getStaticConfig(paths.staticConfigPath!).name).toBe('app-config-json');
199082815dcSEvan Bacon  });
200082815dcSEvan Bacon});
201