concurrently 6.0.0 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/bin/concurrently.js +3 -1
- package/bin/concurrently.spec.js +365 -0
- package/package.json +2 -2
- package/src/command-parser/expand-npm-shortcut.spec.js +36 -0
- package/src/command-parser/expand-npm-wildcard.spec.js +58 -0
- package/src/command-parser/strip-quotes.spec.js +20 -0
- package/src/command.js +3 -0
- package/src/command.spec.js +183 -0
- package/src/completion-listener.js +1 -1
- package/src/completion-listener.spec.js +88 -0
- package/src/concurrently.js +1 -0
- package/src/concurrently.spec.js +167 -0
- package/src/defaults.js +1 -1
- package/src/flow-control/input-handler.js +1 -1
- package/src/flow-control/input-handler.spec.js +91 -0
- package/src/flow-control/kill-on-signal.spec.js +79 -0
- package/src/flow-control/kill-others.spec.js +66 -0
- package/src/flow-control/log-error.spec.js +40 -0
- package/src/flow-control/log-exit.spec.js +36 -0
- package/src/flow-control/log-output.spec.js +41 -0
- package/src/flow-control/restart-process.js +1 -0
- package/src/flow-control/restart-process.spec.js +131 -0
- package/src/get-spawn-opts.spec.js +30 -0
- package/src/logger.js +4 -3
- package/src/logger.spec.js +195 -0
- package/src/flow-control/fixtures/fake-command.js +0 -16
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const { createMockInstance } = require('jest-create-mock-instance');
|
|
2
|
+
|
|
3
|
+
const Logger = require('../logger');
|
|
4
|
+
const createFakeCommand = require('./fixtures/fake-command');
|
|
5
|
+
const KillOthers = require('./kill-others');
|
|
6
|
+
|
|
7
|
+
let commands, logger;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
commands = [
|
|
10
|
+
createFakeCommand(),
|
|
11
|
+
createFakeCommand()
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
logger = createMockInstance(Logger);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const createWithConditions = conditions => new KillOthers({
|
|
18
|
+
logger,
|
|
19
|
+
conditions
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns same commands', () => {
|
|
23
|
+
expect(createWithConditions(['foo']).handle(commands)).toBe(commands);
|
|
24
|
+
expect(createWithConditions(['failure']).handle(commands)).toBe(commands);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('does not kill others if condition does not match', () => {
|
|
28
|
+
createWithConditions(['failure']).handle(commands);
|
|
29
|
+
commands[1].killable = true;
|
|
30
|
+
commands[0].close.next({ exitCode: 0 });
|
|
31
|
+
|
|
32
|
+
expect(logger.logGlobalEvent).not.toHaveBeenCalled();
|
|
33
|
+
expect(commands[0].kill).not.toHaveBeenCalled();
|
|
34
|
+
expect(commands[1].kill).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('kills other killable processes on success', () => {
|
|
38
|
+
createWithConditions(['success']).handle(commands);
|
|
39
|
+
commands[1].killable = true;
|
|
40
|
+
commands[0].close.next({ exitCode: 0 });
|
|
41
|
+
|
|
42
|
+
expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
|
|
43
|
+
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGTERM to other processes..');
|
|
44
|
+
expect(commands[0].kill).not.toHaveBeenCalled();
|
|
45
|
+
expect(commands[1].kill).toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('kills other killable processes on failure', () => {
|
|
49
|
+
createWithConditions(['failure']).handle(commands);
|
|
50
|
+
commands[1].killable = true;
|
|
51
|
+
commands[0].close.next({ exitCode: 1 });
|
|
52
|
+
|
|
53
|
+
expect(logger.logGlobalEvent).toHaveBeenCalledTimes(1);
|
|
54
|
+
expect(logger.logGlobalEvent).toHaveBeenCalledWith('Sending SIGTERM to other processes..');
|
|
55
|
+
expect(commands[0].kill).not.toHaveBeenCalled();
|
|
56
|
+
expect(commands[1].kill).toHaveBeenCalled();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('does not try to kill processes already dead', () => {
|
|
60
|
+
createWithConditions(['failure']).handle(commands);
|
|
61
|
+
commands[0].close.next({ exitCode: 1 });
|
|
62
|
+
|
|
63
|
+
expect(logger.logGlobalEvent).not.toHaveBeenCalled();
|
|
64
|
+
expect(commands[0].kill).not.toHaveBeenCalled();
|
|
65
|
+
expect(commands[1].kill).not.toHaveBeenCalled();
|
|
66
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const { createMockInstance } = require('jest-create-mock-instance');
|
|
2
|
+
const Logger = require('../logger');
|
|
3
|
+
const LogError = require('./log-error');
|
|
4
|
+
const createFakeCommand = require('./fixtures/fake-command');
|
|
5
|
+
|
|
6
|
+
let controller, logger, commands;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
commands = [
|
|
9
|
+
createFakeCommand(),
|
|
10
|
+
createFakeCommand(),
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
logger = createMockInstance(Logger);
|
|
14
|
+
controller = new LogError({ logger });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('returns same commands', () => {
|
|
18
|
+
expect(controller.handle(commands)).toBe(commands);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('logs the error event of each command', () => {
|
|
22
|
+
controller.handle(commands);
|
|
23
|
+
commands[0].error.next('error from command 0');
|
|
24
|
+
|
|
25
|
+
const error = new Error('some error message');
|
|
26
|
+
commands[1].error.next(error);
|
|
27
|
+
|
|
28
|
+
expect(logger.logCommandEvent).toHaveBeenCalledTimes(4);
|
|
29
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(
|
|
30
|
+
`Error occurred when executing command: ${commands[0].command}`,
|
|
31
|
+
commands[0]
|
|
32
|
+
);
|
|
33
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith('error from command 0', commands[0]);
|
|
34
|
+
|
|
35
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(
|
|
36
|
+
`Error occurred when executing command: ${commands[1].command}`,
|
|
37
|
+
commands[1]
|
|
38
|
+
);
|
|
39
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(error.stack, commands[1]);
|
|
40
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { createMockInstance } = require('jest-create-mock-instance');
|
|
2
|
+
const Logger = require('../logger');
|
|
3
|
+
const LogExit = require('./log-exit');
|
|
4
|
+
const createFakeCommand = require('./fixtures/fake-command');
|
|
5
|
+
|
|
6
|
+
let controller, logger, commands;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
commands = [
|
|
9
|
+
createFakeCommand(),
|
|
10
|
+
createFakeCommand(),
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
logger = createMockInstance(Logger);
|
|
14
|
+
controller = new LogExit({ logger });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('returns same commands', () => {
|
|
18
|
+
expect(controller.handle(commands)).toBe(commands);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('logs the close event of each command', () => {
|
|
22
|
+
controller.handle(commands);
|
|
23
|
+
|
|
24
|
+
commands[0].close.next({ exitCode: 0 });
|
|
25
|
+
commands[1].close.next({ exitCode: 'SIGTERM' });
|
|
26
|
+
|
|
27
|
+
expect(logger.logCommandEvent).toHaveBeenCalledTimes(2);
|
|
28
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(
|
|
29
|
+
`${commands[0].command} exited with code 0`,
|
|
30
|
+
commands[0]
|
|
31
|
+
);
|
|
32
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(
|
|
33
|
+
`${commands[1].command} exited with code SIGTERM`,
|
|
34
|
+
commands[1]
|
|
35
|
+
);
|
|
36
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { createMockInstance } = require('jest-create-mock-instance');
|
|
2
|
+
const Logger = require('../logger');
|
|
3
|
+
const LogOutput = require('./log-output');
|
|
4
|
+
const createFakeCommand = require('./fixtures/fake-command');
|
|
5
|
+
|
|
6
|
+
let controller, logger, commands;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
commands = [
|
|
9
|
+
createFakeCommand(),
|
|
10
|
+
createFakeCommand(),
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
logger = createMockInstance(Logger);
|
|
14
|
+
controller = new LogOutput({ logger });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('returns same commands', () => {
|
|
18
|
+
expect(controller.handle(commands)).toBe(commands);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('logs the stdout of each command', () => {
|
|
22
|
+
controller.handle(commands);
|
|
23
|
+
|
|
24
|
+
commands[0].stdout.next(Buffer.from('foo'));
|
|
25
|
+
commands[1].stdout.next(Buffer.from('bar'));
|
|
26
|
+
|
|
27
|
+
expect(logger.logCommandText).toHaveBeenCalledTimes(2);
|
|
28
|
+
expect(logger.logCommandText).toHaveBeenCalledWith('foo', commands[0]);
|
|
29
|
+
expect(logger.logCommandText).toHaveBeenCalledWith('bar', commands[1]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('logs the stderr of each command', () => {
|
|
33
|
+
controller.handle(commands);
|
|
34
|
+
|
|
35
|
+
commands[0].stderr.next(Buffer.from('foo'));
|
|
36
|
+
commands[1].stderr.next(Buffer.from('bar'));
|
|
37
|
+
|
|
38
|
+
expect(logger.logCommandText).toHaveBeenCalledTimes(2);
|
|
39
|
+
expect(logger.logCommandText).toHaveBeenCalledWith('foo', commands[0]);
|
|
40
|
+
expect(logger.logCommandText).toHaveBeenCalledWith('bar', commands[1]);
|
|
41
|
+
});
|
|
@@ -7,6 +7,7 @@ module.exports = class RestartProcess {
|
|
|
7
7
|
constructor({ delay, tries, logger, scheduler }) {
|
|
8
8
|
this.delay = +delay || defaults.restartDelay;
|
|
9
9
|
this.tries = +tries || defaults.restartTries;
|
|
10
|
+
this.tries = this.tries < 0 ? Infinity : this.tries;
|
|
10
11
|
this.logger = logger;
|
|
11
12
|
this.scheduler = scheduler;
|
|
12
13
|
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const { createMockInstance } = require('jest-create-mock-instance');
|
|
2
|
+
const { TestScheduler } = require('rxjs/testing');
|
|
3
|
+
|
|
4
|
+
const Logger = require('../logger');
|
|
5
|
+
const createFakeCommand = require('./fixtures/fake-command');
|
|
6
|
+
const RestartProcess = require('./restart-process');
|
|
7
|
+
|
|
8
|
+
let commands, controller, logger, scheduler;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
commands = [
|
|
11
|
+
createFakeCommand(),
|
|
12
|
+
createFakeCommand()
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
logger = createMockInstance(Logger);
|
|
16
|
+
scheduler = new TestScheduler();
|
|
17
|
+
controller = new RestartProcess({
|
|
18
|
+
logger,
|
|
19
|
+
scheduler,
|
|
20
|
+
delay: 100,
|
|
21
|
+
tries: 2
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('does not restart processes that complete with success', () => {
|
|
26
|
+
controller.handle(commands);
|
|
27
|
+
|
|
28
|
+
commands[0].close.next({ exitCode: 0 });
|
|
29
|
+
commands[1].close.next({ exitCode: 0 });
|
|
30
|
+
|
|
31
|
+
scheduler.flush();
|
|
32
|
+
|
|
33
|
+
expect(commands[0].start).toHaveBeenCalledTimes(0);
|
|
34
|
+
expect(commands[1].start).toHaveBeenCalledTimes(0);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('restarts processes that fail after delay has passed', () => {
|
|
38
|
+
controller.handle(commands);
|
|
39
|
+
|
|
40
|
+
commands[0].close.next({ exitCode: 1 });
|
|
41
|
+
commands[1].close.next({ exitCode: 0 });
|
|
42
|
+
|
|
43
|
+
scheduler.flush();
|
|
44
|
+
|
|
45
|
+
expect(logger.logCommandEvent).toHaveBeenCalledTimes(1);
|
|
46
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(
|
|
47
|
+
`${commands[0].command} restarted`,
|
|
48
|
+
commands[0]
|
|
49
|
+
);
|
|
50
|
+
expect(commands[0].start).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(commands[1].start).not.toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('restarts processes up to tries', () => {
|
|
55
|
+
controller.handle(commands);
|
|
56
|
+
|
|
57
|
+
commands[0].close.next({ exitCode: 1 });
|
|
58
|
+
commands[0].close.next({ exitCode: 'SIGTERM' });
|
|
59
|
+
commands[0].close.next({ exitCode: 'SIGTERM' });
|
|
60
|
+
commands[1].close.next({ exitCode: 0 });
|
|
61
|
+
|
|
62
|
+
scheduler.flush();
|
|
63
|
+
|
|
64
|
+
expect(logger.logCommandEvent).toHaveBeenCalledTimes(2);
|
|
65
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(
|
|
66
|
+
`${commands[0].command} restarted`,
|
|
67
|
+
commands[0]
|
|
68
|
+
);
|
|
69
|
+
expect(commands[0].start).toHaveBeenCalledTimes(2);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it.todo('restart processes forever, if tries is negative');
|
|
73
|
+
|
|
74
|
+
it('restarts processes until they succeed', () => {
|
|
75
|
+
controller.handle(commands);
|
|
76
|
+
|
|
77
|
+
commands[0].close.next({ exitCode: 1 });
|
|
78
|
+
commands[0].close.next({ exitCode: 0 });
|
|
79
|
+
commands[1].close.next({ exitCode: 0 });
|
|
80
|
+
|
|
81
|
+
scheduler.flush();
|
|
82
|
+
|
|
83
|
+
expect(logger.logCommandEvent).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(logger.logCommandEvent).toHaveBeenCalledWith(
|
|
85
|
+
`${commands[0].command} restarted`,
|
|
86
|
+
commands[0]
|
|
87
|
+
);
|
|
88
|
+
expect(commands[0].start).toHaveBeenCalledTimes(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('returned commands', () => {
|
|
92
|
+
it('are the same if 0 tries are to be attempted', () => {
|
|
93
|
+
controller = new RestartProcess({ logger, scheduler });
|
|
94
|
+
expect(controller.handle(commands)).toBe(commands);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('are not the same, but with same length if 1+ tries are to be attempted', () => {
|
|
98
|
+
const newCommands = controller.handle(commands);
|
|
99
|
+
expect(newCommands).not.toBe(commands);
|
|
100
|
+
expect(newCommands).toHaveLength(commands.length);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('skip close events followed by restarts', () => {
|
|
104
|
+
const newCommands = controller.handle(commands);
|
|
105
|
+
|
|
106
|
+
const callback = jest.fn();
|
|
107
|
+
newCommands[0].close.subscribe(callback);
|
|
108
|
+
newCommands[1].close.subscribe(callback);
|
|
109
|
+
|
|
110
|
+
commands[0].close.next({ exitCode: 1 });
|
|
111
|
+
commands[0].close.next({ exitCode: 1 });
|
|
112
|
+
commands[0].close.next({ exitCode: 1 });
|
|
113
|
+
commands[1].close.next({ exitCode: 1 });
|
|
114
|
+
commands[1].close.next({ exitCode: 0 });
|
|
115
|
+
|
|
116
|
+
scheduler.flush();
|
|
117
|
+
|
|
118
|
+
// 1 failure from commands[0], 1 success from commands[1]
|
|
119
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('keep non-close streams from original commands', () => {
|
|
123
|
+
const newCommands = controller.handle(commands);
|
|
124
|
+
newCommands.forEach((newCommand, i) => {
|
|
125
|
+
expect(newCommand.close).not.toBe(commands[i].close);
|
|
126
|
+
expect(newCommand.error).toBe(commands[i].error);
|
|
127
|
+
expect(newCommand.stdout).toBe(commands[i].stdout);
|
|
128
|
+
expect(newCommand.stderr).toBe(commands[i].stderr);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const getSpawnOpts = require('./get-spawn-opts');
|
|
2
|
+
|
|
3
|
+
it('sets detached mode to false for Windows platform', () => {
|
|
4
|
+
expect(getSpawnOpts({ process: { platform: 'win32', cwd: jest.fn() } }).detached).toBe(false);
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
it('sets stdio to inherit when raw', () => {
|
|
8
|
+
expect(getSpawnOpts({ raw: true }).stdio).toBe('inherit');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('merges FORCE_COLOR into env vars if color supported', () => {
|
|
12
|
+
const process = { env: { foo: 'bar' }, cwd: jest.fn() };
|
|
13
|
+
expect(getSpawnOpts({ process, colorSupport: false }).env).toEqual(process.env);
|
|
14
|
+
expect(getSpawnOpts({ process, colorSupport: { level: 1 } }).env).toEqual({
|
|
15
|
+
FORCE_COLOR: 1,
|
|
16
|
+
foo: 'bar'
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('sets default cwd to process.cwd()', () => {
|
|
21
|
+
const process = { cwd: jest.fn().mockReturnValue('process-cwd') };
|
|
22
|
+
expect(getSpawnOpts({
|
|
23
|
+
process,
|
|
24
|
+
}).cwd).toBe('process-cwd');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('overrides default cwd', () => {
|
|
28
|
+
const cwd = 'foobar';
|
|
29
|
+
expect(getSpawnOpts({ cwd }).cwd).toBe(cwd);
|
|
30
|
+
});
|
package/src/logger.js
CHANGED
|
@@ -61,7 +61,8 @@ module.exports = class Logger {
|
|
|
61
61
|
if (command.prefixColor && command.prefixColor.startsWith('#')) {
|
|
62
62
|
color = chalk.hex(command.prefixColor);
|
|
63
63
|
} else {
|
|
64
|
-
|
|
64
|
+
const defaultColor = _.get(chalk, defaults.prefixColors, chalk.reset);
|
|
65
|
+
color = _.get(chalk, command.prefixColor, defaultColor);
|
|
65
66
|
}
|
|
66
67
|
return color(text);
|
|
67
68
|
}
|
|
@@ -71,7 +72,7 @@ module.exports = class Logger {
|
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
this.logCommandText(chalk.
|
|
75
|
+
this.logCommandText(chalk.reset(text) + '\n', command);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
logCommandText(text, command) {
|
|
@@ -84,7 +85,7 @@ module.exports = class Logger {
|
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
this.log(chalk.
|
|
88
|
+
this.log(chalk.reset('-->') + ' ', chalk.reset(text) + '\n');
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
log(prefix, text) {
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
const { Writable } = require('stream');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const { createMockInstance } = require('jest-create-mock-instance');
|
|
4
|
+
const Logger = require('./logger');
|
|
5
|
+
|
|
6
|
+
let outputStream;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
outputStream = createMockInstance(Writable);
|
|
9
|
+
// Force chalk to use colours, otherwise tests may pass when they were supposed to be failing.
|
|
10
|
+
chalk.level = 3;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const createLogger = options => {
|
|
14
|
+
const logger = new Logger(Object.assign({ outputStream }, options));
|
|
15
|
+
jest.spyOn(logger, 'log');
|
|
16
|
+
return logger;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
describe('#log()', () => {
|
|
20
|
+
it('writes prefix + text to the output stream', () => {
|
|
21
|
+
const logger = new Logger({ outputStream });
|
|
22
|
+
logger.log('foo', 'bar');
|
|
23
|
+
|
|
24
|
+
expect(outputStream.write).toHaveBeenCalledTimes(2);
|
|
25
|
+
expect(outputStream.write).toHaveBeenCalledWith('foo');
|
|
26
|
+
expect(outputStream.write).toHaveBeenCalledWith('bar');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('writes multiple lines of text with prefix on each', () => {
|
|
30
|
+
const logger = new Logger({ outputStream });
|
|
31
|
+
logger.log('foo', 'bar\nbaz\n');
|
|
32
|
+
|
|
33
|
+
expect(outputStream.write).toHaveBeenCalledTimes(2);
|
|
34
|
+
expect(outputStream.write).toHaveBeenCalledWith('foo');
|
|
35
|
+
expect(outputStream.write).toHaveBeenCalledWith('bar\nfoobaz\n');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('does not prepend prefix if last call did not finish with a LF', () => {
|
|
39
|
+
const logger = new Logger({ outputStream });
|
|
40
|
+
logger.log('foo', 'bar');
|
|
41
|
+
outputStream.write.mockClear();
|
|
42
|
+
logger.log('foo', 'baz');
|
|
43
|
+
|
|
44
|
+
expect(outputStream.write).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect(outputStream.write).toHaveBeenCalledWith('baz');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('does not prepend prefix or handle text if logger is in raw mode', () => {
|
|
49
|
+
const logger = new Logger({ outputStream, raw: true });
|
|
50
|
+
logger.log('foo', 'bar\nbaz\n');
|
|
51
|
+
|
|
52
|
+
expect(outputStream.write).toHaveBeenCalledTimes(1);
|
|
53
|
+
expect(outputStream.write).toHaveBeenCalledWith('bar\nbaz\n');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('#logGlobalEvent()', () => {
|
|
58
|
+
it('does nothing if in raw mode', () => {
|
|
59
|
+
const logger = createLogger({ raw: true });
|
|
60
|
+
logger.logGlobalEvent('foo');
|
|
61
|
+
|
|
62
|
+
expect(logger.log).not.toHaveBeenCalled();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('logs in gray dim style with arrow prefix', () => {
|
|
66
|
+
const logger = createLogger();
|
|
67
|
+
logger.logGlobalEvent('foo');
|
|
68
|
+
|
|
69
|
+
expect(logger.log).toHaveBeenCalledWith(
|
|
70
|
+
chalk.reset('-->') + ' ',
|
|
71
|
+
chalk.reset('foo') + '\n'
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('#logCommandText()', () => {
|
|
77
|
+
it('logs with name if no prefixFormat is set', () => {
|
|
78
|
+
const logger = createLogger();
|
|
79
|
+
logger.logCommandText('foo', { name: 'bla' });
|
|
80
|
+
|
|
81
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[bla]') + ' ', 'foo');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('logs with index if no prefixFormat is set, and command has no name', () => {
|
|
85
|
+
const logger = createLogger();
|
|
86
|
+
logger.logCommandText('foo', { index: 2 });
|
|
87
|
+
|
|
88
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[2]') + ' ', 'foo');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('logs with prefixFormat set to pid', () => {
|
|
92
|
+
const logger = createLogger({ prefixFormat: 'pid' });
|
|
93
|
+
logger.logCommandText('foo', {
|
|
94
|
+
pid: 123,
|
|
95
|
+
info: {}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[123]') + ' ', 'foo');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('logs with prefixFormat set to name', () => {
|
|
102
|
+
const logger = createLogger({ prefixFormat: 'name' });
|
|
103
|
+
logger.logCommandText('foo', { name: 'bar' });
|
|
104
|
+
|
|
105
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[bar]') + ' ', 'foo');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('logs with prefixFormat set to index', () => {
|
|
109
|
+
const logger = createLogger({ prefixFormat: 'index' });
|
|
110
|
+
logger.logCommandText('foo', { index: 3 });
|
|
111
|
+
|
|
112
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[3]') + ' ', 'foo');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('logs with prefixFormat set to time (with timestampFormat)', () => {
|
|
116
|
+
const logger = createLogger({ prefixFormat: 'time', timestampFormat: 'yyyy' });
|
|
117
|
+
logger.logCommandText('foo', {});
|
|
118
|
+
|
|
119
|
+
const year = new Date().getFullYear();
|
|
120
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset(`[${year}]`) + ' ', 'foo');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('logs with templated prefixFormat', () => {
|
|
124
|
+
const logger = createLogger({ prefixFormat: '{index}-{name}' });
|
|
125
|
+
logger.logCommandText('foo', { index: 0, name: 'bar' });
|
|
126
|
+
|
|
127
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('0-bar') + ' ', 'foo');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('does not strip spaces from beginning or end of prefixFormat', () => {
|
|
131
|
+
const logger = createLogger({ prefixFormat: ' {index}-{name} ' });
|
|
132
|
+
logger.logCommandText('foo', { index: 0, name: 'bar' });
|
|
133
|
+
|
|
134
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset(' 0-bar ') + ' ', 'foo');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('logs with no prefix', () => {
|
|
138
|
+
const logger = createLogger({ prefixFormat: 'none' });
|
|
139
|
+
logger.logCommandText('foo', { command: 'echo foo' });
|
|
140
|
+
|
|
141
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset(''), 'foo');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('logs prefix using command line itself', () => {
|
|
145
|
+
const logger = createLogger({ prefixFormat: 'command' });
|
|
146
|
+
logger.logCommandText('foo', { command: 'echo foo' });
|
|
147
|
+
|
|
148
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[echo foo]') + ' ', 'foo');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('logs prefix using command line itself, capped at prefixLength bytes', () => {
|
|
152
|
+
const logger = createLogger({ prefixFormat: 'command', prefixLength: 6 });
|
|
153
|
+
logger.logCommandText('foo', { command: 'echo foo' });
|
|
154
|
+
|
|
155
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[ec..oo]') + ' ', 'foo');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('logs prefix using prefixColor from command', () => {
|
|
159
|
+
const logger = createLogger();
|
|
160
|
+
logger.logCommandText('foo', { prefixColor: 'blue', index: 1 });
|
|
161
|
+
|
|
162
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.blue('[1]') + ' ', 'foo');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('logs prefix in gray dim if prefixColor from command does not exist', () => {
|
|
166
|
+
const logger = createLogger();
|
|
167
|
+
logger.logCommandText('foo', { prefixColor: 'blue.fake', index: 1 });
|
|
168
|
+
|
|
169
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[1]') + ' ', 'foo');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('logs prefix using prefixColor from command if prefixColor is a hex value', () => {
|
|
173
|
+
const logger = createLogger();
|
|
174
|
+
const prefixColor = '#32bd8a';
|
|
175
|
+
logger.logCommandText('foo', {prefixColor, index: 1});
|
|
176
|
+
|
|
177
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.hex(prefixColor)('[1]') + ' ', 'foo');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('#logCommandEvent()', () => {
|
|
182
|
+
it('does nothing if in raw mode', () => {
|
|
183
|
+
const logger = createLogger({ raw: true });
|
|
184
|
+
logger.logCommandEvent('foo');
|
|
185
|
+
|
|
186
|
+
expect(logger.log).not.toHaveBeenCalled();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('logs text in gray dim', () => {
|
|
190
|
+
const logger = createLogger();
|
|
191
|
+
logger.logCommandEvent('foo', { index: 1 });
|
|
192
|
+
|
|
193
|
+
expect(logger.log).toHaveBeenCalledWith(chalk.reset('[1]') + ' ', chalk.reset('foo') + '\n');
|
|
194
|
+
});
|
|
195
|
+
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const { createMockInstance } = require('jest-create-mock-instance');
|
|
2
|
-
const { Writable } = require('stream');
|
|
3
|
-
const { Subject } = require('rxjs');
|
|
4
|
-
|
|
5
|
-
module.exports = (name = 'foo', command = 'echo foo', index = 0) => ({
|
|
6
|
-
index,
|
|
7
|
-
name,
|
|
8
|
-
command,
|
|
9
|
-
close: new Subject(),
|
|
10
|
-
error: new Subject(),
|
|
11
|
-
stderr: new Subject(),
|
|
12
|
-
stdout: new Subject(),
|
|
13
|
-
stdin: createMockInstance(Writable),
|
|
14
|
-
start: jest.fn(),
|
|
15
|
-
kill: jest.fn()
|
|
16
|
-
});
|