-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add mock tests to cover subcommand error handling (#1474)
- Loading branch information
1 parent
c119028
commit 948796d
Showing
1 changed file
with
64 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
const commander = require('../'); | ||
const childProcess = require('child_process'); | ||
const EventEmitter = require('events'); | ||
|
||
// Using mock to allow try/catch around what is otherwise out-of-stack error handling. | ||
// Injecting errors, these are not end-to-end tests. | ||
|
||
function makeSystemError(code) { | ||
// We can not make an actual SystemError, but our usage is lightweight so easy to match. | ||
const err = new Error(); | ||
err.code = 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(); | ||
}); | ||
|
||
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(); | ||
}); | ||
|
||
test('when subcommand executable fails with other error 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(); | ||
}); |