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