From 749bb07496db682ff40c707daeebd7b73e176eaf Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 6 Dec 2024 12:30:41 +1300 Subject: [PATCH 1/9] Check for missing executable with message on Windows --- lib/command.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/command.js b/lib/command.js index 673a067fe..77df60c1c 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1165,6 +1165,17 @@ Expecting one of '${allowedValues.join("', '")}'`); launchWithNode = sourceExt.includes(path.extname(executableFile)); + function throwMissingExecutable() { + const executableDirMessage = executableDir + ? `searched for local subcommand relative to directory '${executableDir}'` + : 'no directory for search for local subcommand, use .executableDir() to supply a custom directory'; + const executableMissing = `'${executableFile}' does not exist + - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead + - if the default executable name is not suitable, use the executableFile option to supply a custom name or path + - ${executableDirMessage}`; + throw new Error(executableMissing); + } + let proc; if (process.platform !== 'win32') { if (launchWithNode) { @@ -1177,6 +1188,7 @@ Expecting one of '${allowedValues.join("', '")}'`); proc = childProcess.spawn(executableFile, args, { stdio: 'inherit' }); } } else { + if (!fs.existsSync(executableFile)) throwMissingExecutable(); args.unshift(executableFile); // add executable arguments to spawn args = incrementNodeInspectorPort(process.execArgv).concat(args); @@ -1215,14 +1227,7 @@ Expecting one of '${allowedValues.join("', '")}'`); proc.on('error', (err) => { // @ts-ignore: because err.code is an unknown property if (err.code === 'ENOENT') { - const executableDirMessage = executableDir - ? `searched for local subcommand relative to directory '${executableDir}'` - : 'no directory for search for local subcommand, use .executableDir() to supply a custom directory'; - const executableMissing = `'${executableFile}' does not exist - - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead - - if the default executable name is not suitable, use the executableFile option to supply a custom name or path - - ${executableDirMessage}`; - throw new Error(executableMissing); + throwMissingExecutable(); // @ts-ignore: because err.code is an unknown property } else if (err.code === 'EACCES') { throw new Error(`'${executableFile}' not executable`); From 8762e4421f24042f63abbd7d2dc02ff4cdce2abc Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 6 Dec 2024 13:17:21 +1300 Subject: [PATCH 2/9] Disable failing tests on Windows --- .../command.executableSubcommand.mock.test.js | 144 ++++++++++-------- 1 file changed, 79 insertions(+), 65 deletions(-) diff --git a/tests/command.executableSubcommand.mock.test.js b/tests/command.executableSubcommand.mock.test.js index 460cbb1b8..2510ad4b0 100644 --- a/tests/command.executableSubcommand.mock.test.js +++ b/tests/command.executableSubcommand.mock.test.js @@ -12,76 +12,90 @@ function makeSystemError(code) { return err; } -test('when subcommand executable missing (ENOENT) then throw custom message', () => { - // If the command is not found, we show a custom error with an explanation and offer - // some advice for possible fixes. - const mockProcess = new EventEmitter(); - const spawnSpy = jest.spyOn(childProcess, 'spawn').mockImplementation(() => { - return mockProcess; - }); - const program = new commander.Command(); - program.exitOverride(); - program.command('executable', 'executable description'); - program.parse(['executable'], { from: 'user' }); - expect(() => { - mockProcess.emit('error', makeSystemError('ENOENT')); - }).toThrow('use the executableFile option to supply a custom name'); // part of custom message - spawnSpy.mockRestore(); -}); +// These tests are either not relevant to Windows, or don't failure in same way because fail early for missing executable. +const describeOrSkipOnWindows = + process.platform === 'win32' ? describe.skip : describe; -test('when subcommand executable not executable (EACCES) then throw custom message', () => { - // Side note: this error does not actually happen on Windows! But we can still simulate the behaviour on other platforms. - const mockProcess = new EventEmitter(); - const spawnSpy = jest.spyOn(childProcess, 'spawn').mockImplementation(() => { - return mockProcess; +describeOrSkipOnWindows('executable Subcommand failure modes', () => { + test('when subcommand executable missing (ENOENT) then throw custom message', () => { + // If the command is not found, we show a custom error with an explanation and offer + // some advice for possible fixes. + const mockProcess = new EventEmitter(); + const spawnSpy = jest + .spyOn(childProcess, 'spawn') + .mockImplementation(() => { + return mockProcess; + }); + const program = new commander.Command(); + program.exitOverride(); + program.command('executable', 'executable description'); + program.parse(['executable'], { from: 'user' }); + expect(() => { + mockProcess.emit('error', makeSystemError('ENOENT')); + }).toThrow('use the executableFile option to supply a custom name'); // part of custom message + spawnSpy.mockRestore(); }); - const program = new commander.Command(); - program.exitOverride(); - program.command('executable', 'executable description'); - program.parse(['executable'], { from: 'user' }); - expect(() => { - mockProcess.emit('error', makeSystemError('EACCES')); - }).toThrow('not executable'); // part of custom message - spawnSpy.mockRestore(); -}); -test('when subcommand executable fails with other error and exitOverride then return in custom wrapper', () => { - // The existing behaviour is to just silently fail for unexpected errors, as it is happening - // asynchronously in spawned process and client can not catch errors. - const mockProcess = new EventEmitter(); - const spawnSpy = jest.spyOn(childProcess, 'spawn').mockImplementation(() => { - return mockProcess; + test('when subcommand executable not executable (EACCES) then throw custom message', () => { + // Side note: this error does not actually happen on Windows! But we can still simulate the behaviour on other platforms. + const mockProcess = new EventEmitter(); + const spawnSpy = jest + .spyOn(childProcess, 'spawn') + .mockImplementation(() => { + return mockProcess; + }); + const program = new commander.Command(); + program.exitOverride(); + program.command('executable', 'executable description'); + program.parse(['executable'], { from: 'user' }); + expect(() => { + mockProcess.emit('error', makeSystemError('EACCES')); + }).toThrow('not executable'); // part of custom message + spawnSpy.mockRestore(); }); - const program = new commander.Command(); - program.exitOverride((err) => { - throw err; + + test('when subcommand executable fails with other error and exitOverride then return in custom wrapper', () => { + // The existing behaviour is to just silently fail for unexpected errors, as it is happening + // asynchronously in spawned process and client can not catch errors. + const mockProcess = new EventEmitter(); + const spawnSpy = jest + .spyOn(childProcess, 'spawn') + .mockImplementation(() => { + return mockProcess; + }); + const program = new commander.Command(); + program.exitOverride((err) => { + throw err; + }); + program.command('executable', 'executable description'); + program.parse(['executable'], { from: 'user' }); + let caughtErr; + try { + mockProcess.emit('error', makeSystemError('OTHER')); + } catch (err) { + caughtErr = err; + } + expect(caughtErr.code).toEqual('commander.executeSubCommandAsync'); + expect(caughtErr.nestedError.code).toEqual('OTHER'); + spawnSpy.mockRestore(); }); - program.command('executable', 'executable description'); - program.parse(['executable'], { from: 'user' }); - let caughtErr; - try { - mockProcess.emit('error', makeSystemError('OTHER')); - } catch (err) { - caughtErr = err; - } - expect(caughtErr.code).toEqual('commander.executeSubCommandAsync'); - expect(caughtErr.nestedError.code).toEqual('OTHER'); - spawnSpy.mockRestore(); -}); -test('when subcommand executable fails with other error then exit', () => { - // The existing behaviour is to just silently fail for unexpected errors, as it is happening - // asynchronously in spawned process and client can not catch errors. - const mockProcess = new EventEmitter(); - const spawnSpy = jest.spyOn(childProcess, 'spawn').mockImplementation(() => { - return mockProcess; + test('when subcommand executable fails with other error then exit', () => { + // The existing behaviour is to just silently fail for unexpected errors, as it is happening + // asynchronously in spawned process and client can not catch errors. + const mockProcess = new EventEmitter(); + const spawnSpy = jest + .spyOn(childProcess, 'spawn') + .mockImplementation(() => { + return mockProcess; + }); + const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); + const program = new commander.Command(); + program.command('executable', 'executable description'); + program.parse(['executable'], { from: 'user' }); + mockProcess.emit('error', makeSystemError('OTHER')); + expect(exitSpy).toHaveBeenCalledWith(1); + exitSpy.mockRestore(); + spawnSpy.mockRestore(); }); - const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); - const program = new commander.Command(); - program.command('executable', 'executable description'); - program.parse(['executable'], { from: 'user' }); - mockProcess.emit('error', makeSystemError('OTHER')); - expect(exitSpy).toHaveBeenCalledWith(1); - exitSpy.mockRestore(); - spawnSpy.mockRestore(); }); From c28b860015a5538f5bf342dfadfe649bcef9698c Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 6 Dec 2024 13:19:33 +1300 Subject: [PATCH 3/9] Use similar early failure checking on non-Windows as Windows --- lib/command.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/command.js b/lib/command.js index 77df60c1c..155f33c2d 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1179,6 +1179,7 @@ Expecting one of '${allowedValues.join("', '")}'`); let proc; if (process.platform !== 'win32') { if (launchWithNode) { + if (!fs.existsSync(executableFile)) throwMissingExecutable(); args.unshift(executableFile); // add executable arguments to spawn args = incrementNodeInspectorPort(process.execArgv).concat(args); From a44c30e9a06bb2996c06c77cddd259c7d07af394 Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 6 Dec 2024 13:36:29 +1300 Subject: [PATCH 4/9] Skip broken tests on Windows --- tests/command.executableSubcommand.search.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/command.executableSubcommand.search.test.js b/tests/command.executableSubcommand.search.test.js index a2ebdaf4a..40f25edc1 100644 --- a/tests/command.executableSubcommand.search.test.js +++ b/tests/command.executableSubcommand.search.test.js @@ -50,7 +50,8 @@ describe('search for subcommand', () => { spawnSpy.mockRestore(); }); - describe('whether perform search for local files', () => { + // fs.existsSync gets called on Windows outside the search, so skip the tests (or come up with a different way of checking). + describeOrSkipOnWindows('whether perform search for local files', () => { beforeEach(() => { existsSpy.mockImplementation(() => false); }); From 9dfaf0926939c08f4c88d78b6513713b82c4ad0c Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 6 Dec 2024 14:12:49 +1300 Subject: [PATCH 5/9] Another try at co-existing with unit tests! --- lib/command.js | 42 +++++--- .../command.executableSubcommand.mock.test.js | 101 +++++++++--------- ...ommand.executableSubcommand.search.test.js | 5 +- 3 files changed, 84 insertions(+), 64 deletions(-) diff --git a/lib/command.js b/lib/command.js index 155f33c2d..2020e6c33 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1094,6 +1094,24 @@ Expecting one of '${allowedValues.join("', '")}'`); return this; } + /** + * Note: masked in some unit tests. + * @param {string} executableFile + * @param {string} executableDir + * @param {string} subcommandName + */ + _throwForMissingExecutable(executableFile, executableDir, subcommandName) { + if (fs.existsSync(executableFile)) return; + const executableDirMessage = executableDir + ? `searched for local subcommand relative to directory '${executableDir}'` + : 'no directory for search for local subcommand, use .executableDir() to supply a custom directory'; + const executableMissing = `'${executableFile}' does not exist + - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead + - if the default executable name is not suitable, use the executableFile option to supply a custom name or path + - ${executableDirMessage}`; + throw new Error(executableMissing); + } + /** * Execute a sub-command executable. * @@ -1165,21 +1183,9 @@ Expecting one of '${allowedValues.join("', '")}'`); launchWithNode = sourceExt.includes(path.extname(executableFile)); - function throwMissingExecutable() { - const executableDirMessage = executableDir - ? `searched for local subcommand relative to directory '${executableDir}'` - : 'no directory for search for local subcommand, use .executableDir() to supply a custom directory'; - const executableMissing = `'${executableFile}' does not exist - - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead - - if the default executable name is not suitable, use the executableFile option to supply a custom name or path - - ${executableDirMessage}`; - throw new Error(executableMissing); - } - let proc; if (process.platform !== 'win32') { if (launchWithNode) { - if (!fs.existsSync(executableFile)) throwMissingExecutable(); args.unshift(executableFile); // add executable arguments to spawn args = incrementNodeInspectorPort(process.execArgv).concat(args); @@ -1189,7 +1195,11 @@ Expecting one of '${allowedValues.join("', '")}'`); proc = childProcess.spawn(executableFile, args, { stdio: 'inherit' }); } } else { - if (!fs.existsSync(executableFile)) throwMissingExecutable(); + this._throwForMissingExecutable( + executableFile, + executableDir, + subcommand._name, + ); args.unshift(executableFile); // add executable arguments to spawn args = incrementNodeInspectorPort(process.execArgv).concat(args); @@ -1228,7 +1238,11 @@ Expecting one of '${allowedValues.join("', '")}'`); proc.on('error', (err) => { // @ts-ignore: because err.code is an unknown property if (err.code === 'ENOENT') { - throwMissingExecutable(); + this._throwForMissingExecutable( + executableFile, + executableDir, + subcommand._name, + ); // @ts-ignore: because err.code is an unknown property } else if (err.code === 'EACCES') { throw new Error(`'${executableFile}' not executable`); diff --git a/tests/command.executableSubcommand.mock.test.js b/tests/command.executableSubcommand.mock.test.js index 2510ad4b0..1297040e6 100644 --- a/tests/command.executableSubcommand.mock.test.js +++ b/tests/command.executableSubcommand.mock.test.js @@ -12,12 +12,14 @@ function makeSystemError(code) { return err; } -// These tests are either not relevant to Windows, or don't failure in same way because fail early for missing executable. -const describeOrSkipOnWindows = - process.platform === 'win32' ? describe.skip : describe; +// Suppress false positive warnings due to use of testOrSkipOnWindows +/* eslint-disable jest/no-standalone-expect */ -describeOrSkipOnWindows('executable Subcommand failure modes', () => { - test('when subcommand executable missing (ENOENT) then throw custom message', () => { +const testOrSkipOnWindows = process.platform === 'win32' ? test.skip : test; + +testOrSkipOnWindows( + 'when subcommand executable missing (ENOENT) then throw custom message', + () => { // If the command is not found, we show a custom error with an explanation and offer // some advice for possible fixes. const mockProcess = new EventEmitter(); @@ -34,9 +36,12 @@ describeOrSkipOnWindows('executable Subcommand failure modes', () => { mockProcess.emit('error', makeSystemError('ENOENT')); }).toThrow('use the executableFile option to supply a custom name'); // part of custom message spawnSpy.mockRestore(); - }); + }, +); - test('when subcommand executable not executable (EACCES) then throw custom message', () => { +testOrSkipOnWindows( + 'when subcommand executable not executable (EACCES) then throw custom message', + () => { // Side note: this error does not actually happen on Windows! But we can still simulate the behaviour on other platforms. const mockProcess = new EventEmitter(); const spawnSpy = jest @@ -52,50 +57,48 @@ describeOrSkipOnWindows('executable Subcommand failure modes', () => { mockProcess.emit('error', makeSystemError('EACCES')); }).toThrow('not executable'); // part of custom message spawnSpy.mockRestore(); - }); + }, +); - test('when subcommand executable fails with other error and exitOverride then return in custom wrapper', () => { - // The existing behaviour is to just silently fail for unexpected errors, as it is happening - // asynchronously in spawned process and client can not catch errors. - const mockProcess = new EventEmitter(); - const spawnSpy = jest - .spyOn(childProcess, 'spawn') - .mockImplementation(() => { - return mockProcess; - }); - const program = new commander.Command(); - program.exitOverride((err) => { - throw err; - }); - program.command('executable', 'executable description'); - program.parse(['executable'], { from: 'user' }); - let caughtErr; - try { - mockProcess.emit('error', makeSystemError('OTHER')); - } catch (err) { - caughtErr = err; - } - expect(caughtErr.code).toEqual('commander.executeSubCommandAsync'); - expect(caughtErr.nestedError.code).toEqual('OTHER'); - spawnSpy.mockRestore(); +test('when subcommand executable fails with other error and exitOverride then return in custom wrapper', () => { + // The existing behaviour is to just silently fail for unexpected errors, as it is happening + // asynchronously in spawned process and client can not catch errors. + const mockProcess = new EventEmitter(); + const spawnSpy = jest.spyOn(childProcess, 'spawn').mockImplementation(() => { + return mockProcess; }); - - test('when subcommand executable fails with other error then exit', () => { - // The existing behaviour is to just silently fail for unexpected errors, as it is happening - // asynchronously in spawned process and client can not catch errors. - const mockProcess = new EventEmitter(); - const spawnSpy = jest - .spyOn(childProcess, 'spawn') - .mockImplementation(() => { - return mockProcess; - }); - const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); - const program = new commander.Command(); - program.command('executable', 'executable description'); - program.parse(['executable'], { from: 'user' }); + const program = new commander.Command(); + program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program.exitOverride((err) => { + throw err; + }); + program.command('executable', 'executable description'); + program.parse(['executable'], { from: 'user' }); + let caughtErr; + try { mockProcess.emit('error', makeSystemError('OTHER')); - expect(exitSpy).toHaveBeenCalledWith(1); - exitSpy.mockRestore(); - spawnSpy.mockRestore(); + } catch (err) { + caughtErr = err; + } + expect(caughtErr.code).toEqual('commander.executeSubCommandAsync'); + expect(caughtErr.nestedError.code).toEqual('OTHER'); + spawnSpy.mockRestore(); +}); + +test('when subcommand executable fails with other error then exit', () => { + // The existing behaviour is to just silently fail for unexpected errors, as it is happening + // asynchronously in spawned process and client can not catch errors. + const mockProcess = new EventEmitter(); + const spawnSpy = jest.spyOn(childProcess, 'spawn').mockImplementation(() => { + return mockProcess; }); + const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); + const program = new commander.Command(); + program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program.command('executable', 'executable description'); + program.parse(['executable'], { from: 'user' }); + mockProcess.emit('error', makeSystemError('OTHER')); + expect(exitSpy).toHaveBeenCalledWith(1); + exitSpy.mockRestore(); + spawnSpy.mockRestore(); }); diff --git a/tests/command.executableSubcommand.search.test.js b/tests/command.executableSubcommand.search.test.js index 40f25edc1..3c2c5eaab 100644 --- a/tests/command.executableSubcommand.search.test.js +++ b/tests/command.executableSubcommand.search.test.js @@ -51,13 +51,14 @@ describe('search for subcommand', () => { }); // fs.existsSync gets called on Windows outside the search, so skip the tests (or come up with a different way of checking). - describeOrSkipOnWindows('whether perform search for local files', () => { + describe('whether perform search for local files', () => { beforeEach(() => { existsSpy.mockImplementation(() => false); }); test('when no script arg or executableDir then no search for local file', () => { const program = new commander.Command(); + program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn program.name('pm'); program.command('sub', 'executable description'); program.parse(['sub'], { from: 'user' }); @@ -67,6 +68,7 @@ describe('search for subcommand', () => { test('when script arg then search for local files', () => { const program = new commander.Command(); + program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn program.name('pm'); program.command('sub', 'executable description'); program.parse(['node', 'script-name', 'sub']); @@ -76,6 +78,7 @@ describe('search for subcommand', () => { test('when executableDir then search for local files)', () => { const program = new commander.Command(); + program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn program.name('pm'); program.executableDir(__dirname); program.command('sub', 'executable description'); From 5202eb3f81e77019b3cdd083384d0b59a79b5607 Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 6 Dec 2024 14:18:25 +1300 Subject: [PATCH 6/9] Suppress file check in one more place --- tests/command.executableSubcommand.search.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/command.executableSubcommand.search.test.js b/tests/command.executableSubcommand.search.test.js index 3c2c5eaab..1918bb139 100644 --- a/tests/command.executableSubcommand.search.test.js +++ b/tests/command.executableSubcommand.search.test.js @@ -305,6 +305,7 @@ describe('search for subcommand', () => { test('when script arg then search for local script-sub.js, .ts, .tsx, .mpjs, .cjs', () => { existsSpy.mockImplementation((path) => false); const program = new commander.Command(); + program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn program.command('sub', 'executable description'); const scriptPath = path.resolve(gLocalDirectory, 'script'); program.parse(['node', scriptPath, 'sub']); From c526b8d2772c8f5c200c16d68d89644a274d8061 Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 6 Dec 2024 14:43:26 +1300 Subject: [PATCH 7/9] Remove stale comment --- tests/command.executableSubcommand.mock.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/command.executableSubcommand.mock.test.js b/tests/command.executableSubcommand.mock.test.js index 1297040e6..03d439d39 100644 --- a/tests/command.executableSubcommand.mock.test.js +++ b/tests/command.executableSubcommand.mock.test.js @@ -42,7 +42,6 @@ testOrSkipOnWindows( testOrSkipOnWindows( 'when subcommand executable not executable (EACCES) then throw custom message', () => { - // Side note: this error does not actually happen on Windows! But we can still simulate the behaviour on other platforms. const mockProcess = new EventEmitter(); const spawnSpy = jest .spyOn(childProcess, 'spawn') From e47c492a97bc5a67da7dfa8d68e412232abd52e0 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 7 Dec 2024 09:02:55 +1300 Subject: [PATCH 8/9] Make method name more consistent --- lib/command.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/command.js b/lib/command.js index 2020e6c33..735a7cb4e 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1095,13 +1095,15 @@ Expecting one of '${allowedValues.join("', '")}'`); } /** - * Note: masked in some unit tests. + * Throw if expected executable is missing. Add lots of help for author. + * * @param {string} executableFile * @param {string} executableDir * @param {string} subcommandName */ - _throwForMissingExecutable(executableFile, executableDir, subcommandName) { + _checkForMissingExecutable(executableFile, executableDir, subcommandName) { if (fs.existsSync(executableFile)) return; + const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : 'no directory for search for local subcommand, use .executableDir() to supply a custom directory'; @@ -1195,7 +1197,7 @@ Expecting one of '${allowedValues.join("', '")}'`); proc = childProcess.spawn(executableFile, args, { stdio: 'inherit' }); } } else { - this._throwForMissingExecutable( + this._checkForMissingExecutable( executableFile, executableDir, subcommand._name, @@ -1238,7 +1240,7 @@ Expecting one of '${allowedValues.join("', '")}'`); proc.on('error', (err) => { // @ts-ignore: because err.code is an unknown property if (err.code === 'ENOENT') { - this._throwForMissingExecutable( + this._checkForMissingExecutable( executableFile, executableDir, subcommand._name, From 709168c2b16d83d075913d449e5747704840e3f6 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 7 Dec 2024 09:06:39 +1300 Subject: [PATCH 9/9] Update method name --- tests/command.executableSubcommand.mock.test.js | 4 ++-- tests/command.executableSubcommand.search.test.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/command.executableSubcommand.mock.test.js b/tests/command.executableSubcommand.mock.test.js index 03d439d39..4c80d58ef 100644 --- a/tests/command.executableSubcommand.mock.test.js +++ b/tests/command.executableSubcommand.mock.test.js @@ -67,7 +67,7 @@ test('when subcommand executable fails with other error and exitOverride then re return mockProcess; }); const program = new commander.Command(); - program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program._checkForMissingExecutable = () => {}; // suppress error, call mocked spawn program.exitOverride((err) => { throw err; }); @@ -93,7 +93,7 @@ test('when subcommand executable fails with other error then exit', () => { }); const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); const program = new commander.Command(); - program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program._checkForMissingExecutable = () => {}; // suppress error, call mocked spawn program.command('executable', 'executable description'); program.parse(['executable'], { from: 'user' }); mockProcess.emit('error', makeSystemError('OTHER')); diff --git a/tests/command.executableSubcommand.search.test.js b/tests/command.executableSubcommand.search.test.js index 1918bb139..96a1302ff 100644 --- a/tests/command.executableSubcommand.search.test.js +++ b/tests/command.executableSubcommand.search.test.js @@ -58,7 +58,7 @@ describe('search for subcommand', () => { test('when no script arg or executableDir then no search for local file', () => { const program = new commander.Command(); - program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program._checkForMissingExecutable = () => {}; // suppress error, call mocked spawn program.name('pm'); program.command('sub', 'executable description'); program.parse(['sub'], { from: 'user' }); @@ -68,7 +68,7 @@ describe('search for subcommand', () => { test('when script arg then search for local files', () => { const program = new commander.Command(); - program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program._checkForMissingExecutable = () => {}; // suppress error, call mocked spawn program.name('pm'); program.command('sub', 'executable description'); program.parse(['node', 'script-name', 'sub']); @@ -78,7 +78,7 @@ describe('search for subcommand', () => { test('when executableDir then search for local files)', () => { const program = new commander.Command(); - program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program._checkForMissingExecutable = () => {}; // suppress error, call mocked spawn program.name('pm'); program.executableDir(__dirname); program.command('sub', 'executable description'); @@ -305,7 +305,7 @@ describe('search for subcommand', () => { test('when script arg then search for local script-sub.js, .ts, .tsx, .mpjs, .cjs', () => { existsSpy.mockImplementation((path) => false); const program = new commander.Command(); - program._throwForMissingExecutable = () => {}; // suppress error, call mocked spawn + program._checkForMissingExecutable = () => {}; // suppress error, call mocked spawn program.command('sub', 'executable description'); const scriptPath = path.resolve(gLocalDirectory, 'script'); program.parse(['node', scriptPath, 'sub']);