1import { vol, fs } from 'memfs'; 2 3import { createControlledEnvironment, getFiles } from '../env'; 4 5beforeEach(() => { 6 vol.reset(); 7}); 8 9const originalEnv = process.env; 10 11function resetEnv() { 12 process.env = originalEnv; 13 delete process.env.EXPO_NO_DOTENV; 14} 15 16beforeEach(() => { 17 resetEnv(); 18}); 19afterAll(() => { 20 resetEnv(); 21}); 22 23describe(getFiles, () => { 24 const originalError = console.error; 25 beforeEach(() => { 26 console.error = jest.fn(); 27 resetEnv(); 28 }); 29 afterEach(() => { 30 console.error = originalError; 31 }); 32 33 it(`gets development files`, () => { 34 expect(getFiles('development')).toEqual([ 35 '.env.development.local', 36 '.env.local', 37 '.env.development', 38 '.env', 39 ]); 40 }); 41 it(`gets production files`, () => { 42 expect(getFiles('production')).toEqual([ 43 '.env.production.local', 44 '.env.local', 45 '.env.production', 46 '.env', 47 ]); 48 }); 49 it(`gets test files`, () => { 50 // important 51 expect(getFiles('test')).toEqual(['.env.test.local', '.env.test', '.env']); 52 }); 53 it(`gets no files when dotenv is disabled`, () => { 54 process.env.EXPO_NO_DOTENV = '1'; 55 ['development', 'production', 'test'].forEach((mode) => { 56 expect(getFiles(mode)).toEqual([]); 57 }); 58 }); 59 60 it(`throws if NODE_ENV is not set`, () => { 61 getFiles(undefined); 62 63 expect(console.error).toBeCalledTimes(2); 64 expect(console.error).toBeCalledWith( 65 expect.stringContaining('The NODE_ENV environment variable is required but was not specified') 66 ); 67 }); 68 it(`throws if NODE_ENV is not valid`, () => { 69 expect(() => getFiles('invalid')).toThrowErrorMatchingInlineSnapshot( 70 `"Environment variable "NODE_ENV=invalid" is invalid. Valid values are "development", "test", and "production"` 71 ); 72 }); 73}); 74 75describe('get', () => { 76 beforeEach(() => { 77 resetEnv(); 78 }); 79 80 it(`memoizes`, () => { 81 delete process.env.FOO; 82 const envRuntime = createControlledEnvironment(); 83 vol.fromJSON( 84 { 85 '.env': 'FOO=default', 86 }, 87 '/' 88 ); 89 expect(envRuntime.get('/')).toEqual({ 90 FOO: 'default', 91 }); 92 93 fs.writeFileSync('/.env', 'FOO=changed'); 94 95 expect(envRuntime.get('/')).toEqual({ 96 FOO: 'default', 97 }); 98 expect(envRuntime.get('/', { force: true })).toEqual({ 99 FOO: 'changed', 100 }); 101 }); 102}); 103describe('_getForce', () => { 104 beforeEach(() => { 105 resetEnv(); 106 }); 107 108 it(`returns the value of the environment variable`, () => { 109 delete process.env.FOO; 110 111 const envRuntime = createControlledEnvironment(); 112 vol.fromJSON( 113 { 114 '.env': 'FOO=bar', 115 }, 116 '/' 117 ); 118 119 expect(envRuntime._getForce('/')).toEqual({ 120 FOO: 'bar', 121 }); 122 }); 123 124 it(`cascades env files (development)`, () => { 125 delete process.env.FOO; 126 process.env.NODE_ENV = 'development'; 127 const envRuntime = createControlledEnvironment(); 128 vol.fromJSON( 129 { 130 '.env': 'FOO=default', 131 '.env.local': 'FOO=default-local', 132 '.env.development': 'FOO=dev', 133 '.env.production': 'FOO=prod', 134 '.env.production.local': 'FOO=prod-local', 135 '.env.development.local': 'FOO=dev-local', 136 }, 137 '/' 138 ); 139 140 expect(envRuntime._getForce('/')).toEqual({ 141 FOO: 'dev-local', 142 }); 143 }); 144 145 it(`cascades env files (production)`, () => { 146 delete process.env.FOO; 147 process.env.NODE_ENV = 'production'; 148 const envRuntime = createControlledEnvironment(); 149 vol.fromJSON( 150 { 151 '.env': 'FOO=default', 152 '.env.local': 'FOO=default-local', 153 '.env.production': 'FOO=prod', 154 '.env.production.local': 'FOO=prod-local', 155 }, 156 '/' 157 ); 158 159 expect(envRuntime._getForce('/')).toEqual({ 160 FOO: 'prod-local', 161 }); 162 }); 163 164 it(`cascades env files (default)`, () => { 165 delete process.env.FOO; 166 const envRuntime = createControlledEnvironment(); 167 vol.fromJSON( 168 { 169 '.env': 'FOO=default', 170 '.env.local': 'FOO=default-local', 171 }, 172 '/' 173 ); 174 175 expect(envRuntime._getForce('/')).toEqual({ 176 FOO: 'default-local', 177 }); 178 }); 179 180 it(`skips modifying the environment with dotenv if disabled with EXPO_NO_DOTENV`, () => { 181 delete process.env.FOO; 182 process.env.EXPO_NO_DOTENV = '1'; 183 const envRuntime = createControlledEnvironment(); 184 vol.fromJSON( 185 { 186 '.env': 'FOO=default', 187 '.env.local': 'FOO=default-local', 188 }, 189 '/' 190 ); 191 192 expect(envRuntime._getForce('/')).toEqual({}); 193 }); 194 195 it(`does not return the env var if the initial the value of the environment variable`, () => { 196 const envRuntime = createControlledEnvironment(); 197 process.env.FOO = 'not-bar'; 198 199 vol.fromJSON( 200 { 201 '.env': 'FOO=bar', 202 }, 203 '/' 204 ); 205 206 expect(envRuntime._getForce('/')).toEqual({}); 207 }); 208 209 it(`Does not fail when no files are available`, () => { 210 vol.fromJSON({}, '/'); 211 expect(createControlledEnvironment()._getForce('/')).toEqual({}); 212 }); 213 214 it(`Does not assert on invalid env files`, () => { 215 vol.fromJSON( 216 { 217 '.env': 'ˆ˙•ª∆ø…ˆ', 218 }, 219 '/' 220 ); 221 222 expect(createControlledEnvironment()._getForce('/')).toEqual({}); 223 }); 224}); 225