concurrently 10.0.0 → 10.0.1

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.
Files changed (63) hide show
  1. package/dist/lib/flow-control/flow-controller.d.ts +13 -0
  2. package/dist/tsconfig.tsbuildinfo +1 -1
  3. package/package.json +11 -14
  4. package/dist/bin/index.spec.js +0 -368
  5. package/dist/bin/normalize-cli-command.spec.js +0 -36
  6. package/dist/lib/__fixtures__/create-mock-instance.d.ts +0 -2
  7. package/dist/lib/__fixtures__/create-mock-instance.js +0 -5
  8. package/dist/lib/__fixtures__/fake-command.d.ts +0 -6
  9. package/dist/lib/__fixtures__/fake-command.js +0 -37
  10. package/dist/lib/assert.spec.js +0 -41
  11. package/dist/lib/command-parser/expand-arguments.spec.d.ts +0 -1
  12. package/dist/lib/command-parser/expand-arguments.spec.js +0 -57
  13. package/dist/lib/command-parser/expand-shortcut.spec.d.ts +0 -1
  14. package/dist/lib/command-parser/expand-shortcut.spec.js +0 -36
  15. package/dist/lib/command-parser/expand-wildcard.spec.d.ts +0 -1
  16. package/dist/lib/command-parser/expand-wildcard.spec.js +0 -288
  17. package/dist/lib/command.spec.d.ts +0 -1
  18. package/dist/lib/command.spec.js +0 -369
  19. package/dist/lib/completion-listener.spec.d.ts +0 -1
  20. package/dist/lib/completion-listener.spec.js +0 -229
  21. package/dist/lib/concurrently.spec.d.ts +0 -1
  22. package/dist/lib/concurrently.spec.js +0 -320
  23. package/dist/lib/date-format.spec.d.ts +0 -1
  24. package/dist/lib/date-format.spec.js +0 -480
  25. package/dist/lib/flow-control/input-handler.spec.d.ts +0 -1
  26. package/dist/lib/flow-control/input-handler.spec.js +0 -116
  27. package/dist/lib/flow-control/kill-on-signal.spec.d.ts +0 -1
  28. package/dist/lib/flow-control/kill-on-signal.spec.js +0 -63
  29. package/dist/lib/flow-control/kill-others.spec.d.ts +0 -1
  30. package/dist/lib/flow-control/kill-others.spec.js +0 -98
  31. package/dist/lib/flow-control/log-error.spec.d.ts +0 -1
  32. package/dist/lib/flow-control/log-error.spec.js +0 -33
  33. package/dist/lib/flow-control/log-exit.spec.d.ts +0 -1
  34. package/dist/lib/flow-control/log-exit.spec.js +0 -24
  35. package/dist/lib/flow-control/log-output.spec.d.ts +0 -1
  36. package/dist/lib/flow-control/log-output.spec.js +0 -33
  37. package/dist/lib/flow-control/log-timings.spec.d.ts +0 -1
  38. package/dist/lib/flow-control/log-timings.spec.js +0 -89
  39. package/dist/lib/flow-control/logger-padding.spec.d.ts +0 -1
  40. package/dist/lib/flow-control/logger-padding.spec.js +0 -60
  41. package/dist/lib/flow-control/output-error-handler.spec.d.ts +0 -1
  42. package/dist/lib/flow-control/output-error-handler.spec.js +0 -41
  43. package/dist/lib/flow-control/restart-process.spec.d.ts +0 -1
  44. package/dist/lib/flow-control/restart-process.spec.js +0 -127
  45. package/dist/lib/flow-control/teardown.spec.d.ts +0 -1
  46. package/dist/lib/flow-control/teardown.spec.js +0 -93
  47. package/dist/lib/jsonc.spec.d.ts +0 -1
  48. package/dist/lib/jsonc.spec.js +0 -73
  49. package/dist/lib/logger.spec.d.ts +0 -1
  50. package/dist/lib/logger.spec.js +0 -507
  51. package/dist/lib/observables.spec.d.ts +0 -1
  52. package/dist/lib/observables.spec.js +0 -29
  53. package/dist/lib/output-writer.spec.d.ts +0 -1
  54. package/dist/lib/output-writer.spec.js +0 -96
  55. package/dist/lib/prefix-color-selector.spec.d.ts +0 -1
  56. package/dist/lib/prefix-color-selector.spec.js +0 -159
  57. package/dist/lib/spawn.spec.d.ts +0 -1
  58. package/dist/lib/spawn.spec.js +0 -100
  59. package/dist/lib/utils.spec.d.ts +0 -1
  60. package/dist/lib/utils.spec.js +0 -58
  61. /package/dist/bin/{index.spec.d.ts → bin-options.d.ts} +0 -0
  62. /package/dist/bin/{normalize-cli-command.spec.d.ts → bin-options.js} +0 -0
  63. /package/dist/lib/{assert.spec.d.ts → flow-control/flow-controller.js} +0 -0
@@ -1,369 +0,0 @@
1
- import { Buffer } from 'node:buffer';
2
- import { EventEmitter } from 'node:events';
3
- import { Readable, Writable } from 'node:stream';
4
- import { subscribeSpyTo } from '@hirez_io/observer-spy';
5
- import Rx from 'rxjs';
6
- import { beforeEach, describe, expect, it, vi } from 'vitest';
7
- import { Command, } from './command.js';
8
- let process;
9
- let sendMessage;
10
- let spawn;
11
- let killProcess;
12
- const IPC_FD = 3;
13
- beforeEach(() => {
14
- sendMessage = vi.fn();
15
- process = new (class extends EventEmitter {
16
- pid = 1;
17
- send = sendMessage;
18
- stdout = new Readable({
19
- read() {
20
- // do nothing
21
- },
22
- });
23
- stderr = new Readable({
24
- read() {
25
- // do nothing
26
- },
27
- });
28
- stdin = new Writable({
29
- write() {
30
- // do nothing
31
- },
32
- });
33
- })();
34
- spawn = vi.fn().mockReturnValue(process);
35
- killProcess = vi.fn();
36
- });
37
- const createCommand = (overrides, spawnOpts = {}) => {
38
- const command = new Command({ index: 0, name: '', command: 'echo foo', ...overrides }, spawnOpts, spawn, killProcess);
39
- let error;
40
- let close;
41
- const timer = subscribeSpyTo(command.timer);
42
- const finished = subscribeSpyTo(new Rx.Observable((observer) => {
43
- // First event in both subjects means command has finished
44
- command.error.subscribe({
45
- next: (value) => {
46
- error = value;
47
- observer.complete();
48
- },
49
- });
50
- command.close.subscribe({
51
- next: (value) => {
52
- close = value;
53
- observer.complete();
54
- },
55
- });
56
- }));
57
- const values = async () => {
58
- await finished.onComplete();
59
- return { error, close, timer: timer.getValues() };
60
- };
61
- return { command, values };
62
- };
63
- it('has stopped state by default', () => {
64
- const { command } = createCommand();
65
- expect(command.state).toBe('stopped');
66
- });
67
- describe('#start()', () => {
68
- it('spawns process with given command and options', () => {
69
- const { command } = createCommand({}, { detached: true });
70
- command.start();
71
- expect(spawn).toHaveBeenCalledExactlyOnceWith(command.command, { detached: true });
72
- });
73
- it('sets stdin, process and PID', () => {
74
- const { command } = createCommand();
75
- command.start();
76
- expect(command.process).toBe(process);
77
- expect(command.pid).toBe(process.pid);
78
- expect(command.stdin).toBe(process.stdin);
79
- });
80
- it('handles process with no stdin', () => {
81
- process.stdin = null;
82
- const { command } = createCommand();
83
- command.start();
84
- expect(command.stdin).toBe(undefined);
85
- });
86
- it('changes state to started', () => {
87
- const { command } = createCommand();
88
- const spy = subscribeSpyTo(command.stateChange);
89
- command.start();
90
- expect(command.state).toBe('started');
91
- expect(spy.getFirstValue()).toBe('started');
92
- });
93
- describe('on errors', () => {
94
- it('changes state to errored', () => {
95
- const { command } = createCommand();
96
- command.start();
97
- const spy = subscribeSpyTo(command.stateChange);
98
- process.emit('error', 'foo');
99
- expect(command.state).toBe('errored');
100
- expect(spy.getFirstValue()).toBe('errored');
101
- });
102
- it('shares to the error stream', async () => {
103
- const { command, values } = createCommand();
104
- command.start();
105
- process.emit('error', 'foo');
106
- const { error } = await values();
107
- expect(error).toBe('foo');
108
- expect(command.process).toBeUndefined();
109
- });
110
- it('shares start and error timing events to the timing stream', async () => {
111
- const { command, values } = createCommand();
112
- const startDate = new Date();
113
- const endDate = new Date(startDate.getTime() + 1000);
114
- vi.spyOn(Date, 'now')
115
- .mockReturnValueOnce(startDate.getTime())
116
- .mockReturnValueOnce(endDate.getTime());
117
- command.start();
118
- process.emit('error', 0, null);
119
- const { timer } = await values();
120
- expect(timer[0]).toEqual({ startDate, endDate: undefined });
121
- expect(timer[1]).toEqual({ startDate, endDate });
122
- });
123
- });
124
- describe('on close', () => {
125
- it('changes state to exited', () => {
126
- const { command } = createCommand();
127
- command.start();
128
- const spy = subscribeSpyTo(command.stateChange);
129
- process.emit('close', 0, null);
130
- expect(command.state).toBe('exited');
131
- expect(spy.getFirstValue()).toBe('exited');
132
- });
133
- it('does not change state if there was an error', () => {
134
- const { command } = createCommand();
135
- command.start();
136
- process.emit('error', 'foo');
137
- const spy = subscribeSpyTo(command.stateChange);
138
- process.emit('close', 0, null);
139
- expect(command.state).toBe('errored');
140
- expect(spy.getValuesLength()).toBe(0);
141
- });
142
- it('shares start and close timing events to the timing stream', async () => {
143
- const { command, values } = createCommand();
144
- const startDate = new Date();
145
- const endDate = new Date(startDate.getTime() + 1000);
146
- vi.spyOn(Date, 'now')
147
- .mockReturnValueOnce(startDate.getTime())
148
- .mockReturnValueOnce(endDate.getTime());
149
- command.start();
150
- process.emit('close', 0, null);
151
- const { timer } = await values();
152
- expect(timer[0]).toEqual({ startDate, endDate: undefined });
153
- expect(timer[1]).toEqual({ startDate, endDate });
154
- });
155
- it('shares to the close stream with exit code', async () => {
156
- const { command, values } = createCommand();
157
- command.start();
158
- process.emit('close', 0, null);
159
- const { close } = await values();
160
- expect(close).toMatchObject({ exitCode: 0, killed: false });
161
- expect(command.process).toBeUndefined();
162
- });
163
- it('shares to the close stream with signal', async () => {
164
- const { command, values } = createCommand();
165
- command.start();
166
- process.emit('close', null, 'SIGKILL');
167
- const { close } = await values();
168
- expect(close).toMatchObject({ exitCode: 'SIGKILL', killed: false });
169
- });
170
- it('shares to the close stream with timing information', async () => {
171
- const { command, values } = createCommand();
172
- const startDate = new Date();
173
- const endDate = new Date(startDate.getTime() + 1000);
174
- vi.spyOn(Date, 'now')
175
- .mockReturnValueOnce(startDate.getTime())
176
- .mockReturnValueOnce(endDate.getTime());
177
- vi.spyOn(globalThis.process, 'hrtime')
178
- .mockReturnValueOnce([0, 0])
179
- .mockReturnValueOnce([1, 1e8]);
180
- command.start();
181
- process.emit('close', null, 'SIGKILL');
182
- const { close } = await values();
183
- expect(close.timings).toStrictEqual({
184
- startDate,
185
- endDate,
186
- durationSeconds: 1.1,
187
- });
188
- });
189
- it('shares to the close stream with command info', async () => {
190
- const commandInfo = {
191
- command: 'cmd',
192
- name: 'name',
193
- prefixColor: 'green',
194
- env: { VAR: 'yes' },
195
- };
196
- const { command, values } = createCommand(commandInfo);
197
- command.start();
198
- process.emit('close', 0, null);
199
- const { close } = await values();
200
- expect(close.command).toEqual(expect.objectContaining(commandInfo));
201
- expect(close.killed).toBe(false);
202
- });
203
- });
204
- it('shares stdout to the stdout stream', async () => {
205
- const { command } = createCommand();
206
- const stdout = Rx.firstValueFrom(command.stdout);
207
- command.start();
208
- process.stdout?.emit('data', Buffer.from('hello'));
209
- expect((await stdout).toString()).toBe('hello');
210
- });
211
- it('shares stderr to the stdout stream', async () => {
212
- const { command } = createCommand();
213
- const stderr = Rx.firstValueFrom(command.stderr);
214
- command.start();
215
- process.stderr?.emit('data', Buffer.from('dang'));
216
- expect((await stderr).toString()).toBe('dang');
217
- });
218
- describe('on incoming messages', () => {
219
- it('does not share to the incoming messages stream, if IPC is disabled', () => {
220
- const { command } = createCommand();
221
- const spy = subscribeSpyTo(command.messages.incoming);
222
- command.start();
223
- process.emit('message', {});
224
- expect(spy.getValuesLength()).toBe(0);
225
- });
226
- it('shares to the incoming messages stream, if IPC is enabled', () => {
227
- const { command } = createCommand({ ipc: IPC_FD });
228
- const spy = subscribeSpyTo(command.messages.incoming);
229
- command.start();
230
- const message1 = {};
231
- process.emit('message', message1, undefined);
232
- const message2 = {};
233
- const handle = {};
234
- process.emit('message', message2, handle);
235
- expect(spy.getValuesLength()).toBe(2);
236
- expect(spy.getValueAt(0)).toEqual({ message: message1, handle: undefined });
237
- expect(spy.getValueAt(1)).toEqual({ message: message2, handle });
238
- });
239
- });
240
- describe('on outgoing messages', () => {
241
- it('calls onSent with an error if the process does not have IPC enabled', () => {
242
- const { command } = createCommand({ ipc: IPC_FD });
243
- command.start();
244
- Object.assign(process, {
245
- // The TS types don't assume `send` can be undefined,
246
- // despite the Node docs saying so
247
- send: undefined,
248
- });
249
- const onSent = vi.fn();
250
- command.messages.outgoing.next({ message: {}, onSent });
251
- expect(onSent).toHaveBeenCalledWith(expect.any(Error));
252
- });
253
- it('sends the message to the process', () => {
254
- const { command } = createCommand({ ipc: IPC_FD });
255
- command.start();
256
- const message1 = {};
257
- command.messages.outgoing.next({ message: message1, onSent() { } });
258
- const message2 = {};
259
- const handle = {};
260
- command.messages.outgoing.next({ message: message2, handle, onSent() { } });
261
- const message3 = {};
262
- const options = {};
263
- command.messages.outgoing.next({ message: message3, options, onSent() { } });
264
- expect(process.send).toHaveBeenCalledTimes(3);
265
- expect(process.send).toHaveBeenNthCalledWith(1, message1, undefined, undefined, expect.any(Function));
266
- expect(process.send).toHaveBeenNthCalledWith(2, message2, handle, undefined, expect.any(Function));
267
- expect(process.send).toHaveBeenNthCalledWith(3, message3, undefined, options, expect.any(Function));
268
- });
269
- it('sends the message to the process, if it starts late', () => {
270
- const { command } = createCommand({ ipc: IPC_FD });
271
- command.messages.outgoing.next({ message: {}, onSent() { } });
272
- expect(process.send).not.toHaveBeenCalled();
273
- command.start();
274
- expect(process.send).toHaveBeenCalled();
275
- });
276
- it('calls onSent with the result of sending the message', () => {
277
- const { command } = createCommand({ ipc: IPC_FD });
278
- command.start();
279
- const onSent = vi.fn();
280
- command.messages.outgoing.next({ message: {}, onSent });
281
- expect(onSent).not.toHaveBeenCalled();
282
- sendMessage.mock.calls[0][3]();
283
- expect(onSent).toHaveBeenCalledWith(undefined);
284
- const error = new Error('test');
285
- sendMessage.mock.calls[0][3](error);
286
- expect(onSent).toHaveBeenCalledWith(error);
287
- });
288
- });
289
- });
290
- describe('#send()', () => {
291
- it('throws if IPC is not set up', () => {
292
- const { command } = createCommand();
293
- const fn = () => command.send({});
294
- expect(fn).toThrow();
295
- });
296
- it('pushes the message on the outgoing messages stream', () => {
297
- const { command } = createCommand({ ipc: IPC_FD });
298
- const spy = subscribeSpyTo(command.messages.outgoing);
299
- const message1 = { foo: true };
300
- command.send(message1);
301
- const message2 = { bar: 123 };
302
- const handle = {};
303
- command.send(message2, handle);
304
- const message3 = { baz: 'yes' };
305
- const options = {};
306
- command.send(message3, undefined, options);
307
- expect(spy.getValuesLength()).toBe(3);
308
- expect(spy.getValueAt(0)).toMatchObject({
309
- message: message1,
310
- handle: undefined,
311
- options: undefined,
312
- });
313
- expect(spy.getValueAt(1)).toMatchObject({ message: message2, handle, options: undefined });
314
- expect(spy.getValueAt(2)).toMatchObject({ message: message3, handle: undefined, options });
315
- });
316
- it('resolves when onSent callback is called with no arguments', async () => {
317
- const { command } = createCommand({ ipc: IPC_FD });
318
- const spy = subscribeSpyTo(command.messages.outgoing);
319
- const promise = command.send({});
320
- spy.getFirstValue().onSent();
321
- await expect(promise).resolves.toBeUndefined();
322
- });
323
- it('rejects when onSent callback is called with an argument', async () => {
324
- const { command } = createCommand({ ipc: IPC_FD });
325
- const spy = subscribeSpyTo(command.messages.outgoing);
326
- const promise = command.send({});
327
- spy.getFirstValue().onSent('foo');
328
- await expect(promise).rejects.toBe('foo');
329
- });
330
- });
331
- describe('#kill()', () => {
332
- let createdCommand;
333
- beforeEach(() => {
334
- createdCommand = createCommand();
335
- });
336
- it('kills process', () => {
337
- createdCommand.command.start();
338
- createdCommand.command.kill();
339
- expect(killProcess).toHaveBeenCalledExactlyOnceWith(createdCommand.command.pid, undefined);
340
- });
341
- it('kills process with some signal', () => {
342
- createdCommand.command.start();
343
- createdCommand.command.kill('SIGKILL');
344
- expect(killProcess).toHaveBeenCalledExactlyOnceWith(createdCommand.command.pid, 'SIGKILL');
345
- });
346
- it('does not try to kill inexistent process', () => {
347
- createdCommand.command.start();
348
- process.emit('error');
349
- createdCommand.command.kill();
350
- expect(killProcess).not.toHaveBeenCalled();
351
- });
352
- it('marks the command as killed', async () => {
353
- createdCommand.command.start();
354
- createdCommand.command.kill();
355
- process.emit('close', 1, null);
356
- const { close } = await createdCommand.values();
357
- expect(close).toMatchObject({ exitCode: 1, killed: true });
358
- });
359
- });
360
- describe('.canKill()', () => {
361
- it('returns whether command has both PID and process', () => {
362
- const { command } = createCommand();
363
- expect(Command.canKill(command)).toBe(false);
364
- command.pid = 1;
365
- expect(Command.canKill(command)).toBe(false);
366
- command.process = process;
367
- expect(Command.canKill(command)).toBe(true);
368
- });
369
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,229 +0,0 @@
1
- import { getEventListeners } from 'node:events';
2
- import { TestScheduler } from 'rxjs/testing';
3
- import { beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { createFakeCloseEvent, FakeCommand } from './__fixtures__/fake-command.js';
5
- import { CompletionListener } from './completion-listener.js';
6
- let commands;
7
- let scheduler;
8
- beforeEach(() => {
9
- commands = [
10
- new FakeCommand('foo', 'echo', 0),
11
- new FakeCommand('bar', 'echo', 1),
12
- new FakeCommand('baz', 'echo', 2),
13
- ];
14
- scheduler = new TestScheduler(() => true);
15
- });
16
- const createController = (successCondition) => new CompletionListener({
17
- successCondition,
18
- scheduler,
19
- });
20
- const emitFakeCloseEvent = (command, event) => {
21
- const fakeEvent = createFakeCloseEvent({ ...event, command, index: command.index });
22
- command.state = 'exited';
23
- command.close.next(fakeEvent);
24
- return fakeEvent;
25
- };
26
- const flushPromises = () => new Promise((resolve) => setTimeout(resolve, 0));
27
- describe('listen', () => {
28
- it('resolves when there are no commands', async () => {
29
- const result = createController().listen([]);
30
- await expect(result).resolves.toHaveLength(0);
31
- });
32
- it('completes only when commands emit a close event, returns close event', async () => {
33
- const abortCtrl = new AbortController();
34
- const result = createController('all').listen(commands, abortCtrl.signal);
35
- commands[0].state = 'started';
36
- abortCtrl.abort();
37
- const event = emitFakeCloseEvent(commands[0]);
38
- scheduler.flush();
39
- await expect(result).resolves.toHaveLength(1);
40
- await expect(result).resolves.toEqual([event]);
41
- });
42
- it('completes when abort signal is received and command is stopped, returns nothing', async () => {
43
- const abortCtrl = new AbortController();
44
- // Use success condition = first to test index access when there are no close events
45
- const result = createController('first').listen([new FakeCommand()], abortCtrl.signal);
46
- abortCtrl.abort();
47
- scheduler.flush();
48
- await expect(result).resolves.toHaveLength(0);
49
- });
50
- it('does not leak memory when listening for abort signals', () => {
51
- const abortCtrl = new AbortController();
52
- createController().listen(Array.from({ length: 10 }, () => new FakeCommand()), abortCtrl.signal);
53
- expect(getEventListeners(abortCtrl.signal, 'abort')).toHaveLength(1);
54
- });
55
- it('check for success once all commands have emitted at least a single close event', async () => {
56
- const finallyCallback = vi.fn();
57
- const result = createController().listen(commands).finally(finallyCallback);
58
- // Emitting multiple close events to mimic calling command `kill/start` APIs.
59
- emitFakeCloseEvent(commands[0]);
60
- emitFakeCloseEvent(commands[0]);
61
- emitFakeCloseEvent(commands[0]);
62
- scheduler.flush();
63
- // A broken implementation will have called finallyCallback only after flushing promises
64
- await flushPromises();
65
- expect(finallyCallback).not.toHaveBeenCalled();
66
- emitFakeCloseEvent(commands[1]);
67
- emitFakeCloseEvent(commands[2]);
68
- scheduler.flush();
69
- await expect(result).resolves.toEqual(expect.anything());
70
- expect(finallyCallback).toHaveBeenCalled();
71
- });
72
- it('takes last event emitted from each command', async () => {
73
- const result = createController().listen(commands);
74
- emitFakeCloseEvent(commands[0], { exitCode: 0 });
75
- emitFakeCloseEvent(commands[0], { exitCode: 1 });
76
- emitFakeCloseEvent(commands[1], { exitCode: 0 });
77
- emitFakeCloseEvent(commands[2], { exitCode: 0 });
78
- scheduler.flush();
79
- await expect(result).rejects.toEqual(expect.anything());
80
- });
81
- it('waits for manually restarted events to close', async () => {
82
- const finallyCallback = vi.fn();
83
- const result = createController().listen(commands).finally(finallyCallback);
84
- emitFakeCloseEvent(commands[0]);
85
- commands[0].state = 'started';
86
- emitFakeCloseEvent(commands[1]);
87
- emitFakeCloseEvent(commands[2]);
88
- scheduler.flush();
89
- // A broken implementation will have called finallyCallback only after flushing promises
90
- await flushPromises();
91
- expect(finallyCallback).not.toHaveBeenCalled();
92
- commands[0].state = 'exited';
93
- emitFakeCloseEvent(commands[0]);
94
- scheduler.flush();
95
- await expect(result).resolves.toEqual(expect.anything());
96
- expect(finallyCallback).toHaveBeenCalled();
97
- });
98
- });
99
- describe('detect commands exit conditions', () => {
100
- describe('with default success condition set', () => {
101
- it('succeeds if all processes exited with code 0', () => {
102
- const result = createController().listen(commands);
103
- commands[0].close.next(createFakeCloseEvent({ exitCode: 0 }));
104
- commands[1].close.next(createFakeCloseEvent({ exitCode: 0 }));
105
- commands[2].close.next(createFakeCloseEvent({ exitCode: 0 }));
106
- scheduler.flush();
107
- return expect(result).resolves.toEqual(expect.anything());
108
- });
109
- it('fails if one of the processes exited with non-0 code', () => {
110
- const result = createController().listen(commands);
111
- commands[0].close.next(createFakeCloseEvent({ exitCode: 0 }));
112
- commands[1].close.next(createFakeCloseEvent({ exitCode: 1 }));
113
- commands[2].close.next(createFakeCloseEvent({ exitCode: 0 }));
114
- scheduler.flush();
115
- return expect(result).rejects.toEqual(expect.anything());
116
- });
117
- });
118
- describe('with success condition set to first', () => {
119
- it('succeeds if first process to exit has code 0', () => {
120
- const result = createController('first').listen(commands);
121
- commands[1].close.next(createFakeCloseEvent({ exitCode: 0 }));
122
- commands[0].close.next(createFakeCloseEvent({ exitCode: 1 }));
123
- commands[2].close.next(createFakeCloseEvent({ exitCode: 1 }));
124
- scheduler.flush();
125
- return expect(result).resolves.toEqual(expect.anything());
126
- });
127
- it('fails if first process to exit has non-0 code', () => {
128
- const result = createController('first').listen(commands);
129
- commands[1].close.next(createFakeCloseEvent({ exitCode: 1 }));
130
- commands[0].close.next(createFakeCloseEvent({ exitCode: 0 }));
131
- commands[2].close.next(createFakeCloseEvent({ exitCode: 0 }));
132
- scheduler.flush();
133
- return expect(result).rejects.toEqual(expect.anything());
134
- });
135
- });
136
- describe('with success condition set to last', () => {
137
- it('succeeds if last process to exit has code 0', () => {
138
- const result = createController('last').listen(commands);
139
- commands[1].close.next(createFakeCloseEvent({ exitCode: 1 }));
140
- commands[0].close.next(createFakeCloseEvent({ exitCode: 0 }));
141
- commands[2].close.next(createFakeCloseEvent({ exitCode: 0 }));
142
- scheduler.flush();
143
- return expect(result).resolves.toEqual(expect.anything());
144
- });
145
- it('fails if last process to exit has non-0 code', () => {
146
- const result = createController('last').listen(commands);
147
- commands[1].close.next(createFakeCloseEvent({ exitCode: 0 }));
148
- commands[0].close.next(createFakeCloseEvent({ exitCode: 1 }));
149
- commands[2].close.next(createFakeCloseEvent({ exitCode: 1 }));
150
- scheduler.flush();
151
- return expect(result).rejects.toEqual(expect.anything());
152
- });
153
- });
154
- describe.each([
155
- // Use the middle command for both cases to make it more difficult to make a mess up
156
- // in the implementation cause false passes.
157
- ['command-bar', 'bar'],
158
- ['command-1', 1],
159
- ])('with success condition set to %s', (condition, nameOrIndex) => {
160
- it(`succeeds if command ${nameOrIndex} exits with code 0`, () => {
161
- const result = createController(condition).listen(commands);
162
- emitFakeCloseEvent(commands[0], { exitCode: 1 });
163
- emitFakeCloseEvent(commands[1], { exitCode: 0 });
164
- emitFakeCloseEvent(commands[2], { exitCode: 1 });
165
- scheduler.flush();
166
- return expect(result).resolves.toEqual(expect.anything());
167
- });
168
- it(`succeeds if all commands ${nameOrIndex} exit with code 0`, () => {
169
- commands = [commands[0], commands[1], commands[1]];
170
- const result = createController(condition).listen(commands);
171
- emitFakeCloseEvent(commands[0], { exitCode: 1 });
172
- emitFakeCloseEvent(commands[1], { exitCode: 0 });
173
- emitFakeCloseEvent(commands[2], { exitCode: 0 });
174
- scheduler.flush();
175
- return expect(result).resolves.toEqual(expect.anything());
176
- });
177
- it(`fails if command ${nameOrIndex} exits with non-0 code`, () => {
178
- const result = createController(condition).listen(commands);
179
- emitFakeCloseEvent(commands[0], { exitCode: 0 });
180
- emitFakeCloseEvent(commands[1], { exitCode: 1 });
181
- emitFakeCloseEvent(commands[2], { exitCode: 0 });
182
- scheduler.flush();
183
- return expect(result).rejects.toEqual(expect.anything());
184
- });
185
- it(`succeeds if command ${nameOrIndex} exits with code 0 even when others fail`, () => {
186
- const result = createController(condition).listen(commands);
187
- emitFakeCloseEvent(commands[0], { exitCode: 1 });
188
- emitFakeCloseEvent(commands[1], { exitCode: 0 });
189
- emitFakeCloseEvent(commands[2], { exitCode: 1 });
190
- scheduler.flush();
191
- return expect(result).resolves.toEqual(expect.anything());
192
- });
193
- it(`fails if command ${nameOrIndex} doesn't exist`, () => {
194
- const result = createController(condition).listen([commands[0]]);
195
- emitFakeCloseEvent(commands[0], { exitCode: 0 });
196
- scheduler.flush();
197
- return expect(result).rejects.toEqual(expect.anything());
198
- });
199
- });
200
- describe.each([
201
- // Use the middle command for both cases to make it more difficult to make a mess up
202
- // in the implementation cause false passes.
203
- ['!command-bar', 'bar'],
204
- ['!command-1', 1],
205
- ])('with success condition set to %s', (condition, nameOrIndex) => {
206
- it(`succeeds if all commands but ${nameOrIndex} exit with code 0`, () => {
207
- const result = createController(condition).listen(commands);
208
- emitFakeCloseEvent(commands[0], { exitCode: 0 });
209
- emitFakeCloseEvent(commands[1], { exitCode: 1 });
210
- emitFakeCloseEvent(commands[2], { exitCode: 0 });
211
- scheduler.flush();
212
- return expect(result).resolves.toEqual(expect.anything());
213
- });
214
- it(`fails if any commands but ${nameOrIndex} exit with non-0 code`, () => {
215
- const result = createController(condition).listen(commands);
216
- emitFakeCloseEvent(commands[0], { exitCode: 1 });
217
- emitFakeCloseEvent(commands[1], { exitCode: 1 });
218
- emitFakeCloseEvent(commands[2], { exitCode: 0 });
219
- scheduler.flush();
220
- return expect(result).rejects.toEqual(expect.anything());
221
- });
222
- it(`succeeds if command ${nameOrIndex} doesn't exist`, () => {
223
- const result = createController(condition).listen([commands[0]]);
224
- emitFakeCloseEvent(commands[0], { exitCode: 0 });
225
- scheduler.flush();
226
- return expect(result).resolves.toEqual(expect.anything());
227
- });
228
- });
229
- });
@@ -1 +0,0 @@
1
- export {};