Skip to content

Commit 06bbe2d

Browse files
seanpoultercpojer
authored andcommitted
Add an option to spawn command in a shell (#5340)
* Add tests for Process.js * Add option to spawn command inside a shell * Add tests for constructor, start, and closeProcess * Add option to spawn command in a shell * Add #5340 to change log * Fix build errors
1 parent 30a9ca2 commit 06bbe2d

File tree

6 files changed

+403
-43
lines changed

6 files changed

+403
-43
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## master
22

3+
* `[jest-editor-support]` Add option to spawn command in shell ([#5340](https://github.com/facebook/jest/pull/5340))
4+
35
## jest 22.1.2
46

57
### Fixes

packages/jest-editor-support/src/Process.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
*/
99

1010
import {ChildProcess, spawn} from 'child_process';
11-
1211
import ProjectWorkspace from './project_workspace';
12+
import type {SpawnOptions} from './types';
1313

1414
/**
1515
* Spawns and returns a Jest process with specific args
@@ -20,6 +20,7 @@ import ProjectWorkspace from './project_workspace';
2020
export const createProcess = (
2121
workspace: ProjectWorkspace,
2222
args: Array<string>,
23+
options?: SpawnOptions = {},
2324
): ChildProcess => {
2425
// A command could look like `npm run test`, which we cannot use as a command
2526
// as they can only be the first command, so take out the command, and add
@@ -31,16 +32,20 @@ export const createProcess = (
3132
const runtimeArgs = [].concat(initialArgs, args);
3233

3334
// If a path to configuration file was defined, push it to runtimeArgs
34-
const configPath = workspace.pathToConfig;
35-
if (configPath !== '') {
35+
if (workspace.pathToConfig) {
3636
runtimeArgs.push('--config');
37-
runtimeArgs.push(configPath);
37+
runtimeArgs.push(workspace.pathToConfig);
3838
}
3939

4040
// To use our own commands in create-react, we need to tell the command that
4141
// we're in a CI environment, or it will always append --watch
4242
const env = process.env;
4343
env['CI'] = 'true';
4444

45-
return spawn(command, runtimeArgs, {cwd: workspace.rootPath, env});
45+
const spawnOptions = {
46+
cwd: workspace.rootPath,
47+
env,
48+
shell: options.shell,
49+
};
50+
return spawn(command, runtimeArgs, spawnOptions);
4651
};

packages/jest-editor-support/src/Runner.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import type {Options, MessageType} from './types';
10+
import type {Options, MessageType, SpawnOptions} from './types';
1111
import {messageTypes} from './types';
1212

1313
import {ChildProcess, spawn} from 'child_process';
@@ -27,6 +27,7 @@ export default class Runner extends EventEmitter {
2727
_createProcess: (
2828
workspace: ProjectWorkspace,
2929
args: Array<string>,
30+
options?: SpawnOptions,
3031
) => ChildProcess;
3132
watchMode: boolean;
3233
options: Options;
@@ -64,7 +65,11 @@ export default class Runner extends EventEmitter {
6465
args.push(this.options.testFileNamePattern);
6566
}
6667

67-
this.debugprocess = this._createProcess(this.workspace, args);
68+
const options = {
69+
shell: this.options.shell,
70+
};
71+
72+
this.debugprocess = this._createProcess(this.workspace, args, options);
6873
this.debugprocess.stdout.on('data', (data: Buffer) => {
6974
// Make jest save to a file, otherwise we get chunked data
7075
// and it can be hard to put it back together.
@@ -118,10 +123,13 @@ export default class Runner extends EventEmitter {
118123

119124
runJestWithUpdateForSnapshots(completion: any, args: string[]) {
120125
const defaultArgs = ['--updateSnapshot'];
121-
const updateProcess = this._createProcess(this.workspace, [
122-
...defaultArgs,
123-
...(args ? args : []),
124-
]);
126+
127+
const options = {shell: this.options.shell};
128+
const updateProcess = this._createProcess(
129+
this.workspace,
130+
[...defaultArgs, ...(args ? args : [])],
131+
options,
132+
);
125133
updateProcess.on('close', () => {
126134
completion();
127135
});
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
'use strict';
11+
12+
jest.mock('child_process');
13+
14+
import {createProcess} from '../Process';
15+
import {spawn} from 'child_process';
16+
17+
describe('createProcess', () => {
18+
afterEach(() => {
19+
jest.resetAllMocks();
20+
});
21+
22+
it('spawns the process', () => {
23+
const workspace: any = {pathToJest: ''};
24+
const args = [];
25+
createProcess(workspace, args);
26+
27+
expect(spawn).toBeCalled();
28+
});
29+
30+
it('spawns the command from workspace.pathToJest', () => {
31+
const workspace: any = {pathToJest: 'jest'};
32+
const args = [];
33+
createProcess(workspace, args);
34+
35+
expect(spawn.mock.calls[0][0]).toBe('jest');
36+
expect(spawn.mock.calls[0][1]).toEqual([]);
37+
});
38+
39+
it('spawns the first arg from workspace.pathToJest split on " "', () => {
40+
const workspace: any = {pathToJest: 'npm test --'};
41+
const args = [];
42+
createProcess(workspace, args);
43+
44+
expect(spawn.mock.calls[0][0]).toBe('npm');
45+
expect(spawn.mock.calls[0][1]).toEqual(['test', '--']);
46+
});
47+
48+
it('fails to spawn the first quoted arg from workspace.pathToJest', () => {
49+
const workspace: any = {
50+
pathToJest:
51+
'"../build scripts/test" --coverageDirectory="../code coverage"',
52+
};
53+
const args = [];
54+
createProcess(workspace, args);
55+
56+
expect(spawn.mock.calls[0][0]).not.toBe('"../build scripts/test"');
57+
expect(spawn.mock.calls[0][1]).not.toEqual([
58+
'--coverageDirectory="../code coverage"',
59+
]);
60+
});
61+
62+
it('appends args', () => {
63+
const workspace: any = {pathToJest: 'npm test --'};
64+
const args = ['--option', 'value', '--another'];
65+
createProcess(workspace, args);
66+
67+
expect(spawn.mock.calls[0][1]).toEqual(['test', '--', ...args]);
68+
});
69+
70+
it('sets the --config arg to workspace.pathToConfig', () => {
71+
const workspace: any = {
72+
pathToConfig: 'non-standard.jest.js',
73+
pathToJest: 'npm test --',
74+
};
75+
const args = ['--option', 'value'];
76+
createProcess(workspace, args);
77+
78+
expect(spawn.mock.calls[0][1]).toEqual([
79+
'test',
80+
'--',
81+
'--option',
82+
'value',
83+
'--config',
84+
'non-standard.jest.js',
85+
]);
86+
});
87+
88+
it('defines the "CI" environment variable', () => {
89+
const expected = {
90+
...process.env,
91+
CI: 'true',
92+
};
93+
94+
const workspace: any = {pathToJest: ''};
95+
const args = [];
96+
createProcess(workspace, args);
97+
98+
expect(spawn.mock.calls[0][2].env).toEqual(expected);
99+
});
100+
101+
it('sets the current working directory of the child process', () => {
102+
const workspace: any = {
103+
pathToJest: '',
104+
rootPath: 'root directory',
105+
};
106+
const args = [];
107+
createProcess(workspace, args);
108+
109+
expect(spawn.mock.calls[0][2].cwd).toBe(workspace.rootPath);
110+
});
111+
112+
it('should not set the "shell" property when "options" are not provided', () => {
113+
const workspace: any = {pathToJest: ''};
114+
const args = [];
115+
createProcess(workspace, args);
116+
117+
expect(spawn.mock.calls[0][2].shell).not.toBeDefined();
118+
});
119+
120+
it('should set the "shell" property when "options" are provided', () => {
121+
const expected = {};
122+
const workspace: any = {pathToJest: ''};
123+
const args = [];
124+
const options: any = {shell: expected};
125+
createProcess(workspace, args, options);
126+
127+
expect(spawn.mock.calls[0][2].shell).toBe(expected);
128+
});
129+
});

0 commit comments

Comments
 (0)