Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions lib/arguments/specific.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,23 @@ export const normalizeFdSpecificOptions = options => {
};

export const normalizeFdSpecificOption = (options, optionName) => {
const optionBaseArray = Array.from({length: getStdioLength(options) + 1});
const optionArray = normalizeFdSpecificValue(options[optionName], optionBaseArray, optionName);
const stdioLength = getStdioLength(options);
const optionBaseArray = Array.from({length: stdioLength + 1});
const optionArray = normalizeFdSpecificValue(options[optionName], optionBaseArray, optionName, stdioLength);
return addDefaultValue(optionArray, optionName);
};

const getStdioLength = ({stdio}) => Array.isArray(stdio)
? Math.max(stdio.length, STANDARD_STREAMS_ALIASES.length)
: STANDARD_STREAMS_ALIASES.length;

const normalizeFdSpecificValue = (optionValue, optionArray, optionName) => isPlainObject(optionValue)
? normalizeOptionObject(optionValue, optionArray, optionName)
const normalizeFdSpecificValue = (optionValue, optionArray, optionName, stdioLength) => isPlainObject(optionValue)
? normalizeOptionObject(optionValue, optionArray, optionName, stdioLength)
: optionArray.fill(optionValue);

const normalizeOptionObject = (optionValue, optionArray, optionName) => {
const normalizeOptionObject = (optionValue, optionArray, optionName, stdioLength) => {
for (const fdName of Object.keys(optionValue).sort(compareFdName)) {
for (const fdNumber of parseFdName(fdName, optionName, optionArray)) {
for (const fdNumber of parseFdName(fdName, optionName, stdioLength)) {
optionArray[fdNumber] = optionValue[fdName];
}
}
Expand All @@ -50,9 +51,9 @@ const getFdNameOrder = fdName => {
return fdName === 'all' ? 2 : 1;
};

const parseFdName = (fdName, optionName, optionArray) => {
const parseFdName = (fdName, optionName, stdioLength) => {
if (fdName === 'ipc') {
return [optionArray.length - 1];
return [stdioLength];
Comment thread
sindresorhus marked this conversation as resolved.
}

const fdNumber = parseFd(fdName);
Expand All @@ -61,7 +62,7 @@ const parseFdName = (fdName, optionName, optionArray) => {
It must be "${optionName}.stdout", "${optionName}.stderr", "${optionName}.all", "${optionName}.ipc", or "${optionName}.fd3", "${optionName}.fd4" (and so on).`);
}

if (fdNumber >= optionArray.length) {
if (fdNumber !== 'all' && fdNumber >= stdioLength) {
Comment thread
sindresorhus marked this conversation as resolved.
throw new TypeError(`"${optionName}.${fdName}" is invalid: that file descriptor does not exist.
Please set the "stdio" option to ensure that file descriptor exists.`);
}
Expand Down
20 changes: 10 additions & 10 deletions test-d/arguments/specific.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ await execa('unicorns', {maxBuffer: {stdout: 0, stderr: 0} as const});
await execa('unicorns', {maxBuffer: {all: 0}});
await execa('unicorns', {maxBuffer: {fd1: 0}});
await execa('unicorns', {maxBuffer: {fd2: 0}});
await execa('unicorns', {maxBuffer: {fd3: 0}});
await execa('unicorns', {maxBuffer: {fd3: 0}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});

@ehmicky ehmicky Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should keep the original assertion as well (without the stdio option), to make sure maxBuffer.fd3 type works, even when stdio is not set?
Same for the other changes in that same file.

await execa('unicorns', {maxBuffer: {ipc: 0}});
expectError(await execa('unicorns', {maxBuffer: {stdout: '0'}}));

Expand All @@ -21,7 +21,7 @@ execaSync('unicorns', {maxBuffer: {stdout: 0, stderr: 0} as const});
execaSync('unicorns', {maxBuffer: {all: 0}});
execaSync('unicorns', {maxBuffer: {fd1: 0}});
execaSync('unicorns', {maxBuffer: {fd2: 0}});
execaSync('unicorns', {maxBuffer: {fd3: 0}});
execaSync('unicorns', {maxBuffer: {fd3: 0}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
execaSync('unicorns', {maxBuffer: {ipc: 0}});
expectError(execaSync('unicorns', {maxBuffer: {stdout: '0'}}));

Expand All @@ -33,7 +33,7 @@ await execa('unicorns', {verbose: {stdout: 'none', stderr: 'none'} as const});
await execa('unicorns', {verbose: {all: 'none'}});
await execa('unicorns', {verbose: {fd1: 'none'}});
await execa('unicorns', {verbose: {fd2: 'none'}});
await execa('unicorns', {verbose: {fd3: 'none'}});
await execa('unicorns', {verbose: {fd3: 'none'}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
await execa('unicorns', {verbose: {ipc: 'none'}});
expectError(await execa('unicorns', {verbose: {stdout: 'other'}}));

Expand All @@ -45,7 +45,7 @@ execaSync('unicorns', {verbose: {stdout: 'none', stderr: 'none'} as const});
execaSync('unicorns', {verbose: {all: 'none'}});
execaSync('unicorns', {verbose: {fd1: 'none'}});
execaSync('unicorns', {verbose: {fd2: 'none'}});
execaSync('unicorns', {verbose: {fd3: 'none'}});
execaSync('unicorns', {verbose: {fd3: 'none'}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
execaSync('unicorns', {verbose: {ipc: 'none'}});
expectError(execaSync('unicorns', {verbose: {stdout: 'other'}}));

Expand All @@ -57,7 +57,7 @@ await execa('unicorns', {stripFinalNewline: {stdout: true, stderr: true} as cons
await execa('unicorns', {stripFinalNewline: {all: true}});
await execa('unicorns', {stripFinalNewline: {fd1: true}});
await execa('unicorns', {stripFinalNewline: {fd2: true}});
await execa('unicorns', {stripFinalNewline: {fd3: true}});
await execa('unicorns', {stripFinalNewline: {fd3: true}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
await execa('unicorns', {stripFinalNewline: {ipc: true}});
expectError(await execa('unicorns', {stripFinalNewline: {stdout: 'true'}}));

Expand All @@ -69,7 +69,7 @@ execaSync('unicorns', {stripFinalNewline: {stdout: true, stderr: true} as const}
execaSync('unicorns', {stripFinalNewline: {all: true}});
execaSync('unicorns', {stripFinalNewline: {fd1: true}});
execaSync('unicorns', {stripFinalNewline: {fd2: true}});
execaSync('unicorns', {stripFinalNewline: {fd3: true}});
execaSync('unicorns', {stripFinalNewline: {fd3: true}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
execaSync('unicorns', {stripFinalNewline: {ipc: true}});
expectError(execaSync('unicorns', {stripFinalNewline: {stdout: 'true'}}));

Expand All @@ -81,7 +81,7 @@ await execa('unicorns', {lines: {stdout: true, stderr: true} as const});
await execa('unicorns', {lines: {all: true}});
await execa('unicorns', {lines: {fd1: true}});
await execa('unicorns', {lines: {fd2: true}});
await execa('unicorns', {lines: {fd3: true}});
await execa('unicorns', {lines: {fd3: true}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
await execa('unicorns', {lines: {ipc: true}});
expectError(await execa('unicorns', {lines: {stdout: 'true'}}));

Expand All @@ -93,7 +93,7 @@ execaSync('unicorns', {lines: {stdout: true, stderr: true} as const});
execaSync('unicorns', {lines: {all: true}});
execaSync('unicorns', {lines: {fd1: true}});
execaSync('unicorns', {lines: {fd2: true}});
execaSync('unicorns', {lines: {fd3: true}});
execaSync('unicorns', {lines: {fd3: true}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
execaSync('unicorns', {lines: {ipc: true}});
expectError(execaSync('unicorns', {lines: {stdout: 'true'}}));

Expand All @@ -105,7 +105,7 @@ await execa('unicorns', {buffer: {stdout: true, stderr: true} as const});
await execa('unicorns', {buffer: {all: true}});
await execa('unicorns', {buffer: {fd1: true}});
await execa('unicorns', {buffer: {fd2: true}});
await execa('unicorns', {buffer: {fd3: true}});
await execa('unicorns', {buffer: {fd3: true}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
await execa('unicorns', {buffer: {ipc: true}});
expectError(await execa('unicorns', {buffer: {stdout: 'true'}}));

Expand All @@ -117,7 +117,7 @@ execaSync('unicorns', {buffer: {stdout: true, stderr: true} as const});
execaSync('unicorns', {buffer: {all: true}});
execaSync('unicorns', {buffer: {fd1: true}});
execaSync('unicorns', {buffer: {fd2: true}});
execaSync('unicorns', {buffer: {fd3: true}});
execaSync('unicorns', {buffer: {fd3: true}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
execaSync('unicorns', {buffer: {ipc: true}});
expectError(execaSync('unicorns', {buffer: {stdout: 'true'}}));

Expand Down
7 changes: 7 additions & 0 deletions test-d/return/no-buffer-specific.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ expectType<string>(noBufferFd3Result.all);
expectType<undefined>(noBufferFd3Result.stdio[3]);
expectType<string>(noBufferFd3Result.stdio[4]);

const noBufferIpcResult = await execa('unicorns', {buffer: {ipc: false}, ipc: true, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
expectType<string>(noBufferIpcResult.stdio[3]);
expectType<[]>(noBufferIpcResult.ipcOutput);

const noBufferStdoutResultSync = execaSync('unicorns', {all: true, buffer: {stdout: false}});
expectType<undefined>(noBufferStdoutResultSync.stdout);
expectType<undefined>(noBufferStdoutResultSync.stdio[1]);
Expand Down Expand Up @@ -88,3 +92,6 @@ expectType<string>(noBufferFd3ResultSync.stdio[2]);
expectType<string>(noBufferFd3ResultSync.all);
expectType<undefined>(noBufferFd3ResultSync.stdio[3]);
expectType<string>(noBufferFd3ResultSync.stdio[4]);

const noBufferIpcStdioResultSync = execaSync('unicorns', {buffer: {ipc: false}, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
expectType<string>(noBufferIpcStdioResultSync.stdio[3]);
11 changes: 9 additions & 2 deletions test/helpers/verbose.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import {stripVTControlCharacters} from 'node:util';
import {replaceSymbols} from 'figures';
import {foobarString} from './input.js';
import {nestedSubprocess} from './nested.js';
import {fullStdio} from './stdio.js';

const isWindows = platform === 'win32';
export const QUOTE = isWindows ? '"' : '\'';

export const runErrorSubprocess = async (t, verbose, isSync = false, expectExitCode = true) => {
const {stderr, nestedResult} = await nestedSubprocess('noop-fail.js', ['1', foobarString], {verbose, isSync});
export const runErrorSubprocess = async (t, verbose, isSync = false, options = {}) => {
const {expectExitCode = true, ...subprocessOptions} = options;
const {stderr, nestedResult} = await nestedSubprocess('noop-fail.js', ['1', foobarString], {verbose, isSync, ...subprocessOptions});
t.true(nestedResult instanceof Error);
if (expectExitCode) {
t.true(stderr.includes('exit code 2'));
Expand Down Expand Up @@ -44,6 +46,7 @@ export const runVerboseSubprocess = ({
...options
}) => nestedSubprocess('noop-verbose.js', [output], {
ipc: !isSync,
...getStdioForFd3Option(fdNumber, secondFdNumber),
optionsFixture,
optionsInput: {
type,
Expand All @@ -57,6 +60,10 @@ export const runVerboseSubprocess = ({
...options,
});

export const getStdioForFd3Option = (...values) => values.some(value => hasFd3Option(value)) ? fullStdio : {};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, this is added to tests that use some {option: {fd3: ....}} option, to make them also pass {stdio: ['pipe', 'pipe', 'pipe', 'pipe']}. However, shouldn't fd3 work even without users having to pass that stdio option?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for runtime behavior. fd3 should only be valid when the child actually has fd 3, for xample via stdio: ['pipe', 'pipe', 'pipe', 'pipe']. With default stdio, fd3 should throw. The bug was that {ipc: true} added an internal pseudo-slot at index 3, so fd3 accidentally targeted IPC. This helper just makes the fd3 verbose matrix tests create a real fd3; the regression tests cover the default-stdio throw case.


const hasFd3Option = value => value === 'fd3' || (typeof value === 'object' && value !== null && Object.hasOwn(value, 'fd3'));

export const getCommandLine = stderr => getCommandLines(stderr)[0];
export const getCommandLines = stderr => getNormalizedLines(stderr).filter(line => isCommandLine(line));
const isCommandLine = line => line.includes(' $ ') || line.includes(' | ');
Expand Down
20 changes: 20 additions & 0 deletions test/io/max-buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,26 @@ test('maxBuffer does not affect other file descriptors with fd-specific options'
t.false(isMaxBuffer);
});

test('maxBuffer.fd3 is invalid without stdio[3], even with ipc', t => {
const {message} = t.throws(() => {
execa('ipc-send-twice.js', {ipc: true, maxBuffer: {fd3: 1}});
});
t.true(message.includes('"maxBuffer.fd3" is invalid: that file descriptor does not exist.'));
});

test('maxBuffer.fd3 and maxBuffer.ipc are distinct', async t => {
const {isMaxBuffer, ipcOutput} = await execa('ipc-send-twice.js', {
ipc: true,
stdio: ['ignore', 'pipe', 'pipe', 'pipe'],
maxBuffer: {
fd3: 1,
ipc: 2,
},
});
t.false(isMaxBuffer);
t.deepEqual(ipcOutput, foobarArray);
});

test('maxBuffer.stdout is used for other file descriptors with fd-specific options, sync', async t => {
const length = 1;
const {shortMessage, stderr} = await runMaxBuffer(t, execaSync, 2, {maxBuffer: {stdout: length}});
Expand Down
13 changes: 13 additions & 0 deletions test/ipc/buffer-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {execa, execaSync} from '../../index.js';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString, foobarArray} from '../helpers/input.js';
import {PARALLEL_COUNT} from '../helpers/parallel.js';
import {fullStdio} from '../helpers/stdio.js';

setFixtureDirectory();

Expand All @@ -22,6 +23,18 @@ const testResultNoBuffer = async (t, options) => {
test('Sets empty result.ipcOutput if buffer is false', testResultNoBuffer, {buffer: false});
test('Sets empty result.ipcOutput if buffer is false, fd-specific buffer', testResultNoBuffer, {buffer: {ipc: false}});

test('buffer.fd3 is invalid without stdio[3], even with ipc', t => {
const {message} = t.throws(() => {
execa('ipc-send-twice.js', {ipc: true, buffer: {fd3: false}});
});
t.true(message.includes('"buffer.fd3" is invalid: that file descriptor does not exist.'));
});

test('buffer.fd3 does not affect result.ipcOutput', async t => {
const {ipcOutput} = await execa('ipc-send-twice.js', {ipc: true, buffer: {fd3: false}, ...fullStdio});
t.deepEqual(ipcOutput, foobarArray);
});

test('Can use IPC methods when buffer is false', async t => {
const subprocess = execa('ipc-send.js', {ipc: true, buffer: false});
t.is(await subprocess.getOneMessage(), foobarString);
Expand Down
13 changes: 7 additions & 6 deletions test/verbose/complete.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
getCompletionLines,
testTimestamp,
getVerboseOption,
getStdioForFd3Option,
stdoutNoneOption,
stdoutShortOption,
stdoutFullOption,
Expand All @@ -28,7 +29,7 @@ import {
setFixtureDirectory();

const testPrintCompletion = async (t, verbose, isSync) => {
const {stderr} = await nestedSubprocess('noop.js', [foobarString], {verbose, isSync});
const {stderr} = await nestedSubprocess('noop.js', [foobarString], {verbose, ...getStdioForFd3Option(verbose), isSync});
t.is(getCompletionLine(stderr), `${testTimestamp} [0] √ (done in 0ms)`);
};

Expand All @@ -54,24 +55,24 @@ test('Prints completion, verbose "short", fd-specific ipc, sync', testPrintCompl
test('Prints completion, verbose "full", fd-specific ipc, sync', testPrintCompletion, ipcFullOption, true);

const testNoPrintCompletion = async (t, verbose, isSync) => {
const {stderr} = await nestedSubprocess('noop.js', [foobarString], {verbose, isSync});
const {stderr} = await nestedSubprocess('noop.js', [foobarString], {verbose, ...getStdioForFd3Option(verbose), isSync});
t.is(stderr, '');
};

test('Does not print completion, verbose "none"', testNoPrintCompletion, 'none', false);
test('Does not print completion, verbose default"', testNoPrintCompletion, undefined, false);
test('Does not print completion, verbose default', testNoPrintCompletion, undefined, false);
test('Does not print completion, verbose "none", fd-specific stdout', testNoPrintCompletion, stdoutNoneOption, false);
test('Does not print completion, verbose "none", fd-specific stderr', testNoPrintCompletion, stderrNoneOption, false);
test('Does not print completion, verbose "none", fd-specific fd3', testNoPrintCompletion, fd3NoneOption, false);
test('Does not print completion, verbose "none", fd-specific ipc', testNoPrintCompletion, ipcNoneOption, false);
test('Does not print completion, verbose default", fd-specific', testNoPrintCompletion, {}, false);
test('Does not print completion, verbose default, fd-specific', testNoPrintCompletion, {}, false);
test('Does not print completion, verbose "none", sync', testNoPrintCompletion, 'none', true);
test('Does not print completion, verbose default", sync', testNoPrintCompletion, undefined, true);
test('Does not print completion, verbose default, sync', testNoPrintCompletion, undefined, true);
test('Does not print completion, verbose "none", fd-specific stdout, sync', testNoPrintCompletion, stdoutNoneOption, true);
test('Does not print completion, verbose "none", fd-specific stderr, sync', testNoPrintCompletion, stderrNoneOption, true);
test('Does not print completion, verbose "none", fd-specific fd3, sync', testNoPrintCompletion, fd3NoneOption, true);
test('Does not print completion, verbose "none", fd-specific ipc, sync', testNoPrintCompletion, ipcNoneOption, true);
test('Does not print completion, verbose default", fd-specific, sync', testNoPrintCompletion, {}, true);
test('Does not print completion, verbose default, fd-specific, sync', testNoPrintCompletion, {}, true);

const testPrintCompletionError = async (t, isSync) => {
const stderr = await runErrorSubprocess(t, 'short', isSync);
Expand Down
11 changes: 7 additions & 4 deletions test/verbose/error.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import test from 'ava';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString, foobarRed} from '../helpers/input.js';
import {foobarString} from '../helpers/input.js';
import {nestedSubprocess} from '../helpers/nested.js';
import {
QUOTE,
Expand All @@ -10,6 +10,7 @@ import {
getErrorLines,
testTimestamp,
getVerboseOption,
getStdioForFd3Option,
stdoutNoneOption,
stdoutShortOption,
stdoutFullOption,
Expand All @@ -26,8 +27,10 @@ import {

setFixtureDirectory();

const redFoobarString = `\u001B[31m${foobarString}\u001B[39m`;

const testPrintError = async (t, verbose, isSync) => {
const stderr = await runErrorSubprocess(t, verbose, isSync);
const stderr = await runErrorSubprocess(t, verbose, isSync, getStdioForFd3Option(verbose));
t.is(getErrorLine(stderr), `${testTimestamp} [0] × Command failed with exit code 2: noop-fail.js 1 ${foobarString}`);
};

Expand All @@ -53,7 +56,7 @@ test('Prints error, verbose "short", fd-specific ipc, sync', testPrintError, ipc
test('Prints error, verbose "full", fd-specific ipc, sync', testPrintError, ipcFullOption, true);

const testNoPrintError = async (t, verbose, isSync) => {
const stderr = await runErrorSubprocess(t, verbose, isSync, false);
const stderr = await runErrorSubprocess(t, verbose, isSync, {expectExitCode: false, ...getStdioForFd3Option(verbose)});
t.is(getErrorLine(stderr), undefined);
};

Expand Down Expand Up @@ -149,7 +152,7 @@ test('Does not escape internal characters from error', async t => {
});

test('Escapes and strips color sequences from error', async t => {
const {stderr} = await t.throwsAsync(nestedSubprocess('noop-forever.js', [foobarRed], {parentFixture: 'nested-fail.js', verbose: 'short'}));
const {stderr} = await t.throwsAsync(nestedSubprocess('noop-forever.js', [redFoobarString], {parentFixture: 'nested-fail.js', verbose: 'short'}));
t.deepEqual(getErrorLines(stderr), [
`${testTimestamp} [0] × Command was killed with SIGTERM (Termination): noop-forever.js ${QUOTE}\\u001b[31m${foobarString}\\u001b[39m${QUOTE}`,
`${testTimestamp} [0] × ${foobarString}`,
Expand Down
20 changes: 18 additions & 2 deletions test/verbose/ipc.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {on} from 'node:events';
import {inspect} from 'node:util';
import test from 'ava';
import {red} from 'yoctocolors';
import {execa} from '../../index.js';
import {setFixtureDirectory} from '../helpers/fixtures-directory.js';
import {foobarString, foobarRed, foobarObject} from '../helpers/input.js';
import {foobarString, foobarObject} from '../helpers/input.js';
import {nestedSubprocess, nestedInstance} from '../helpers/nested.js';
import {fullStdio} from '../helpers/stdio.js';
import {
getIpcLine,
getIpcLines,
Expand All @@ -23,6 +26,19 @@ const testPrintIpc = async (t, verbose) => {
test('Prints IPC, verbose "full"', testPrintIpc, 'full');
test('Prints IPC, verbose "full", fd-specific', testPrintIpc, ipcFullOption);

test('verbose.fd3 is invalid without stdio[3], even with ipc', t => {
const {message} = t.throws(() => {
execa('ipc-send.js', {ipc: true, verbose: {fd3: 'full'}});
});
t.true(message.includes('"verbose.fd3" is invalid: that file descriptor does not exist.'));
});

test('verbose.fd3 does not affect IPC', async t => {
const {nestedResult, stderr} = await nestedSubprocess('ipc-send.js', {ipc: true, verbose: {fd3: 'full'}, ...fullStdio});
t.deepEqual(nestedResult.ipcOutput, [foobarString]);
t.is(getIpcLine(stderr), undefined);
});

const testNoPrintIpc = async (t, verbose) => {
const {stderr} = await nestedSubprocess('ipc-send.js', {ipc: true, verbose});
t.is(getIpcLine(stderr), undefined);
Expand Down Expand Up @@ -83,7 +99,7 @@ test('Does not escape internal characters from IPC', async t => {
});

test('Strips color sequences from IPC', async t => {
const {stderr} = await nestedSubprocess('ipc-send.js', [foobarRed], {ipc: true, verbose: 'full'});
const {stderr} = await nestedSubprocess('ipc-send.js', [red(foobarString)], {ipc: true, verbose: 'full'}, {env: {FORCE_COLOR: '1', NO_COLOR: undefined}});
t.is(getIpcLine(stderr), `${testTimestamp} [0] * ${foobarString}`);
});

Expand Down
Loading
Loading