Skip to content

Commit ae3d55e

Browse files
authored
Make "process.env" case insensitive in Windows (#5465)
1 parent af09be8 commit ae3d55e

2 files changed

Lines changed: 83 additions & 1 deletion

File tree

packages/jest-util/src/__tests__/create_process_object.test.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,47 @@ it('creates a process object that looks like the original one', () => {
3030
it('fakes require("process") so it is equal to "global.process"', () => {
3131
expect(require('process') === process).toBe(true);
3232
});
33+
34+
it('checks that process.env works as expected on Linux platforms', () => {
35+
Object.defineProperty(process, 'platform', {get: () => 'linux'});
36+
37+
// Existing properties inside process.env are copied to the fake environment.
38+
process.env.PROP_STRING = 'foo';
39+
process.env.PROP_NUMBER = 3;
40+
process.env.PROP_UNDEFINED = undefined;
41+
42+
const fake = createProcessObject().env;
43+
44+
// All values converted to strings.
45+
expect(fake.PROP_STRING).toBe('foo');
46+
expect(fake.PROP_NUMBER).toBe('3');
47+
expect(fake.PROP_UNDEFINED).toBe('undefined');
48+
49+
// Mac and Linux are case sensitive.
50+
expect(fake.PROP_string).toBe(undefined);
51+
52+
// Added properties to the fake object are not added to the real one.
53+
fake.PROP_ADDED = 'new!';
54+
55+
expect(fake.PROP_ADDED).toBe('new!');
56+
expect(process.env.PROP_ADDED).toBe(undefined);
57+
});
58+
59+
it('checks that process.env works as expected in Windows platforms', () => {
60+
Object.defineProperty(process, 'platform', {get: () => 'win32'});
61+
62+
// Windows is not case sensitive when it comes to property names.
63+
process.env.PROP_STRING = 'foo';
64+
65+
const fake = createProcessObject().env;
66+
67+
expect(fake.PROP_STRING).toBe('foo');
68+
expect(fake.PROP_string).toBe('foo');
69+
70+
// Inherited methods, however, are not affected by case insensitiveness.
71+
expect(typeof fake.toString).toBe('function');
72+
expect(typeof fake.valueOf).toBe('function');
73+
74+
expect(typeof fake.tostring).toBe('undefined');
75+
expect(typeof fake.valueof).toBe('undefined');
76+
});

packages/jest-util/src/create_process_object.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,43 @@
99

1010
import deepCyclicCopy from './deep_cyclic_copy';
1111

12-
const BLACKLIST = new Set(['mainModule', '_events']);
12+
const BLACKLIST = new Set(['env', 'mainModule', '_events']);
13+
14+
// The "process.env" object has a bunch of particularities: first, it does not
15+
// directly extend from Object; second, it converts any assigned value to a
16+
// string; and third, it is case-insensitive in Windows. We use a proxy here to
17+
// mimic it (see https://nodejs.org/api/process.html#process_process_env).
18+
19+
function createProcessEnv() {
20+
// $FlowFixMe: Apparently Flow does not understand that this is a prototype.
21+
const proto: Object = Object.getPrototypeOf(process.env);
22+
const real = Object.create(proto);
23+
const lookup = {};
24+
25+
const proxy = new Proxy(real, {
26+
get(target, key) {
27+
if ((typeof key === 'string') && (process.platform === 'win32')) {
28+
return lookup[key in proto ? key : key.toLowerCase()];
29+
} else {
30+
return real[key];
31+
}
32+
},
33+
34+
set(target, key, value) {
35+
const strValue = '' + value;
36+
37+
if (typeof key === 'string') {
38+
lookup[key.toLowerCase()] = strValue;
39+
}
40+
41+
real[key] = strValue;
42+
43+
return true;
44+
},
45+
});
46+
47+
return Object.assign(proxy, process.env);
48+
}
1349

1450
export default function() {
1551
const process = require('process');
@@ -29,5 +65,7 @@ export default function() {
2965
}
3066
}
3167

68+
newProcess.env = createProcessEnv();
69+
3270
return newProcess;
3371
}

0 commit comments

Comments
 (0)