Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(interactive-mode): Added option to enable support of inquirer plugins #28

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,26 @@ yargsInteractive()
```
➜ node my-cli.js --name='Johh' --likesPizza
```

### Inquirer plugins support

Inquirer plugins support must be opt-in by setting `allowInquirerPlugins` to `true` in the interactive mode options:

```js
const options = {
interactive: {
allowInquirerPlugins: true,
default: true,
},
...
};

yargsInteractive()
.usage('$0 <command> [args]')
.interactive(options)
.then((result) => {
// The tool will prompt questions and will output your answers.
// TODO: Do something with the result (e.g result.name)
console.log(result)
});
```
11 changes: 9 additions & 2 deletions src/interactive-mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ const inquirer = require('inquirer');
/**
* Initiate an interactive prompt to get values from the user.
* @param {object} values The values to configure the prompt
* @param {object} inquirerOptions Payload encapsulating runtime configuration options for inquirer, mainly "allowInquirerPlugins", which enables support of inquirer plugins
* @return {object} A promise that, when fullfilled, will contain answer of the questions prompted to the user
*/
module.exports = (values = {}) => {
const prompt = inquirer.createPromptModule();
module.exports = (values = {}, inquirerOptions = {}) => {
const questions = Object.keys(values).map((key) => {
const value = values[key];
return Object.assign({}, value, {
Expand All @@ -17,5 +17,12 @@ module.exports = (values = {}) => {
});
});

if (inquirerOptions.allowInquirerPlugins) {
return inquirer.prompt(questions);
}

// https://github.com/SBoudrias/Inquirer.js#inquirercreatepromptmodule---prompt-function
const prompt = inquirer.createPromptModule();

return prompt(questions);
};
7 changes: 6 additions & 1 deletion src/yargs-interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,13 @@ const yargsInteractive = (processArgs = process.argv.slice(2), cwd) => {
return isEmpty(argv[key]) && isEmpty(item.default);
});

// Assess self-contained mode -- Wheteher to create a self contained inquirer module or allow other libraries to be usable.
const inquirerOptions = {
allowInquirerPlugins: !!(options.interactive && options.interactive.allowInquirerPlugins)
};

// Check if we should get the values from the interactive mode
return argv.interactive ? interactiveMode(interactiveOptions).then((result) => Object.assign({}, argv, result)) : Promise.resolve(argv);
return argv.interactive ? interactiveMode(interactiveOptions, inquirerOptions).then((result) => Object.assign({}, argv, result)) : Promise.resolve(argv);
};

return yargsConfig;
Expand Down
80 changes: 67 additions & 13 deletions test/interactive-mode.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,40 @@ const inquirer = require('inquirer');
const interactiveMode = require('../src/interactive-mode');

describe('interactive-mode', () => {
let inquirerCreatePromptModuleStub;
let inquirerPromptStub;
let stubCreatePrompt;
let stubPrompt;
let stubSelfContainedPrompt;
let values;

beforeAll(() => {
inquirerPromptStub = jest.fn();
inquirerCreatePromptModuleStub = jest.spyOn(inquirer, 'createPromptModule').mockReturnValue(inquirerPromptStub);
stubSelfContainedPrompt = jest.fn();
stubCreatePrompt = jest.spyOn(inquirer, 'createPromptModule').mockReturnValue(stubSelfContainedPrompt);
stubPrompt = jest.spyOn(inquirer, 'prompt').mockResolvedValue({});
});

describe('with no values', () => {
beforeAll(() => {
jest.clearAllMocks();
values = undefined;
interactiveMode(values);
});

test('should call createPromptModule', () => {
expect(inquirerCreatePromptModuleStub).toHaveBeenCalled();
test('should call inquirer.createPromptModule() method', () => {
expect(stubCreatePrompt).toHaveBeenCalled();
});

test('should call prompt', () => {
expect(inquirerPromptStub).toHaveBeenCalled();
test('should call prompt() of created module', () => {
expect(stubSelfContainedPrompt).toHaveBeenCalled();
});

test('should NOT default inquirer.prompt() method', () => {
expect(stubPrompt).not.toHaveBeenCalled();
});
});

describe('with values', () => {
beforeAll(() => {
jest.clearAllMocks();
values = {
title: {
type: 'input',
Expand All @@ -43,16 +51,62 @@ describe('interactive-mode', () => {
interactiveMode(values);
});

test('should call createPromptModule', () => {
expect(inquirerCreatePromptModuleStub).toHaveBeenCalled();
test('should call inquirer.createPromptModule() method', () => {
expect(stubCreatePrompt).toHaveBeenCalled();
});

test('should call prompt() of created module', () => {
expect(stubSelfContainedPrompt).toHaveBeenCalled();
});

test('should NOT default inquirer.prompt() method', () => {
expect(stubPrompt).not.toHaveBeenCalled();
});

test('should properly transform the values to inquirer values', () => {
const args = stubSelfContainedPrompt.mock.calls[0][0];
expect(args.length).toEqual(Object.keys(values).length);

args.forEach((question) => {
const inputValues = values[question.name];
expect(inputValues).toBeTruthy();
expect(question.type).toBe(inputValues.type);
expect(question.message).toBe(inputValues.describe);
expect(question.default).toBe(inputValues.default);
expect(question.choices).toBe(inputValues.choices);
});
});
});

describe('with support of inquirer plugins', () => {
beforeAll(() => {
jest.clearAllMocks();
values = {
title: {
type: 'input',
describe: 'Do you like plugins?',
default: 'Who does not?',
},
};
interactiveMode(values, {
allowInquirerPlugins: true,
});
});

test('should NOT call inquirer.createPromptModule() method', () => {
expect(stubCreatePrompt).not.toHaveBeenCalled();
});

test('should NOT call prompt() of created module', () => {
expect(stubSelfContainedPrompt).not.toHaveBeenCalled();
});

test('should call prompt', () => {
expect(inquirerPromptStub).toHaveBeenCalled();
test('should default inquirer.prompt() method', () => {
expect(stubPrompt).toHaveBeenCalled();
});

test('should properly transform the values to inquirer values', () => {
const args = inquirerPromptStub.mock.calls[1][0];
const args = stubPrompt.mock.calls[0][0];
expect(args.length).toEqual(Object.keys(values).length);

args.forEach((question) => {
Expand Down