1import * as fs from 'fs'; 2import { vol } from 'memfs'; 3import * as path from 'path'; 4 5import { getConfig } from '../Config'; 6 7const fsReal = jest.requireActual('fs') as typeof fs; 8 9jest.mock('fs'); 10 11describe(getConfig, () => { 12 afterAll(() => { 13 vol.reset(); 14 }); 15 16 // Tests the following: 17 // - All supported languages are working 18 // - ensure `app.config` has higher priority to `app` 19 // - generated `.expo` object is created and the language hint is added 20 describe('language support', () => { 21 beforeEach(() => { 22 delete process.env.EXPO_DEBUG; 23 vol.reset(); 24 }); 25 it('parses a ts config', () => { 26 vol.fromJSON( 27 { 28 // Read this TS file so we can validate the types 29 'app.config.ts': fsReal.readFileSync( 30 path.join(__dirname, './fixtures/ts/app.config.ts'), 31 'utf8' 32 ), 33 'package.json': JSON.stringify({ 34 name: 'ts-config-test', 35 version: '1.0.0', 36 }), 37 }, 38 '/' 39 ); 40 41 const { exp } = getConfig('/', { 42 skipSDKVersionRequirement: true, 43 }); 44 // @ts-ignore: foo property is not defined 45 expect(exp.foo).toBe('bar+value'); 46 expect(exp.name).toBe('rewrote+ts-config-test'); 47 expect(exp._internal).toStrictEqual({ 48 dynamicConfigPath: '/app.config.ts', 49 isDebug: false, 50 packageJsonPath: '/package.json', 51 projectRoot: '/', 52 staticConfigPath: null, 53 }); 54 }); 55 it('parses a js config', () => { 56 vol.fromJSON( 57 { 58 'app.json': JSON.stringify({ 59 expo: { 60 foo: 'invalid', 61 slug: 'someslug', 62 }, 63 }), 64 'package.json': JSON.stringify({ 65 name: 'js-config-test', 66 version: '1.0.0', 67 }), 68 // Config exporting a function on the module.exports object 69 'app.config.js': `module.exports = function ({ config }) { 70 config.foo = 'bar'; 71 if (config.name) config.name += '+config'; 72 if (config.slug) config.slug += '+config'; 73 return config; 74 };`, 75 }, 76 '/' 77 ); 78 79 // ensure config is composed (package.json values still exist) 80 const { exp, dynamicConfigPath, staticConfigPath } = getConfig('/', { 81 skipSDKVersionRequirement: true, 82 }); 83 expect(dynamicConfigPath).toBe('/app.config.js'); 84 expect(staticConfigPath).toBe('/app.json'); 85 86 // @ts-ignore: foo property is not defined 87 expect(exp.foo).toBe('bar'); 88 // Ensure the config is passed the package.json values 89 expect(exp.name).toBe('js-config-test+config'); 90 // Ensures that the app.json is read and passed to the method 91 expect(exp.slug).toBe('someslug+config'); 92 expect(exp._internal).toStrictEqual({ 93 dynamicConfigPath: '/app.config.js', 94 isDebug: false, 95 packageJsonPath: '/package.json', 96 projectRoot: '/', 97 staticConfigPath: '/app.json', 98 }); 99 }); 100 it('parses a js config with export default', () => { 101 vol.fromJSON( 102 { 103 'package.json': JSON.stringify({ 104 name: 'js-config-test', 105 version: '1.0.0', 106 }), 107 // Config exporting a function as default 108 'app.config.js': `export default function ({ config }) { 109 config.foo = 'bar'; 110 if (config.name) config.name += '+config-default'; 111 return config; 112 }`, 113 }, 114 '/' 115 ); 116 const { exp, staticConfigPath } = getConfig('/', { 117 skipSDKVersionRequirement: true, 118 }); 119 // @ts-ignore: foo property is not defined 120 expect(exp.foo).toBe('bar'); 121 expect(exp.name).toBe('js-config-test+config-default'); 122 // Static is undefined when a custom path is a dynamic config. 123 expect(staticConfigPath).toBe(null); 124 }); 125 it('parses a js config that exports json', () => { 126 vol.fromJSON( 127 { 128 'package.json': JSON.stringify({ 129 name: 'js-config-test', 130 version: '1.0.0', 131 }), 132 // Config exporting an object (JSON) 133 'app.config.js': `module.exports = { 134 foo: 'bar', 135 name: 'cool+export-json_app.config', 136 };`, 137 }, 138 '/' 139 ); 140 141 const { exp } = getConfig('/', { 142 skipSDKVersionRequirement: true, 143 }); 144 // @ts-ignore: foo property is not defined 145 expect(exp.foo).toBe('bar'); 146 expect(exp.name).toBe('cool+export-json_app.config'); 147 }); 148 }); 149 150 describe('behavior', () => { 151 beforeEach(() => { 152 delete process.env.EXPO_DEBUG; 153 vol.reset(); 154 }); 155 156 it(`skips plugin parsing`, () => { 157 vol.fromJSON( 158 { 159 'app.json': JSON.stringify({ 160 expo: { 161 name: 'app-expo-name', 162 plugins: ['__missing-plugin'], 163 }, 164 }), 165 'package.json': JSON.stringify({ 166 version: '1.0.0', 167 }), 168 }, 169 '/' 170 ); 171 const { exp } = getConfig('/', { 172 skipSDKVersionRequirement: true, 173 skipPlugins: true, 174 }); 175 expect(exp.plugins).toBeUndefined(); 176 }); 177 it(`skips JS plugin parsing`, () => { 178 vol.fromJSON( 179 { 180 'app.config.js': `module.exports = { 181 foo: 'bar', 182 name: 'cool+export-json_app.config', 183 plugins: [(config)=> { config.name ='custom'; return config; }] 184 };`, 185 'package.json': JSON.stringify({ 186 version: '1.0.0', 187 }), 188 }, 189 '/' 190 ); 191 const { exp } = getConfig('/', { 192 skipSDKVersionRequirement: true, 193 skipPlugins: true, 194 }); 195 expect(exp.name).toBe('cool+export-json_app.config'); 196 expect(exp.plugins).toBeUndefined(); 197 }); 198 it(`applies JS plugins`, () => { 199 vol.fromJSON( 200 { 201 'app.config.js': `module.exports = { 202 foo: 'bar', 203 name: 'cool+export-json_app.config', 204 plugins: [(config)=> { config.name ='custom'; return config; }] 205 };`, 206 'package.json': JSON.stringify({ 207 version: '1.0.0', 208 }), 209 }, 210 '/' 211 ); 212 const { exp } = getConfig('/', { 213 skipSDKVersionRequirement: true, 214 skipPlugins: false, 215 }); 216 expect(exp.name).toBe('custom'); 217 expect(exp.plugins).toBeDefined(); 218 }); 219 it(`throws when plugins are missing`, () => { 220 vol.fromJSON( 221 { 222 'app.json': JSON.stringify({ 223 expo: { 224 name: 'app-expo-name', 225 plugins: ['__missing-plugin'], 226 }, 227 }), 228 'package.json': JSON.stringify({ 229 version: '1.0.0', 230 }), 231 }, 232 '/' 233 ); 234 expect(() => 235 getConfig('/', { 236 skipSDKVersionRequirement: true, 237 skipPlugins: false, 238 }) 239 ).toThrow(/Failed to resolve plugin for module "__missing-plugin" relative to "\/"/); 240 }); 241 }); 242}); 243