1082815dcSEvan Baconimport * as fs from 'fs'; 2082815dcSEvan Baconimport { vol } from 'memfs'; 3082815dcSEvan Baconimport * as path from 'path'; 4082815dcSEvan Bacon 5*97e1898cSEvan Baconimport { getConfig } from '../Config'; 6082815dcSEvan Bacon 7082815dcSEvan Baconconst fsReal = jest.requireActual('fs') as typeof fs; 8082815dcSEvan Bacon 9082815dcSEvan Baconjest.mock('fs'); 10082815dcSEvan Bacon 11082815dcSEvan Bacondescribe(getConfig, () => { 12*97e1898cSEvan Bacon afterAll(() => { 13*97e1898cSEvan Bacon vol.reset(); 14*97e1898cSEvan Bacon }); 15*97e1898cSEvan Bacon 16*97e1898cSEvan Bacon // Tests the following: 17*97e1898cSEvan Bacon // - All supported languages are working 18*97e1898cSEvan Bacon // - ensure `app.config` has higher priority to `app` 19*97e1898cSEvan Bacon // - generated `.expo` object is created and the language hint is added 20*97e1898cSEvan Bacon describe('language support', () => { 21*97e1898cSEvan Bacon beforeEach(() => { 22*97e1898cSEvan Bacon delete process.env.EXPO_DEBUG; 23*97e1898cSEvan Bacon vol.reset(); 24*97e1898cSEvan Bacon }); 25*97e1898cSEvan Bacon it('parses a ts config', () => { 26*97e1898cSEvan Bacon vol.fromJSON( 27*97e1898cSEvan Bacon { 28*97e1898cSEvan Bacon // Read this TS file so we can validate the types 29*97e1898cSEvan Bacon 'app.config.ts': fsReal.readFileSync( 30*97e1898cSEvan Bacon path.join(__dirname, './fixtures/ts/app.config.ts'), 31*97e1898cSEvan Bacon 'utf8' 32*97e1898cSEvan Bacon ), 33*97e1898cSEvan Bacon 'package.json': JSON.stringify({ 34*97e1898cSEvan Bacon name: 'ts-config-test', 35*97e1898cSEvan Bacon version: '1.0.0', 36*97e1898cSEvan Bacon }), 37*97e1898cSEvan Bacon }, 38*97e1898cSEvan Bacon '/' 39*97e1898cSEvan Bacon ); 40*97e1898cSEvan Bacon 41*97e1898cSEvan Bacon const { exp } = getConfig('/', { 42*97e1898cSEvan Bacon skipSDKVersionRequirement: true, 43*97e1898cSEvan Bacon }); 44*97e1898cSEvan Bacon // @ts-ignore: foo property is not defined 45*97e1898cSEvan Bacon expect(exp.foo).toBe('bar+value'); 46*97e1898cSEvan Bacon expect(exp.name).toBe('rewrote+ts-config-test'); 47*97e1898cSEvan Bacon expect(exp._internal).toStrictEqual({ 48*97e1898cSEvan Bacon dynamicConfigPath: '/app.config.ts', 49*97e1898cSEvan Bacon isDebug: false, 50*97e1898cSEvan Bacon packageJsonPath: '/package.json', 51*97e1898cSEvan Bacon projectRoot: '/', 52*97e1898cSEvan Bacon staticConfigPath: null, 53*97e1898cSEvan Bacon }); 54*97e1898cSEvan Bacon }); 55*97e1898cSEvan Bacon it('parses a js config', () => { 56082815dcSEvan Bacon vol.fromJSON( 57082815dcSEvan Bacon { 58082815dcSEvan Bacon 'app.json': JSON.stringify({ 59082815dcSEvan Bacon expo: { 60082815dcSEvan Bacon foo: 'invalid', 61082815dcSEvan Bacon slug: 'someslug', 62082815dcSEvan Bacon }, 63082815dcSEvan Bacon }), 64082815dcSEvan Bacon 'package.json': JSON.stringify({ 65082815dcSEvan Bacon name: 'js-config-test', 66082815dcSEvan Bacon version: '1.0.0', 67082815dcSEvan Bacon }), 68082815dcSEvan Bacon // Config exporting a function on the module.exports object 69082815dcSEvan Bacon 'app.config.js': `module.exports = function ({ config }) { 70082815dcSEvan Bacon config.foo = 'bar'; 71082815dcSEvan Bacon if (config.name) config.name += '+config'; 72082815dcSEvan Bacon if (config.slug) config.slug += '+config'; 73082815dcSEvan Bacon return config; 74082815dcSEvan Bacon };`, 75*97e1898cSEvan Bacon }, 76*97e1898cSEvan Bacon '/' 77*97e1898cSEvan Bacon ); 78*97e1898cSEvan Bacon 79*97e1898cSEvan Bacon // ensure config is composed (package.json values still exist) 80*97e1898cSEvan Bacon const { exp, dynamicConfigPath, staticConfigPath } = getConfig('/', { 81*97e1898cSEvan Bacon skipSDKVersionRequirement: true, 82*97e1898cSEvan Bacon }); 83*97e1898cSEvan Bacon expect(dynamicConfigPath).toBe('/app.config.js'); 84*97e1898cSEvan Bacon expect(staticConfigPath).toBe('/app.json'); 85*97e1898cSEvan Bacon 86*97e1898cSEvan Bacon // @ts-ignore: foo property is not defined 87*97e1898cSEvan Bacon expect(exp.foo).toBe('bar'); 88*97e1898cSEvan Bacon // Ensure the config is passed the package.json values 89*97e1898cSEvan Bacon expect(exp.name).toBe('js-config-test+config'); 90*97e1898cSEvan Bacon // Ensures that the app.json is read and passed to the method 91*97e1898cSEvan Bacon expect(exp.slug).toBe('someslug+config'); 92*97e1898cSEvan Bacon expect(exp._internal).toStrictEqual({ 93*97e1898cSEvan Bacon dynamicConfigPath: '/app.config.js', 94*97e1898cSEvan Bacon isDebug: false, 95*97e1898cSEvan Bacon packageJsonPath: '/package.json', 96*97e1898cSEvan Bacon projectRoot: '/', 97*97e1898cSEvan Bacon staticConfigPath: '/app.json', 98*97e1898cSEvan Bacon }); 99*97e1898cSEvan Bacon }); 100*97e1898cSEvan Bacon it('parses a js config with export default', () => { 101*97e1898cSEvan Bacon vol.fromJSON( 102*97e1898cSEvan Bacon { 103*97e1898cSEvan Bacon 'package.json': JSON.stringify({ 104*97e1898cSEvan Bacon name: 'js-config-test', 105*97e1898cSEvan Bacon version: '1.0.0', 106*97e1898cSEvan Bacon }), 107082815dcSEvan Bacon // Config exporting a function as default 108*97e1898cSEvan Bacon 'app.config.js': `export default function ({ config }) { 109082815dcSEvan Bacon config.foo = 'bar'; 110082815dcSEvan Bacon if (config.name) config.name += '+config-default'; 111082815dcSEvan Bacon return config; 112082815dcSEvan Bacon }`, 113*97e1898cSEvan Bacon }, 114*97e1898cSEvan Bacon '/' 115*97e1898cSEvan Bacon ); 116*97e1898cSEvan Bacon const { exp, staticConfigPath } = getConfig('/', { 117*97e1898cSEvan Bacon skipSDKVersionRequirement: true, 118*97e1898cSEvan Bacon }); 119*97e1898cSEvan Bacon // @ts-ignore: foo property is not defined 120*97e1898cSEvan Bacon expect(exp.foo).toBe('bar'); 121*97e1898cSEvan Bacon expect(exp.name).toBe('js-config-test+config-default'); 122*97e1898cSEvan Bacon // Static is undefined when a custom path is a dynamic config. 123*97e1898cSEvan Bacon expect(staticConfigPath).toBe(null); 124*97e1898cSEvan Bacon }); 125*97e1898cSEvan Bacon it('parses a js config that exports json', () => { 126*97e1898cSEvan Bacon vol.fromJSON( 127*97e1898cSEvan Bacon { 128*97e1898cSEvan Bacon 'package.json': JSON.stringify({ 129*97e1898cSEvan Bacon name: 'js-config-test', 130*97e1898cSEvan Bacon version: '1.0.0', 131*97e1898cSEvan Bacon }), 132082815dcSEvan Bacon // Config exporting an object (JSON) 133*97e1898cSEvan Bacon 'app.config.js': `module.exports = { 134082815dcSEvan Bacon foo: 'bar', 135082815dcSEvan Bacon name: 'cool+export-json_app.config', 136082815dcSEvan Bacon };`, 137082815dcSEvan Bacon }, 138*97e1898cSEvan Bacon '/' 139082815dcSEvan Bacon ); 140*97e1898cSEvan Bacon 141*97e1898cSEvan Bacon const { exp } = getConfig('/', { 142*97e1898cSEvan Bacon skipSDKVersionRequirement: true, 143*97e1898cSEvan Bacon }); 144*97e1898cSEvan Bacon // @ts-ignore: foo property is not defined 145*97e1898cSEvan Bacon expect(exp.foo).toBe('bar'); 146*97e1898cSEvan Bacon expect(exp.name).toBe('cool+export-json_app.config'); 147*97e1898cSEvan Bacon }); 148*97e1898cSEvan Bacon }); 149*97e1898cSEvan Bacon 150*97e1898cSEvan Bacon describe('behavior', () => { 151*97e1898cSEvan Bacon beforeEach(() => { 152*97e1898cSEvan Bacon delete process.env.EXPO_DEBUG; 153*97e1898cSEvan Bacon vol.reset(); 154*97e1898cSEvan Bacon }); 155*97e1898cSEvan Bacon 156*97e1898cSEvan Bacon it(`skips plugin parsing`, () => { 157082815dcSEvan Bacon vol.fromJSON( 158082815dcSEvan Bacon { 159082815dcSEvan Bacon 'app.json': JSON.stringify({ 160082815dcSEvan Bacon expo: { 161082815dcSEvan Bacon name: 'app-expo-name', 162082815dcSEvan Bacon plugins: ['__missing-plugin'], 163082815dcSEvan Bacon }, 164082815dcSEvan Bacon }), 165082815dcSEvan Bacon 'package.json': JSON.stringify({ 166082815dcSEvan Bacon version: '1.0.0', 167082815dcSEvan Bacon }), 168082815dcSEvan Bacon }, 169*97e1898cSEvan Bacon '/' 170082815dcSEvan Bacon ); 171*97e1898cSEvan Bacon const { exp } = getConfig('/', { 172*97e1898cSEvan Bacon skipSDKVersionRequirement: true, 173*97e1898cSEvan Bacon skipPlugins: true, 174*97e1898cSEvan Bacon }); 175*97e1898cSEvan Bacon expect(exp.plugins).toBeUndefined(); 176*97e1898cSEvan Bacon }); 177*97e1898cSEvan Bacon it(`skips JS plugin parsing`, () => { 178082815dcSEvan Bacon vol.fromJSON( 179082815dcSEvan Bacon { 180082815dcSEvan Bacon 'app.config.js': `module.exports = { 181082815dcSEvan Bacon foo: 'bar', 182082815dcSEvan Bacon name: 'cool+export-json_app.config', 183082815dcSEvan Bacon plugins: [(config)=> { config.name ='custom'; return config; }] 184082815dcSEvan Bacon };`, 185082815dcSEvan Bacon 'package.json': JSON.stringify({ 186082815dcSEvan Bacon version: '1.0.0', 187082815dcSEvan Bacon }), 188082815dcSEvan Bacon }, 189*97e1898cSEvan Bacon '/' 190082815dcSEvan Bacon ); 191*97e1898cSEvan Bacon const { exp } = getConfig('/', { 192082815dcSEvan Bacon skipSDKVersionRequirement: true, 193082815dcSEvan Bacon skipPlugins: true, 194082815dcSEvan Bacon }); 195082815dcSEvan Bacon expect(exp.name).toBe('cool+export-json_app.config'); 196082815dcSEvan Bacon expect(exp.plugins).toBeUndefined(); 197082815dcSEvan Bacon }); 198082815dcSEvan Bacon it(`applies JS plugins`, () => { 199*97e1898cSEvan Bacon vol.fromJSON( 200*97e1898cSEvan Bacon { 201*97e1898cSEvan Bacon 'app.config.js': `module.exports = { 202*97e1898cSEvan Bacon foo: 'bar', 203*97e1898cSEvan Bacon name: 'cool+export-json_app.config', 204*97e1898cSEvan Bacon plugins: [(config)=> { config.name ='custom'; return config; }] 205*97e1898cSEvan Bacon };`, 206*97e1898cSEvan Bacon 'package.json': JSON.stringify({ 207*97e1898cSEvan Bacon version: '1.0.0', 208*97e1898cSEvan Bacon }), 209*97e1898cSEvan Bacon }, 210*97e1898cSEvan Bacon '/' 211*97e1898cSEvan Bacon ); 212*97e1898cSEvan Bacon const { exp } = getConfig('/', { 213082815dcSEvan Bacon skipSDKVersionRequirement: true, 214082815dcSEvan Bacon skipPlugins: false, 215082815dcSEvan Bacon }); 216082815dcSEvan Bacon expect(exp.name).toBe('custom'); 217082815dcSEvan Bacon expect(exp.plugins).toBeDefined(); 218082815dcSEvan Bacon }); 219082815dcSEvan Bacon it(`throws when plugins are missing`, () => { 220*97e1898cSEvan Bacon vol.fromJSON( 221*97e1898cSEvan Bacon { 222*97e1898cSEvan Bacon 'app.json': JSON.stringify({ 223*97e1898cSEvan Bacon expo: { 224*97e1898cSEvan Bacon name: 'app-expo-name', 225*97e1898cSEvan Bacon plugins: ['__missing-plugin'], 226*97e1898cSEvan Bacon }, 227*97e1898cSEvan Bacon }), 228*97e1898cSEvan Bacon 'package.json': JSON.stringify({ 229*97e1898cSEvan Bacon version: '1.0.0', 230*97e1898cSEvan Bacon }), 231*97e1898cSEvan Bacon }, 232*97e1898cSEvan Bacon '/' 233*97e1898cSEvan Bacon ); 234082815dcSEvan Bacon expect(() => 235*97e1898cSEvan Bacon getConfig('/', { 236082815dcSEvan Bacon skipSDKVersionRequirement: true, 237082815dcSEvan Bacon skipPlugins: false, 238082815dcSEvan Bacon }) 239*97e1898cSEvan Bacon ).toThrow(/Failed to resolve plugin for module "__missing-plugin" relative to "\/"/); 240082815dcSEvan Bacon }); 241082815dcSEvan Bacon }); 242082815dcSEvan Bacon}); 243