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

Revert tty behavior for inquirer 7.x #903

Merged
merged 3 commits into from
Mar 10, 2020
Merged
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
7 changes: 6 additions & 1 deletion packages/inquirer/lib/inquirer.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ inquirer.ui = {
*/
inquirer.createPromptModule = function(opt) {
var promptModule = function(questions) {
var ui = new inquirer.ui.Prompt(promptModule.prompts, opt);
var ui;
try {
ui = new inquirer.ui.Prompt(promptModule.prompts, opt);
} catch (error) {
return Promise.reject(error);
}
var promise = ui.run(questions);

// Monkey patch the UI on the promise object so
Expand Down
13 changes: 13 additions & 0 deletions packages/inquirer/lib/ui/baseUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,23 @@ class UI {

function setupReadlineOptions(opt) {
opt = opt || {};
// Inquirer 8.x:
// opt.skipTTYChecks = opt.skipTTYChecks === undefined ? opt.input !== undefined : opt.skipTTYChecks;
mshima marked this conversation as resolved.
Show resolved Hide resolved
opt.skipTTYChecks = opt.skipTTYChecks === undefined ? true : opt.skipTTYChecks;

// Default `input` to stdin
var input = opt.input || process.stdin;

// Check if prompt is being called in TTY environment
// If it isn't return a failed promise
if (!opt.skipTTYChecks && !input.isTTY) {
const nonTtyError = new Error(
'Prompts can not be meaningfully rendered in non-TTY environments'
);
nonTtyError.isTtyError = true;
throw nonTtyError;
}

// Add mute capabilities to the output
var ms = new MuteStream();
ms.pipe(opt.output || process.stdout);
Expand Down
10 changes: 0 additions & 10 deletions packages/inquirer/lib/ui/prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,6 @@ class PromptUI extends Base {
}

fetchAnswer(question) {
// Check if prompt is being called in TTY environment
// If it isn't return a failed promise
if (!process.stdin.isTTY) {
const nonTtyError = new Error(
'Prompts can not be meaningfully rendered in non-TTY environments'
);
nonTtyError.isTtyError = true;
return Promise.reject(nonTtyError);
}

var Prompt = this.prompts[question.type];
this.activePrompt = new Prompt(question, this.rl, this.answers);
return defer(() =>
Expand Down
134 changes: 128 additions & 6 deletions packages/inquirer/test/specs/inquirer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
* Inquirer public API test
*/

var fs = require('fs');
var stream = require('stream');
var tty = require('tty');
var expect = require('chai').expect;
var sinon = require('sinon');
var _ = require('lodash');
var { Observable } = require('rxjs');

var inquirer = require('../../lib/inquirer');
var autosubmit = require('../helpers/events').autosubmit;

Expand Down Expand Up @@ -687,7 +691,7 @@ describe('inquirer.prompt', function() {
});

it('Throw an exception when run in non-tty', function() {
var prompt = inquirer.createPromptModule();
var prompt = inquirer.createPromptModule({ skipTTYChecks: false });

var prompts = [
{
Expand All @@ -709,22 +713,140 @@ describe('inquirer.prompt', function() {
});
});

it('No exception when when flags non-tty', function() {
it("Don't throw an exception when run in non-tty by default", function(done) {
var prompt = inquirer.createPromptModule();
var prompts = [
{
type: 'confirm',
name: 'q1',
message: 'message'
},
{
type: 'confirm',
name: 'q2',
message: 'message'
}
];

var promise = prompt(prompts);
autosubmit(promise.ui);
promise
.then(() => {
done();
})
.catch(error => {
console.log(error);
expect(error.isTtyError).to.equal(false);
});
});

it("Don't throw an exception when run in non-tty and skipTTYChecks is true", function(done) {
var prompt = inquirer.createPromptModule({ skipTTYChecks: true });
var prompts = [
{
name: 'name',
message: 'give a name to your app',
type: 'confirm',
name: 'q1',
message: 'message'
},
{
type: 'confirm',
name: 'q2',
message: 'message'
}
];

var promise = prompt(prompts);
autosubmit(promise.ui);
promise
.then(() => {
done();
})
.catch(error => {
console.log(error);
expect(error.isTtyError).to.equal(false);
});
});

it("Don't throw an exception when run in non-tty and custom input is provided", function(done) {
var prompt = inquirer.createPromptModule({ input: new stream.Readable() });
var prompts = [
{
type: 'confirm',
name: 'q1',
message: 'message'
},
{
type: 'confirm',
name: 'q2',
message: 'message'
}
];

var promise = prompt(prompts);
autosubmit(promise.ui);
promise
.then(() => {
done();
})
.catch(error => {
console.log(error);
expect(error.isTtyError).to.equal(false);
});
});

it('Throw an exception when run in non-tty and custom input is provided with skipTTYChecks: false', function() {
var prompt = inquirer.createPromptModule({
input: new stream.Readable(),
skipTTYChecks: false
});

var prompts = [
{
type: 'confirm',
name: 'q1',
message: 'message'
}
];

var promise = prompt(prompts);

return promise
.then(() => {
// Failure
expect(true).to.equal(false);
})
.catch(error => {
expect(error.isTtyError).to.equal(true);
});
});

it('No exception when using tty other than process.stdin', function() {
// Manually opens a new tty
var input = new tty.ReadStream(fs.openSync('/dev/tty', 'r+'));

// Uses manually opened tty as input instead of process.stdin
var prompt = inquirer.createPromptModule({
input: input,
skipTTYChecks: false
});

var prompts = [
{
type: 'input',
name: 'q1',
default: 'foo',
when: () => false
message: 'message'
}
];

var promise = prompt(prompts);
promise.ui.rl.emit('line');

// Release the input tty socket
input.unref();

return promise.then(answers => {
expect(answers).to.deep.equal({});
expect(answers).to.deep.equal({ q1: 'foo' });
});
});
});
Expand Down