diff --git a/.travis.yml b/.travis.yml index 0e8f27289..f1d659d0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,5 @@ language: node_js node_js: - '10' - '8' - - '6' after_success: - './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls' diff --git a/index.js b/index.js index 07d683d84..872c7fa84 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,7 @@ function handleArgs(command, args, options) { args = parsed.args; options = parsed.options; - options = Object.assign({ + options = { maxBuffer: TEN_MEGABYTES, buffer: true, stripFinalNewline: true, @@ -28,17 +28,23 @@ function handleArgs(command, args, options) { localDir: options.cwd || process.cwd(), encoding: 'utf8', reject: true, - cleanup: true - }, options, { + cleanup: true, + ...options, windowsHide: true - }); + }; if (options.extendEnv !== false) { - options.env = Object.assign({}, process.env, options.env); + options.env = { + ...process.env, + ...options.env + }; } if (options.preferLocal) { - options.env = npmRunPath.env(Object.assign({}, options, {cwd: options.localDir})); + options.env = npmRunPath.env({ + ...options, + cwd: options.localDir + }); } // TODO: Remove in the next major release @@ -82,7 +88,7 @@ function handleOutput(options, value) { } function handleShell(fn, command, options) { - return fn(command, Object.assign({}, options, {shell: true})); + return fn(command, {...options, shell: true}); } function getStream(process, stream, {encoding, buffer, maxBuffer}) { @@ -257,14 +263,15 @@ module.exports = (command, args, options) => { } } + // TODO: Use native "finally" syntax when targeting Node.js 10 const handlePromise = () => pFinally(Promise.all([ processDone, getStream(spawned, 'stdout', {encoding, buffer, maxBuffer}), getStream(spawned, 'stderr', {encoding, buffer, maxBuffer}) - ]).then(arr => { - const result = arr[0]; - result.stdout = arr[1]; - result.stderr = arr[2]; + ]).then(results => { // eslint-disable-line promise/prefer-await-to-then + const result = results[0]; + result.stdout = results[1]; + result.stderr = results[2]; if (result.error || result.code !== 0 || result.signal !== null) { const error = makeError(result, { @@ -301,21 +308,29 @@ module.exports = (command, args, options) => { handleInput(spawned, parsed.options.input); - spawned.then = (onfulfilled, onrejected) => handlePromise().then(onfulfilled, onrejected); - spawned.catch = onrejected => handlePromise().catch(onrejected); - // eslint-disable-next-line no-use-extend-native/no-use-extend-native + // eslint-disable-next-line promise/prefer-await-to-then + spawned.then = (onFulfilled, onRejected) => handlePromise().then(onFulfilled, onRejected); + spawned.catch = onRejected => handlePromise().catch(onRejected); + + // TOOD: Remove the `if`-guard when targeting Node.js 10 if (Promise.prototype.finally) { - spawned.finally = onfinally => handlePromise().finally(onfinally); + spawned.finally = onFinally => handlePromise().finally(onFinally); } return spawned; }; // TODO: set `stderr: 'ignore'` when that option is implemented -module.exports.stdout = (...args) => module.exports(...args).then(x => x.stdout); +module.exports.stdout = async (...args) => { + const {stdout} = await module.exports(...args); + return stdout; +}; // TODO: set `stdout: 'ignore'` when that option is implemented -module.exports.stderr = (...args) => module.exports(...args).then(x => x.stderr); +module.exports.stderr = async (...args) => { + const {stderr} = await module.exports(...args); + return stderr; +}; module.exports.shell = (command, options) => handleShell(module.exports, command, options); diff --git a/lib/errname.js b/lib/errname.js index 562284abf..8f9e1fb1b 100644 --- a/lib/errname.js +++ b/lib/errname.js @@ -9,7 +9,7 @@ if (typeof util.getSystemErrorName === 'function') { module.exports = util.getSystemErrorName; } else { try { - uv = process.binding('uv'); + uv = process.binding('uv'); // eslint-disable-line node/no-deprecated-api if (typeof uv.errname !== 'function') { throw new TypeError('uv.errname is not a function'); diff --git a/package.json b/package.json index 29a6dd2d0..d6a84e558 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "url": "sindresorhus.com" }, "engines": { - "node": ">=6" + "node": ">=8" }, "scripts": { "test": "xo && nyc ava" @@ -46,14 +46,14 @@ "strip-final-newline": "^2.0.0" }, "devDependencies": { - "ava": "^1.2.1", - "cat-names": "^1.0.2", - "coveralls": "^3.0.1", - "delay": "^3.0.0", + "ava": "^1.3.1", + "cat-names": "^2.0.0", + "coveralls": "^3.0.3", + "delay": "^4.1.0", "is-running": "^2.0.0", - "nyc": "^13.0.1", + "nyc": "^13.3.0", "tempfile": "^2.0.0", - "xo": "^0.23.0" + "xo": "^0.24.0" }, "nyc": { "exclude": [ diff --git a/test.js b/test.js index 532298d0f..93b3e0d14 100644 --- a/test.js +++ b/test.js @@ -7,7 +7,7 @@ import getStream from 'get-stream'; import isRunning from 'is-running'; import delay from 'delay'; import tempfile from 'tempfile'; -import m from '.'; +import execa from '.'; process.env.PATH = path.join(__dirname, 'fixtures') + path.delimiter + process.env.PATH; process.env.FOO = 'foo'; @@ -16,134 +16,131 @@ const NO_NEWLINES_REGEXP = /^[^\n]*$/; const STDERR_STDOUT_REGEXP = /stderr[^]*stdout/; const TIMEOUT_REGEXP = /timed out after/; -function getExitRegExp(exitMessage) { - return new RegExp(`failed with exit code ${exitMessage}`); -} +const getExitRegExp = exitMessage => new RegExp(`failed with exit code ${exitMessage}`); test('execa()', async t => { - const {stdout} = await m('noop', ['foo']); + const {stdout} = await execa('noop', ['foo']); t.is(stdout, 'foo'); }); if (process.platform === 'win32') { test('execa() - cmd file', async t => { - const {stdout} = await m('hello.cmd'); - + const {stdout} = await execa('hello.cmd'); t.is(stdout, 'Hello World'); }); } test('buffer', async t => { - const {stdout} = await m('noop', ['foo'], {encoding: null}); + const {stdout} = await execa('noop', ['foo'], {encoding: null}); t.true(Buffer.isBuffer(stdout)); t.is(stdout.toString(), 'foo'); }); test('execa.stdout()', async t => { - const stdout = await m.stdout('noop', ['foo']); + const stdout = await execa.stdout('noop', ['foo']); t.is(stdout, 'foo'); }); test('execa.stderr()', async t => { - const stderr = await m.stderr('noop-err', ['foo']); + const stderr = await execa.stderr('noop-err', ['foo']); t.is(stderr, 'foo'); }); test('stdout/stderr available on errors', async t => { - const err = await t.throwsAsync(m('exit', ['2']), {message: getExitRegExp('2')}); + const err = await t.throwsAsync(execa('exit', ['2']), {message: getExitRegExp('2')}); t.is(typeof err.stdout, 'string'); t.is(typeof err.stderr, 'string'); }); test('include stdout and stderr in errors for improved debugging', async t => { - await t.throwsAsync(m('fixtures/error-message.js'), {message: STDERR_STDOUT_REGEXP, code: 1}); + await t.throwsAsync(execa('fixtures/error-message.js'), {message: STDERR_STDOUT_REGEXP, code: 1}); }); test('do not include in errors when `stdio` is set to `inherit`', async t => { - await t.throwsAsync(m('fixtures/error-message.js', {stdio: 'inherit'}), {message: NO_NEWLINES_REGEXP}); + await t.throwsAsync(execa('fixtures/error-message.js', {stdio: 'inherit'}), {message: NO_NEWLINES_REGEXP}); }); test('do not include `stderr` and `stdout` in errors when set to `inherit`', async t => { - await t.throwsAsync(m('fixtures/error-message.js', {stdout: 'inherit', stderr: 'inherit'}), {message: NO_NEWLINES_REGEXP}); + await t.throwsAsync(execa('fixtures/error-message.js', {stdout: 'inherit', stderr: 'inherit'}), {message: NO_NEWLINES_REGEXP}); }); test('do not include `stderr` and `stdout` in errors when `stdio` is set to `inherit`', async t => { - await t.throwsAsync(m('fixtures/error-message.js', {stdio: [null, 'inherit', 'inherit']}), {message: NO_NEWLINES_REGEXP}); + await t.throwsAsync(execa('fixtures/error-message.js', {stdio: [null, 'inherit', 'inherit']}), {message: NO_NEWLINES_REGEXP}); }); test('do not include `stdout` in errors when set to `inherit`', async t => { - const err = await t.throwsAsync(m('fixtures/error-message.js', {stdout: 'inherit'}), {message: /stderr/}); + const err = await t.throwsAsync(execa('fixtures/error-message.js', {stdout: 'inherit'}), {message: /stderr/}); t.notRegex(err.message, /stdout/); }); test('do not include `stderr` in errors when set to `inherit`', async t => { - const err = await t.throwsAsync(m('fixtures/error-message.js', {stderr: 'inherit'}), {message: /stdout/}); + const err = await t.throwsAsync(execa('fixtures/error-message.js', {stderr: 'inherit'}), {message: /stdout/}); t.notRegex(err.message, /stderr/); }); test('pass `stdout` to a file descriptor', async t => { const file = tempfile('.txt'); - await m('fixtures/noop', ['foo bar'], {stdout: fs.openSync(file, 'w')}); + await execa('fixtures/noop', ['foo bar'], {stdout: fs.openSync(file, 'w')}); t.is(fs.readFileSync(file, 'utf8'), 'foo bar\n'); }); test('pass `stderr` to a file descriptor', async t => { const file = tempfile('.txt'); - await m('fixtures/noop-err', ['foo bar'], {stderr: fs.openSync(file, 'w')}); + await execa('fixtures/noop-err', ['foo bar'], {stderr: fs.openSync(file, 'w')}); t.is(fs.readFileSync(file, 'utf8'), 'foo bar\n'); }); test('execa.shell()', async t => { - const {stdout} = await m.shell('node fixtures/noop foo'); + const {stdout} = await execa.shell('node fixtures/noop foo'); t.is(stdout, 'foo'); }); test('execa.sync()', t => { - const {stdout} = m.sync('noop', ['foo']); + const {stdout} = execa.sync('noop', ['foo']); t.is(stdout, 'foo'); }); test('execa.sync() throws error if written to stderr', t => { - t.throws(() => m.sync('foo'), process.platform === 'win32' ? /'foo' is not recognized as an internal or external command/ : /spawnSync foo ENOENT/); + t.throws(() => execa.sync('foo'), process.platform === 'win32' ? /'foo' is not recognized as an internal or external command/ : /spawnSync foo ENOENT/); }); test('execa.sync() includes stdout and stderr in errors for improved debugging', t => { - t.throws(() => m.sync('node', ['fixtures/error-message.js']), {message: STDERR_STDOUT_REGEXP, code: 1}); + t.throws(() => execa.sync('node', ['fixtures/error-message.js']), {message: STDERR_STDOUT_REGEXP, code: 1}); }); test('skip throwing when using reject option in execa.sync()', t => { - const err = m.sync('node', ['fixtures/error-message.js'], {reject: false}); + const err = execa.sync('node', ['fixtures/error-message.js'], {reject: false}); t.is(typeof err.stdout, 'string'); t.is(typeof err.stderr, 'string'); }); test('execa.shellSync()', t => { - const {stdout} = m.shellSync('node fixtures/noop foo'); + const {stdout} = execa.shellSync('node fixtures/noop foo'); t.is(stdout, 'foo'); }); test('execa.shellSync() includes stdout and stderr in errors for improved debugging', t => { - t.throws(() => m.shellSync('node fixtures/error-message.js'), {message: STDERR_STDOUT_REGEXP, code: 1}); + t.throws(() => execa.shellSync('node fixtures/error-message.js'), {message: STDERR_STDOUT_REGEXP, code: 1}); }); test('skip throwing when using reject option in execa.shellSync()', t => { - const err = m.shellSync('node fixtures/error-message.js', {reject: false}); + const err = execa.shellSync('node fixtures/error-message.js', {reject: false}); t.is(typeof err.stdout, 'string'); t.is(typeof err.stderr, 'string'); }); test('stripEof option (legacy)', async t => { - const {stdout} = await m('noop', ['foo'], {stripEof: false}); + const {stdout} = await execa('noop', ['foo'], {stripEof: false}); t.is(stdout, 'foo\n'); }); test('stripFinalNewline option', async t => { - const {stdout} = await m('noop', ['foo'], {stripFinalNewline: false}); + const {stdout} = await execa('noop', ['foo'], {stripFinalNewline: false}); t.is(stdout, 'foo\n'); }); test.serial('preferLocal option', async t => { - t.true((await m('cat-names')).stdout.length > 2); + t.true((await execa('cat-names')).stdout.length > 2); if (process.platform === 'win32') { // TODO: figure out how to make the below not hang on Windows @@ -153,7 +150,7 @@ test.serial('preferLocal option', async t => { // Account for npm adding local binaries to the PATH const _path = process.env.PATH; process.env.PATH = ''; - await t.throwsAsync(m('cat-names', {preferLocal: false}), /spawn .* ENOENT/); + await t.throwsAsync(execa('cat-names', {preferLocal: false}), /spawn .* ENOENT/); process.env.PATH = _path; }); @@ -161,20 +158,20 @@ test.serial('localDir option', async t => { const cwd = 'fixtures/local-dir'; const bin = path.resolve(cwd, 'node_modules/.bin/self-path'); - await m('npm', ['install', '--no-package-lock'], {cwd}); + await execa('npm', ['install', '--no-package-lock'], {cwd}); - const {stdout} = await m(bin, {localDir: cwd}); + const {stdout} = await execa(bin, {localDir: cwd}); t.is(path.relative(cwd, stdout), path.normalize('node_modules/self-path')); }); test('input option can be a String', async t => { - const {stdout} = await m('stdin', {input: 'foobar'}); + const {stdout} = await execa('stdin', {input: 'foobar'}); t.is(stdout, 'foobar'); }); test('input option can be a Buffer', async t => { - const {stdout} = await m('stdin', {input: 'testing12'}); + const {stdout} = await execa('stdin', {input: 'testing12'}); t.is(stdout, 'testing12'); }); @@ -182,28 +179,28 @@ test('input can be a Stream', async t => { const s = new stream.PassThrough(); s.write('howdy'); s.end(); - const {stdout} = await m('stdin', {input: s}); + const {stdout} = await execa('stdin', {input: s}); t.is(stdout, 'howdy'); }); test('you can write to child.stdin', async t => { - const child = m('stdin'); + const child = execa('stdin'); child.stdin.end('unicorns'); t.is((await child).stdout, 'unicorns'); }); test('input option can be a String - sync', t => { - const {stdout} = m.sync('stdin', {input: 'foobar'}); + const {stdout} = execa.sync('stdin', {input: 'foobar'}); t.is(stdout, 'foobar'); }); test('input option can be a Buffer - sync', t => { - const {stdout} = m.sync('stdin', {input: Buffer.from('testing12', 'utf8')}); + const {stdout} = execa.sync('stdin', {input: Buffer.from('testing12', 'utf8')}); t.is(stdout, 'testing12'); }); test('opts.stdout:ignore - stdout will not collect data', async t => { - const {stdout} = await m('stdin', { + const {stdout} = await execa('stdin', { input: 'hello', stdio: [null, 'ignore', null] }); @@ -212,29 +209,29 @@ test('opts.stdout:ignore - stdout will not collect data', async t => { test('helpful error trying to provide an input stream in sync mode', t => { t.throws( - () => m.sync('stdin', {input: new stream.PassThrough()}), + () => execa.sync('stdin', {input: new stream.PassThrough()}), /The `input` option cannot be a stream in sync mode/ ); }); test('execa() returns a promise with kill() and pid', t => { - const promise = m('noop', ['foo']); + const promise = execa('noop', ['foo']); t.is(typeof promise.kill, 'function'); t.is(typeof promise.pid, 'number'); }); test('maxBuffer affects stdout', async t => { - await t.throwsAsync(m('max-buffer', ['stdout', '11'], {maxBuffer: 10}), /stdout maxBuffer exceeded/); - await t.notThrowsAsync(m('max-buffer', ['stdout', '10'], {maxBuffer: 10})); + await t.throwsAsync(execa('max-buffer', ['stdout', '11'], {maxBuffer: 10}), /stdout maxBuffer exceeded/); + await t.notThrowsAsync(execa('max-buffer', ['stdout', '10'], {maxBuffer: 10})); }); test('maxBuffer affects stderr', async t => { - await t.throwsAsync(m('max-buffer', ['stderr', '13'], {maxBuffer: 12}), /stderr maxBuffer exceeded/); - await t.notThrowsAsync(m('max-buffer', ['stderr', '12'], {maxBuffer: 12})); + await t.throwsAsync(execa('max-buffer', ['stderr', '13'], {maxBuffer: 12}), /stderr maxBuffer exceeded/); + await t.notThrowsAsync(execa('max-buffer', ['stderr', '12'], {maxBuffer: 12})); }); test('do not buffer stdout when `buffer` set to `false`', async t => { - const promise = m('max-buffer', ['stdout', '10'], {buffer: false}); + const promise = execa('max-buffer', ['stdout', '10'], {buffer: false}); const [result, stdout] = await Promise.all([ promise, getStream(promise.stdout) @@ -245,7 +242,7 @@ test('do not buffer stdout when `buffer` set to `false`', async t => { }); test('do not buffer stderr when `buffer` set to `false`', async t => { - const promise = m('max-buffer', ['stderr', '10'], {buffer: false}); + const promise = execa('max-buffer', ['stderr', '10'], {buffer: false}); const [result, stderr] = await Promise.all([ promise, getStream(promise.stderr) @@ -256,18 +253,18 @@ test('do not buffer stderr when `buffer` set to `false`', async t => { }); test('skip throwing when using reject option', async t => { - const error = await m('exit', ['2'], {reject: false}); + const error = await execa('exit', ['2'], {reject: false}); t.is(typeof error.stdout, 'string'); t.is(typeof error.stderr, 'string'); }); test('allow unknown exit code', async t => { - await t.throwsAsync(m('exit', ['255']), {message: /exit code 255 \(Unknown system error -255\)/}); + await t.throwsAsync(execa('exit', ['255']), {message: /exit code 255 \(Unknown system error -255\)/}); }); test('execa() returns code and failed properties', async t => { - const {code, failed} = await m('noop', ['foo']); - const error = await t.throwsAsync(m('exit', ['2']), {code: 2, message: getExitRegExp('2')}); + const {code, failed} = await execa('noop', ['foo']); + const error = await t.throwsAsync(execa('exit', ['2']), {code: 2, message: getExitRegExp('2')}); t.is(code, 0); t.false(failed); t.true(error.failed); @@ -275,19 +272,19 @@ test('execa() returns code and failed properties', async t => { test('use relative path with \'..\' chars', async t => { const pathViaParentDir = path.join('..', path.basename(__dirname), 'fixtures', 'noop'); - const {stdout} = await m(pathViaParentDir, ['foo']); + const {stdout} = await execa(pathViaParentDir, ['foo']); t.is(stdout, 'foo'); }); if (process.platform !== 'win32') { test('execa() rejects if running non-executable', async t => { - const cp = m('non-executable'); + const cp = execa('non-executable'); await t.throwsAsync(cp); }); } test('error.killed is true if process was killed directly', async t => { - const cp = m('forever'); + const cp = execa('forever'); setTimeout(() => { cp.kill(); @@ -299,7 +296,7 @@ test('error.killed is true if process was killed directly', async t => { // TODO: Should this really be the case, or should we improve on child_process? test('error.killed is false if process was killed indirectly', async t => { - const cp = m('forever'); + const cp = execa('forever'); setTimeout(() => { process.kill(cp.pid, 'SIGINT'); @@ -327,7 +324,7 @@ if (process.platform === 'darwin') { if (process.platform !== 'win32') { test('error.signal is SIGINT', async t => { - const cp = m('forever'); + const cp = execa('forever'); setTimeout(() => { process.kill(cp.pid, 'SIGINT'); @@ -338,7 +335,7 @@ if (process.platform !== 'win32') { }); test('error.signal is SIGTERM', async t => { - const cp = m('forever'); + const cp = execa('forever'); setTimeout(() => { process.kill(cp.pid, 'SIGTERM'); @@ -349,22 +346,22 @@ if (process.platform !== 'win32') { }); test('custom error.signal', async t => { - const error = await t.throwsAsync(m('delay', ['3000', '0'], {killSignal: 'SIGHUP', timeout: 1500, message: TIMEOUT_REGEXP})); + const error = await t.throwsAsync(execa('delay', ['3000', '0'], {killSignal: 'SIGHUP', timeout: 1500, message: TIMEOUT_REGEXP})); t.is(error.signal, 'SIGHUP'); }); } test('result.signal is null for successful execution', async t => { - t.is((await m('noop')).signal, null); + t.is((await execa('noop')).signal, null); }); test('result.signal is null if process failed, but was not killed', async t => { - const error = await t.throwsAsync(m('exit', [2]), {message: getExitRegExp('2')}); + const error = await t.throwsAsync(execa('exit', [2]), {message: getExitRegExp('2')}); t.is(error.signal, null); }); async function code(t, num) { - await t.throwsAsync(m('exit', [`${num}`]), {code: num, message: getExitRegExp(num)}); + await t.throwsAsync(execa('exit', [`${num}`]), {code: num, message: getExitRegExp(num)}); } test('error.code is 2', code, 2); @@ -372,29 +369,29 @@ test('error.code is 3', code, 3); test('error.code is 4', code, 4); test('timeout will kill the process early', async t => { - const error = await t.throwsAsync(m('delay', ['60000', '0'], {timeout: 1500, message: TIMEOUT_REGEXP})); + const error = await t.throwsAsync(execa('delay', ['60000', '0'], {timeout: 1500, message: TIMEOUT_REGEXP})); t.true(error.timedOut); t.not(error.code, 22); }); test('timeout will not kill the process early', async t => { - const error = await t.throwsAsync(m('delay', ['3000', '22'], {timeout: 30000}), {code: 22, message: getExitRegExp('22')}); + const error = await t.throwsAsync(execa('delay', ['3000', '22'], {timeout: 30000}), {code: 22, message: getExitRegExp('22')}); t.false(error.timedOut); }); test('timedOut will be false if no timeout was set and zero exit code', async t => { - const result = await m('delay', ['1000', '0']); + const result = await execa('delay', ['1000', '0']); t.false(result.timedOut); }); test('timedOut will be false if no timeout was set and non-zero exit code', async t => { - const error = await t.throwsAsync(m('delay', ['1000', '3']), {message: getExitRegExp('3')}); + const error = await t.throwsAsync(execa('delay', ['1000', '3']), {message: getExitRegExp('3')}); t.false(error.timedOut); }); async function errorMessage(t, expected, ...args) { - await t.throwsAsync(m('exit', args), {message: expected}); + await t.throwsAsync(execa('exit', args), {message: expected}); } errorMessage.title = (message, expected) => `error.message matches: ${expected}`; @@ -403,10 +400,10 @@ test(errorMessage, /Command failed with exit code 2.*: exit 2 foo bar/, 2, 'foo' test(errorMessage, /Command failed with exit code 3.*: exit 3 baz quz/, 3, 'baz', 'quz'); async function cmd(t, expected, ...args) { - const error = await t.throwsAsync(m('fail', args)); + const error = await t.throwsAsync(execa('fail', args)); t.is(error.cmd, `fail${expected}`); - const result = await m('noop', args); + const result = await execa('noop', args); t.is(result.cmd, `noop${expected}`); } @@ -418,7 +415,7 @@ test(cmd, ''); async function spawnAndKill(t, signal, cleanup) { const name = cleanup ? 'sub-process' : 'sub-process-false'; - const cp = m(name); + const cp = execa(name); let pid; cp.stdout.setEncoding('utf8'); @@ -450,7 +447,7 @@ if (process.platform !== 'win32') { } test('execa.shell() supports the `shell` option', async t => { - const {stdout} = await m.shell('node fixtures/noop foo', { + const {stdout} = await execa.shell('node fixtures/noop foo', { shell: process.platform === 'win32' ? 'cmd.exe' : '/bin/bash' }); t.is(stdout, 'foo'); @@ -461,7 +458,7 @@ if (process.platform !== 'win32') { // Try-catch here is necessary, because this test is not 100% accurate // Sometimes process can manage to accept input before exiting try { - await m(`fast-exit-${process.platform}`, [], {input: 'data'}); + await execa(`fast-exit-${process.platform}`, [], {input: 'data'}); t.pass(); } catch (error) { t.is(error.code, 32); @@ -470,7 +467,7 @@ if (process.platform !== 'win32') { } test('use environment variables by default', async t => { - const result = await m.stdout('environment'); + const result = await execa.stdout('environment'); t.deepEqual(result.split('\n'), [ 'foo', @@ -479,7 +476,7 @@ test('use environment variables by default', async t => { }); test('extend environment variables by default', async t => { - const result = await m.stdout('environment', [], {env: {BAR: 'bar'}}); + const result = await execa.stdout('environment', [], {env: {BAR: 'bar'}}); t.deepEqual(result.split('\n'), [ 'foo', @@ -488,7 +485,7 @@ test('extend environment variables by default', async t => { }); test('do not extend environment with `extendEnv: false`', async t => { - const result = await m.stdout('environment', [], {env: {BAR: 'bar', PATH: process.env.PATH}, extendEnv: false}); + const result = await execa.stdout('environment', [], {env: {BAR: 'bar', PATH: process.env.PATH}, extendEnv: false}); t.deepEqual(result.split('\n'), [ 'undefined', @@ -499,13 +496,13 @@ test('do not extend environment with `extendEnv: false`', async t => { test('use extend environment with `extendEnv: true` and `shell: true`', async t => { process.env.TEST = 'test'; const command = process.platform === 'win32' ? 'echo %TEST%' : 'echo $TEST'; - const stdout = await m.stdout(command, {shell: true, env: {}, extendEnv: true}); + const stdout = await execa.stdout(command, {shell: true, env: {}, extendEnv: true}); t.is(stdout, 'test'); delete process.env.TEST; }); test('do not buffer when streaming', async t => { - const result = await getStream(m('max-buffer', ['stdout', '21'], {maxBuffer: 10}).stdout); + const result = await getStream(execa('max-buffer', ['stdout', '21'], {maxBuffer: 10}).stdout); t.is(result, '....................\n'); }); @@ -513,7 +510,7 @@ test('do not buffer when streaming', async t => { test('detach child process', async t => { const file = tempfile('.txt'); - await m('detach', [file]); + await execa('detach', [file]); await delay(5000); @@ -525,7 +522,7 @@ test('removes exit handler on exit', async t => { // FIXME: This relies on `signal-exit` internals const ee = process.__signal_exit_emitter__; - const child = m('noop'); + const child = execa('noop'); const listener = ee.listeners('exit').pop(); await new Promise((resolve, reject) => { @@ -537,11 +534,11 @@ test('removes exit handler on exit', async t => { t.false(included); }); -// eslint-disable-next-line no-use-extend-native/no-use-extend-native +// TOOD: Remove the `if`-guard when targeting Node.js 10 if (Promise.prototype.finally) { test('finally function is executed on success', async t => { let called = false; - const {stdout} = await m('noop', ['foo']).finally(() => { + const {stdout} = await execa('noop', ['foo']).finally(() => { called = true; }); t.is(called, true); @@ -550,7 +547,7 @@ if (Promise.prototype.finally) { test('finally function is executed on failure', async t => { let called = false; - const err = await t.throwsAsync(m('exit', ['2']).finally(() => { + const err = await t.throwsAsync(execa('exit', ['2']).finally(() => { called = true; })); t.is(called, true); @@ -559,14 +556,14 @@ if (Promise.prototype.finally) { }); test('throw in finally function bubbles up on success', async t => { - const result = await t.throwsAsync(m('noop', ['foo']).finally(() => { + const result = await t.throwsAsync(execa('noop', ['foo']).finally(() => { throw new Error('called'); })); t.is(result.message, 'called'); }); test('throw in finally bubbles up on error', async t => { - const result = await t.throwsAsync(m('exit', ['2']).finally(() => { + const result = await t.throwsAsync(execa('exit', ['2']).finally(() => { throw new Error('called'); })); t.is(result.message, 'called'); diff --git a/test/errname.js b/test/errname.js index 97dafb3d8..d47720d99 100644 --- a/test/errname.js +++ b/test/errname.js @@ -1,7 +1,7 @@ import test from 'ava'; import errname from '../lib/errname'; -const isWin = process.platform === 'win32'; +const isWindows = process.platform === 'win32'; // Simulates failure to capture `process.binding('uv');` const fallback = code => errname.__test__(null, code); @@ -22,5 +22,5 @@ function makeTests(name, m, expected) { const unknown = 'Unknown system error -2'; -makeTests('native', errname, isWin ? unknown : 'ENOENT'); +makeTests('native', errname, isWindows ? unknown : 'ENOENT'); makeTests('fallback', fallback, unknown);