16a750d06SEvan Baconimport { vol, fs } from 'memfs';
26a750d06SEvan Bacon
36a750d06SEvan Baconimport { createControlledEnvironment, getFiles } from '../env';
46a750d06SEvan Bacon
56a750d06SEvan BaconbeforeEach(() => {
66a750d06SEvan Bacon  vol.reset();
76a750d06SEvan Bacon});
86a750d06SEvan Bacon
96a750d06SEvan Baconconst originalEnv = process.env;
106a750d06SEvan Bacon
116a750d06SEvan Baconfunction resetEnv() {
126a750d06SEvan Bacon  process.env = originalEnv;
1378a6243aSEvan Bacon  delete process.env.EXPO_NO_DOTENV;
146a750d06SEvan Bacon}
156a750d06SEvan Bacon
166a750d06SEvan BaconbeforeEach(() => {
176a750d06SEvan Bacon  resetEnv();
186a750d06SEvan Bacon});
196a750d06SEvan BaconafterAll(() => {
206a750d06SEvan Bacon  resetEnv();
216a750d06SEvan Bacon});
226a750d06SEvan Bacon
236a750d06SEvan Bacondescribe(getFiles, () => {
2478a6243aSEvan Bacon  const originalError = console.error;
256a750d06SEvan Bacon  beforeEach(() => {
2678a6243aSEvan Bacon    console.error = jest.fn();
276a750d06SEvan Bacon    resetEnv();
286a750d06SEvan Bacon  });
2978a6243aSEvan Bacon  afterEach(() => {
3078a6243aSEvan Bacon    console.error = originalError;
3178a6243aSEvan Bacon  });
326a750d06SEvan Bacon
336a750d06SEvan Bacon  it(`gets development files`, () => {
346a750d06SEvan Bacon    expect(getFiles('development')).toEqual([
356a750d06SEvan Bacon      '.env.development.local',
366a750d06SEvan Bacon      '.env.local',
376a750d06SEvan Bacon      '.env.development',
386a750d06SEvan Bacon      '.env',
396a750d06SEvan Bacon    ]);
406a750d06SEvan Bacon  });
416a750d06SEvan Bacon  it(`gets production files`, () => {
426a750d06SEvan Bacon    expect(getFiles('production')).toEqual([
436a750d06SEvan Bacon      '.env.production.local',
446a750d06SEvan Bacon      '.env.local',
456a750d06SEvan Bacon      '.env.production',
466a750d06SEvan Bacon      '.env',
476a750d06SEvan Bacon    ]);
486a750d06SEvan Bacon  });
496a750d06SEvan Bacon  it(`gets test files`, () => {
506a750d06SEvan Bacon    // important
516a750d06SEvan Bacon    expect(getFiles('test')).toEqual(['.env.test.local', '.env.test', '.env']);
526a750d06SEvan Bacon  });
5378a6243aSEvan Bacon  it(`gets no files when dotenv is disabled`, () => {
5478a6243aSEvan Bacon    process.env.EXPO_NO_DOTENV = '1';
5578a6243aSEvan Bacon    ['development', 'production', 'test'].forEach((mode) => {
5678a6243aSEvan Bacon      expect(getFiles(mode)).toEqual([]);
57f5917927SEvan Bacon    });
58f5917927SEvan Bacon  });
596a750d06SEvan Bacon
606a750d06SEvan Bacon  it(`throws if NODE_ENV is not set`, () => {
61f5917927SEvan Bacon    getFiles(undefined);
62f5917927SEvan Bacon
63f5917927SEvan Bacon    expect(console.error).toBeCalledTimes(2);
64f5917927SEvan Bacon    expect(console.error).toBeCalledWith(
65f5917927SEvan Bacon      expect.stringContaining('The NODE_ENV environment variable is required but was not specified')
666a750d06SEvan Bacon    );
676a750d06SEvan Bacon  });
686a750d06SEvan Bacon  it(`throws if NODE_ENV is not valid`, () => {
696a750d06SEvan Bacon    expect(() => getFiles('invalid')).toThrowErrorMatchingInlineSnapshot(
706a750d06SEvan Bacon      `"Environment variable "NODE_ENV=invalid" is invalid. Valid values are "development", "test", and "production"`
716a750d06SEvan Bacon    );
726a750d06SEvan Bacon  });
736a750d06SEvan Bacon});
746a750d06SEvan Bacon
756a750d06SEvan Bacondescribe('get', () => {
766a750d06SEvan Bacon  beforeEach(() => {
776a750d06SEvan Bacon    resetEnv();
786a750d06SEvan Bacon  });
796a750d06SEvan Bacon
806a750d06SEvan Bacon  it(`memoizes`, () => {
816a750d06SEvan Bacon    delete process.env.FOO;
826a750d06SEvan Bacon    const envRuntime = createControlledEnvironment();
836a750d06SEvan Bacon    vol.fromJSON(
846a750d06SEvan Bacon      {
856a750d06SEvan Bacon        '.env': 'FOO=default',
866a750d06SEvan Bacon      },
876a750d06SEvan Bacon      '/'
886a750d06SEvan Bacon    );
896a750d06SEvan Bacon    expect(envRuntime.get('/')).toEqual({
90*e30a2315SEvan Bacon      env: {
916a750d06SEvan Bacon        FOO: 'default',
92*e30a2315SEvan Bacon      },
93*e30a2315SEvan Bacon      files: ['/.env'],
946a750d06SEvan Bacon    });
956a750d06SEvan Bacon
966a750d06SEvan Bacon    fs.writeFileSync('/.env', 'FOO=changed');
976a750d06SEvan Bacon
986a750d06SEvan Bacon    expect(envRuntime.get('/')).toEqual({
99*e30a2315SEvan Bacon      env: {
1006a750d06SEvan Bacon        FOO: 'default',
101*e30a2315SEvan Bacon      },
102*e30a2315SEvan Bacon      files: ['/.env'],
1036a750d06SEvan Bacon    });
1046a750d06SEvan Bacon    expect(envRuntime.get('/', { force: true })).toEqual({
105*e30a2315SEvan Bacon      env: {
1066a750d06SEvan Bacon        FOO: 'changed',
107*e30a2315SEvan Bacon      },
108*e30a2315SEvan Bacon      files: ['/.env'],
1096a750d06SEvan Bacon    });
1106a750d06SEvan Bacon  });
1116a750d06SEvan Bacon});
1126a750d06SEvan Bacondescribe('_getForce', () => {
1136a750d06SEvan Bacon  beforeEach(() => {
1146a750d06SEvan Bacon    resetEnv();
1156a750d06SEvan Bacon  });
1166a750d06SEvan Bacon
1176a750d06SEvan Bacon  it(`returns the value of the environment variable`, () => {
1186a750d06SEvan Bacon    delete process.env.FOO;
1196a750d06SEvan Bacon
1206a750d06SEvan Bacon    const envRuntime = createControlledEnvironment();
1216a750d06SEvan Bacon    vol.fromJSON(
1226a750d06SEvan Bacon      {
1236a750d06SEvan Bacon        '.env': 'FOO=bar',
1246a750d06SEvan Bacon      },
1256a750d06SEvan Bacon      '/'
1266a750d06SEvan Bacon    );
1276a750d06SEvan Bacon
1286a750d06SEvan Bacon    expect(envRuntime._getForce('/')).toEqual({
129*e30a2315SEvan Bacon      env: {
1306a750d06SEvan Bacon        FOO: 'bar',
131*e30a2315SEvan Bacon      },
132*e30a2315SEvan Bacon      files: ['/.env'],
1336a750d06SEvan Bacon    });
1346a750d06SEvan Bacon  });
1356a750d06SEvan Bacon
1366a750d06SEvan Bacon  it(`cascades env files (development)`, () => {
1376a750d06SEvan Bacon    delete process.env.FOO;
1386a750d06SEvan Bacon    process.env.NODE_ENV = 'development';
1396a750d06SEvan Bacon    const envRuntime = createControlledEnvironment();
1406a750d06SEvan Bacon    vol.fromJSON(
1416a750d06SEvan Bacon      {
1426a750d06SEvan Bacon        '.env': 'FOO=default',
1436a750d06SEvan Bacon        '.env.local': 'FOO=default-local',
1446a750d06SEvan Bacon        '.env.development': 'FOO=dev',
1456a750d06SEvan Bacon        '.env.production': 'FOO=prod',
1466a750d06SEvan Bacon        '.env.production.local': 'FOO=prod-local',
1476a750d06SEvan Bacon        '.env.development.local': 'FOO=dev-local',
1486a750d06SEvan Bacon      },
1496a750d06SEvan Bacon      '/'
1506a750d06SEvan Bacon    );
1516a750d06SEvan Bacon
1526a750d06SEvan Bacon    expect(envRuntime._getForce('/')).toEqual({
153*e30a2315SEvan Bacon      env: {
1546a750d06SEvan Bacon        FOO: 'dev-local',
155*e30a2315SEvan Bacon      },
156*e30a2315SEvan Bacon      files: ['/.env.development.local', '/.env.local', '/.env.development', '/.env'],
1576a750d06SEvan Bacon    });
1586a750d06SEvan Bacon  });
1596a750d06SEvan Bacon
1606a750d06SEvan Bacon  it(`cascades env files (production)`, () => {
1616a750d06SEvan Bacon    delete process.env.FOO;
1626a750d06SEvan Bacon    process.env.NODE_ENV = 'production';
1636a750d06SEvan Bacon    const envRuntime = createControlledEnvironment();
1646a750d06SEvan Bacon    vol.fromJSON(
1656a750d06SEvan Bacon      {
1666a750d06SEvan Bacon        '.env': 'FOO=default',
1676a750d06SEvan Bacon        '.env.local': 'FOO=default-local',
1686a750d06SEvan Bacon        '.env.production': 'FOO=prod',
1696a750d06SEvan Bacon        '.env.production.local': 'FOO=prod-local',
1706a750d06SEvan Bacon      },
1716a750d06SEvan Bacon      '/'
1726a750d06SEvan Bacon    );
1736a750d06SEvan Bacon
1746a750d06SEvan Bacon    expect(envRuntime._getForce('/')).toEqual({
175*e30a2315SEvan Bacon      files: ['/.env.production.local', '/.env.local', '/.env.production', '/.env'],
176*e30a2315SEvan Bacon      env: {
1776a750d06SEvan Bacon        FOO: 'prod-local',
178*e30a2315SEvan Bacon      },
1796a750d06SEvan Bacon    });
1806a750d06SEvan Bacon  });
1816a750d06SEvan Bacon
1826a750d06SEvan Bacon  it(`cascades env files (default)`, () => {
1836a750d06SEvan Bacon    delete process.env.FOO;
1846a750d06SEvan Bacon    const envRuntime = createControlledEnvironment();
1856a750d06SEvan Bacon    vol.fromJSON(
1866a750d06SEvan Bacon      {
1876a750d06SEvan Bacon        '.env': 'FOO=default',
1886a750d06SEvan Bacon        '.env.local': 'FOO=default-local',
1896a750d06SEvan Bacon      },
1906a750d06SEvan Bacon      '/'
1916a750d06SEvan Bacon    );
1926a750d06SEvan Bacon
1936a750d06SEvan Bacon    expect(envRuntime._getForce('/')).toEqual({
194*e30a2315SEvan Bacon      files: ['/.env.local', '/.env'],
195*e30a2315SEvan Bacon      env: {
1966a750d06SEvan Bacon        FOO: 'default-local',
197*e30a2315SEvan Bacon      },
1986a750d06SEvan Bacon    });
1996a750d06SEvan Bacon  });
2006a750d06SEvan Bacon
20178a6243aSEvan Bacon  it(`skips modifying the environment with dotenv if disabled with EXPO_NO_DOTENV`, () => {
20278a6243aSEvan Bacon    delete process.env.FOO;
20378a6243aSEvan Bacon    process.env.EXPO_NO_DOTENV = '1';
20478a6243aSEvan Bacon    const envRuntime = createControlledEnvironment();
20578a6243aSEvan Bacon    vol.fromJSON(
20678a6243aSEvan Bacon      {
20778a6243aSEvan Bacon        '.env': 'FOO=default',
20878a6243aSEvan Bacon        '.env.local': 'FOO=default-local',
20978a6243aSEvan Bacon      },
21078a6243aSEvan Bacon      '/'
21178a6243aSEvan Bacon    );
21278a6243aSEvan Bacon
213*e30a2315SEvan Bacon    expect(envRuntime._getForce('/')).toEqual({ env: {}, files: [] });
21478a6243aSEvan Bacon  });
21578a6243aSEvan Bacon
2166a750d06SEvan Bacon  it(`does not return the env var if the initial the value of the environment variable`, () => {
2176a750d06SEvan Bacon    const envRuntime = createControlledEnvironment();
2186a750d06SEvan Bacon    process.env.FOO = 'not-bar';
2196a750d06SEvan Bacon
2206a750d06SEvan Bacon    vol.fromJSON(
2216a750d06SEvan Bacon      {
2226a750d06SEvan Bacon        '.env': 'FOO=bar',
2236a750d06SEvan Bacon      },
2246a750d06SEvan Bacon      '/'
2256a750d06SEvan Bacon    );
2266a750d06SEvan Bacon
227*e30a2315SEvan Bacon    expect(envRuntime._getForce('/')).toEqual({ env: {}, files: ['/.env'] });
2286a750d06SEvan Bacon  });
2296a750d06SEvan Bacon
2306a750d06SEvan Bacon  it(`Does not fail when no files are available`, () => {
2316a750d06SEvan Bacon    vol.fromJSON({}, '/');
232*e30a2315SEvan Bacon    expect(createControlledEnvironment()._getForce('/')).toEqual({
233*e30a2315SEvan Bacon      env: {},
234*e30a2315SEvan Bacon      files: [],
235*e30a2315SEvan Bacon    });
2366a750d06SEvan Bacon  });
2376a750d06SEvan Bacon
2386a750d06SEvan Bacon  it(`Does not assert on invalid env files`, () => {
2396a750d06SEvan Bacon    vol.fromJSON(
2406a750d06SEvan Bacon      {
2416a750d06SEvan Bacon        '.env': 'ˆ˙•ª∆ø…ˆ',
2426a750d06SEvan Bacon      },
2436a750d06SEvan Bacon      '/'
2446a750d06SEvan Bacon    );
2456a750d06SEvan Bacon
246*e30a2315SEvan Bacon    expect(createControlledEnvironment()._getForce('/')).toEqual({ env: {}, files: ['/.env'] });
2476a750d06SEvan Bacon  });
2486a750d06SEvan Bacon});
249