diff --git a/modules/setup.js b/modules/setup.js index 9735075..329ab03 100644 --- a/modules/setup.js +++ b/modules/setup.js @@ -31,11 +31,33 @@ export const setupOpts = new Map(); /** * abort setup * @param {string} msg - message + * @param {number} [code] - exit code * @returns {void} */ -export const abortSetup = msg => { +export const abortSetup = (msg, code) => { + setupOpts.clear(); console.info(`Setup aborted: ${msg}`); - process.exit(); + if (!Number.isInteger(code)) { + code = 1; + } + process.exit(code); +}; + +/** + * handle inquirer error + * @param {object} e - Error + * @throws + * @returns {Function} - abortSetup + */ +export const handleInquirerError = e => { + if (e instanceof Error) { + let code = 1; + if (e.name === 'ExitPromptError') { + code = 130; + } + return abortSetup(e.message, code); + } + return abortSetup('Unknown error.', 1); }; /** @@ -51,11 +73,11 @@ export const handleCmdArgsInput = async editorArgs => { const useCmdArgs = await inquirer.confirm({ message: 'Execute editor with command line options?', default: false - }); + }).catch(handleInquirerError); if (useCmdArgs) { const ans = await inquirer.input({ message: 'Input command line options:' - }); + }).catch(handleInquirerError); if (ans) { cmdArgs = new CmdArgs(ans.trim()).toArray(); } else { @@ -78,7 +100,7 @@ export const handleEditorPathInput = async editorFilePath => { editorFilePath = await inquirer.input({ message: 'Input editor path:', required: true - }); + }).catch(handleInquirerError); } let parsedPath = editorFilePath; if (/\$\{\w+\}|\$\w+/.test(editorFilePath)) { @@ -144,11 +166,11 @@ export const confirmOverwriteEditorConfig = async file => { const ans = await inquirer.confirm({ message: `${file} already exists. Overwrite?`, default: false - }); + }).catch(handleInquirerError); if (ans) { func = createEditorConfig(); } else { - func = abortSetup(`${file} already exists.`); + func = abortSetup(`${file} already exists.`, 1); } return func; }; diff --git a/test/setup.test.js b/test/setup.test.js index 4e71f2d..02fe27c 100644 --- a/test/setup.test.js +++ b/test/setup.test.js @@ -14,8 +14,8 @@ import { /* test */ import { abortSetup, confirmOverwriteEditorConfig, createEditorConfig, inquirer, - handleCmdArgsInput, handleEditorPathInput, handleSetupCallback, runSetup, - setupOpts + handleCmdArgsInput, handleEditorPathInput, handleInquirerError, + handleSetupCallback, runSetup, setupOpts } from '../modules/setup.js'; /* constants */ @@ -34,13 +34,86 @@ describe('abortSetup', () => { info = msg; }); const stubExit = sinon.stub(process, 'exit'); + const i = stubExit.withArgs(1).callCount; abortSetup('foo'); const { calledOnce: infoCalled } = stubInfo; - const { calledOnce: exitCalled } = stubExit; + const { callCount: exitCallCount } = stubExit; stubInfo.restore(); stubExit.restore(); - assert.isTrue(infoCalled); - assert.isTrue(exitCalled); + assert.strictEqual(infoCalled, true); + assert.strictEqual(exitCallCount, i + 1); + assert.strictEqual(info, 'Setup aborted: foo'); + }); + + it('should exit with message', () => { + let info; + const stubInfo = sinon.stub(console, 'info').callsFake(msg => { + info = msg; + }); + const stubExit = sinon.stub(process, 'exit'); + const i = stubExit.withArgs(2).callCount; + abortSetup('foo', 2); + const { calledOnce: infoCalled } = stubInfo; + const { callCount: exitCallCount } = stubExit; + stubInfo.restore(); + stubExit.restore(); + assert.strictEqual(infoCalled, true); + assert.strictEqual(exitCallCount, i + 1); + assert.strictEqual(info, 'Setup aborted: foo'); + }); +}); + +describe('handleInquirerError', () => { + it('should exit with unknown error message', () => { + let info; + const stubInfo = sinon.stub(console, 'info').callsFake(msg => { + info = msg; + }); + const stubExit = sinon.stub(process, 'exit'); + const i = stubExit.withArgs(1).callCount; + handleInquirerError('foo'); + const { calledOnce: infoCalled } = stubInfo; + const { callCount: exitCallCount } = stubExit; + stubInfo.restore(); + stubExit.restore(); + assert.strictEqual(infoCalled, true); + assert.strictEqual(exitCallCount, i + 1); + assert.strictEqual(info, 'Setup aborted: Unknown error.'); + }); + + it('should exit with message', () => { + let info; + const stubInfo = sinon.stub(console, 'info').callsFake(msg => { + info = msg; + }); + const stubExit = sinon.stub(process, 'exit'); + const i = stubExit.withArgs(1).callCount; + handleInquirerError(new Error('foo')); + const { calledOnce: infoCalled } = stubInfo; + const { callCount: exitCallCount } = stubExit; + stubInfo.restore(); + stubExit.restore(); + assert.strictEqual(infoCalled, true); + assert.strictEqual(exitCallCount, i + 1); + assert.strictEqual(info, 'Setup aborted: foo'); + }); + + it('should exit with message', () => { + let info; + const stubInfo = sinon.stub(console, 'info').callsFake(msg => { + info = msg; + }); + const stubExit = sinon.stub(process, 'exit'); + const i = stubExit.withArgs(130).callCount; + const e = new Error('foo'); + e.name = 'ExitPromptError'; + handleInquirerError(e); + const { calledOnce: infoCalled } = stubInfo; + const { callCount: exitCallCount } = stubExit; + stubInfo.restore(); + stubExit.restore(); + assert.strictEqual(infoCalled, true); + assert.strictEqual(exitCallCount, i + 1); assert.strictEqual(info, 'Setup aborted: foo'); }); }); @@ -485,7 +558,7 @@ describe('handleSetupCallback', () => { const { calledOnce: exitCalled } = stubExit; stubInfo.restore(); stubExit.restore(); - assert.strictEqual(setupOpts.get('configPath'), configDirPath); + assert.strictEqual(setupOpts.has('configPath'), false); assert.strictEqual(stubRl.callCount, i); assert.isTrue(stubConfirm.calledOnce); assert.isTrue(infoCalled);