blob: 22e26bc4d575c14672593114e786a8446839c376 [file] [log] [blame]
/*
* prompt-test.js: Tests for prompt.
*
* (C) 2010, Nodejitsu Inc.
*
*/
var assert = require('assert'),
vows = require('vows'),
prompt = require('../lib/prompt'),
helpers = require('./helpers'),
macros = require('./macros'),
schema = helpers.schema;
// A helper to pass fragments of our schema into prompt as full schemas.
function grab () {
var names = [].slice.call(arguments),
complete = { schema: {} };
names.forEach(function (name) {
complete.path = [name],
complete.schema = schema.properties[name];
});
return complete;
};
//
// Reset the prompt for mock testing
//
prompt.started = false;
prompt.start({
stdin: helpers.stdin,
stdout: helpers.stdout
});
vows.describe('prompt').addBatch({
"When using prompt": {
"the getInput() method": {
"with a simple string prompt": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
})
prompt.getInput('test input', this.callback);
helpers.stdin.writeNextTick('test value\n');
},
"should prompt to stdout and respond with data": function (err, input) {
assert.isNull(err);
assert.equal(input, 'test value');
assert.isTrue(this.msg.indexOf('test input') !== -1);
}
},
}
}
}).addBatch({
"When using prompt": {
"the getInput() method": {
"with any field that is not supposed to be empty": {
"and we don't provide any input": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
helpers.stderr.once('data', function (msg) {
that.errmsg = msg;
});
prompt.getInput(grab('notblank'), function () {});
prompt.once('invalid', this.callback.bind(null, null))
helpers.stdin.writeNextTick('\n');
},
"should prompt with an error": function (_, prop, input) {
assert.isObject(prop);
assert.equal(input, '');
assert.isTrue(this.errmsg.indexOf('Invalid input') !== -1);
assert.isTrue(this.msg.indexOf('notblank') !== -1);
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the getInput() method": {
"with a hidden field that is not supposed to be empty": {
"and we provide valid input": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
prompt.getInput('password', this.callback);
helpers.stdin.writeNextTick('trustno1\n');
},
"should prompt to stdout and respond with data": function (err, input) {
assert.isNull(err);
assert.equal(input, 'trustno1');
assert.isTrue(this.msg.indexOf('password') !== -1);
}
},
}
}
}
}).addBatch({
"When using prompt": {
"the getInput() method": {
"with a hidden field that is not supposed to be empty": {
"and we don't provide an input": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
helpers.stderr.once('data', function (msg) {
that.errmsg = msg;
});
prompt.getInput(grab('password'), function () {} );
prompt.once('invalid', this.callback.bind(null, null))
helpers.stdin.writeNextTick('\n');
},
"should prompt with an error": function (ign, prop, input) {
assert.isObject(prop);
assert.equal(input, '');
assert.isTrue(this.errmsg.indexOf('Invalid input') !== -1);
assert.isTrue(this.msg.indexOf('password') !== -1);
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the getInput() method": {
"with a complex property prompt": {
"and a valid input": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
prompt.getInput(grab('username'), this.callback);
helpers.stdin.writeNextTick('some-user\n');
},
"should prompt to stdout and respond with data": function (err, input) {
assert.isNull(err);
assert.equal(input, 'some-user');
assert.isTrue(this.msg.indexOf('username') !== -1);
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the getInput() method": {
"with a complex property prompt": {
"and an invalid input": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
helpers.stderr.once('data', function (msg) {
that.errmsg = msg;
})
prompt.getInput(grab('username'), this.callback);
prompt.once('invalid', function () {
prompt.once('prompt', function () {
process.nextTick(function () {
helpers.stdin.writeNextTick('some-user\n');
})
})
});
helpers.stdin.writeNextTick('some -user\n');
},
"should prompt with an error before completing the operation": function (err, input) {
assert.isNull(err);
assert.equal(input, 'some-user');
assert.isTrue(this.errmsg.indexOf('Invalid input') !== -1);
assert.isTrue(this.msg.indexOf('username') !== -1);
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the getInput() method": {
"with a complex property prompt": {
"with an invalid validator (array)": {
topic: function () {
var that = this,
called;
prompt.getInput(grab('badValidator'), function (err) {
if (!called) {
called = true;
that.callback(err);
}
});
helpers.stdin.writeNextTick('some-user\n');
},
"should respond with an error": function (err, ign) {
assert.isTrue(!!err);
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"with a simple string prompt": {
"that is not a property in prompt.properties": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
})
prompt.get('test input', this.callback);
helpers.stdin.writeNextTick('test value\n');
},
"should prompt to stdout and respond with the value": function (err, result) {
assert.isNull(err);
assert.include(result, 'test input');
assert.equal(result['test input'], 'test value');
assert.isTrue(this.msg.indexOf('test input') !== -1);
}
},
}
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"with a simple string prompt": {
"that is a property name in prompt.properties": {
"with a default value": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
prompt.properties.riffwabbles = schema.properties.riffwabbles;
prompt.get('riffwabbles', this.callback);
helpers.stdin.writeNextTick('\n');
},
"should prompt to stdout and respond with the default value": function (err, result) {
assert.isNull(err);
assert.isTrue(this.msg.indexOf('riffwabbles') !== -1);
assert.isTrue(this.msg.indexOf('(foobizzles)') !== -1);
assert.include(result, 'riffwabbles');
assert.equal(result['riffwabbles'], schema.properties['riffwabbles'].default);
}
},
}
}
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"with a simple string prompt": {
"that is a property name in prompt.properties": {
"that expects a numeric value": {
"and gets valid input": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
prompt.properties.number = schema.properties.number;
prompt.get('number', this.callback);
helpers.stdin.writeNextTick('15\n');
},
"should prompt to stdout and respond with a numeric value": function (err, result) {
assert.isNull(err);
assert.include(result, 'number');
assert.equal(result['number'], 15);
}
}
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"with a simple string prompt": {
"that is a property name in prompt.properties": {
"with a sync function validator (.validator)": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
prompt.get(helpers.schema.properties.fnvalidator, this.callback);
helpers.stdin.writeNextTick('fn123\n');
},
"should accept a value that is checked": function (err, result) {
assert.isNull(err);
assert.equal(result['fnvalidator'],'fn123');
}
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"with a simple string prompt": {
"that is a property name in prompt.properties": {
"with a sync function validator (.conform)": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
prompt.get(grab('fnconform'), this.callback);
helpers.stdin.writeNextTick('fn123\n');
},
"should accept a value that is checked": function (err, result) {
assert.isNull(err);
assert.equal(result['fnconform'],'fn123');
}
}
//
// Remark Does not work with revalidator
//
// "with a callback validator": {
// topic: function () {
// var that = this;
//
// helpers.stdout.once('data', function (msg) {
// that.msg = msg;
// });
//
// prompt.get(grab('cbvalidator'), this.callback);
// helpers.stdin.writeNextTick('cb123\n');
// },
// "should not accept a value that is correct": function (err, result) {
// assert.isNull(err);
// assert.equal(result['cbvalidator'],'cb123');
// }
// }
}
},
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"with a simple string prompt": {
"that is a property name in prompt.properties": {
"with a sync function before (.before)": {
topic: function() {
var that = this;
helpers.stdout.once('data', function(msg) {
that.msg = msg;
});
prompt.get({
properties: {
fnbefore: {
before: function(v) {
return 'v' + v;
}
}
}
}, this.callback);
helpers.stdin.writeNextTick('fn456\n');
},
"should modify user's input": function(e, result) {
assert.equal(result.fnbefore, 'vfn456');
}
}
}
}
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"skip prompt with prompt.overide": {
topic: function () {
prompt.override = { coconihet: 'whatever' }
prompt.get('coconihet', this.callback);
},
"skips prompt and uses overide": function (err, results) {
assert.equal(results.coconihet, 'whatever')
}
}
}
}
}).addBatch({
"When using prompt": {
"the addProperties() method": {
topic: function () {
prompt.addProperties({}, ['foo', 'bar'], this.callback);
helpers.stdin.writeSequence(['foo\n', 'bar\n']);
},
"should add the properties to the object": function (err, obj) {
assert.isNull(err);
assert.isObject(obj);
assert.equal(obj.foo, 'foo');
assert.equal(obj.bar, 'bar');
}
}
}
}).addBatch({
"When using prompt": {
"the get() method": {
"with old schema": {
topic: function () {
var that = this;
helpers.stdout.once('data', function (msg) {
that.msg = msg;
});
prompt.properties.username = schema.properties.oldschema;
prompt.get('username', this.callback);
helpers.stdin.writeSequence(['\n', 'hell$\n', 'hello\n']);
},
"should prompt to stdout and respond with the default value": function (err, result) {
assert.isNull(err);
assert.isTrue(this.msg.indexOf('username') !== -1);
assert.include(result, 'username');
assert.equal(result.username, 'hello');
}
}
}
}
}).addBatch({
"When using prompt": {
"the history() method": {
"when used inside of a complex property": {
"with correct value(s)": {
topic: function () {
prompt.get([grab('animal'), grab('sound')], this.callback);
helpers.stdin.writeSequence(['dog\n', 'woof\n']);
},
"should respond with the values entered": function (err, result) {
assert.isTrue(!err);
assert.equal(result.animal, 'dog');
assert.equal(result.sound, 'woof');
}
},
}
}
}
}).addBatch({
"When using prompt": {
"the history() method": {
"when used inside of a complex property": {
"with an incorrect value": {
topic: function () {
prompt.get([grab('animal'), grab('sound')], function () {});
prompt.once('invalid', this.callback.bind(null, null));
helpers.stdin.writeSequence(['dog\n', 'meow\n']);
},
"should prompt for the error": function (ign, property, line) {
assert.equal(property.path.join(''), 'sound');
assert.equal(line, 'meow');
}
}
}
}
}
}).addBatch({
"when using prompt": {
"the get() method": {
topic: function () {
prompt.override = { xyz: 468, abc: 123 }
prompt.get(['xyz', 'abc'], this.callback);
},
"should respond with overrides": function (err, results) {
assert.isNull(err);
assert.deepEqual(results, { xyz: 468, abc: 123 });
}
}
}
}).addBatch({
"When using prompt": {
"with fancy properties": {
"the get() method": {
topic: function () {
prompt.override = { UVW: 5423, DEF: 64235 }
prompt.get({
properties: {
'UVW': {
description: 'a custom message',
default: 6
},
'DEF': {
description: 'a custom message',
default: 6
}
}
}, this.callback);
},
"should respond with overrides": function (err, results) {
assert.isNull(err);
assert.deepEqual(results, { UVW: 5423, DEF: 64235 });
}
}
}
}
}).addBatch(
macros.shouldConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'Y'
})
).addBatch(
macros.shouldConfirm({
messages: ['with an empty string and default yes'],
prop: 'test',
response: ''
}, {
default: 'yes'
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'N'
})
).addBatch(
macros.shouldConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'YES'
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'NO'
})
).addBatch(
macros.shouldConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'T'
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'F'
})
).addBatch(
macros.shouldConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'TRUE'
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with a string message'],
prop: 'test',
response: 'FALSE'
})
).addBatch(
macros.shouldConfirm({
messages: ['with an object', 'and description set'],
prop: { description: 'a custom message' },
response: 'Y'
})
).addBatch(
macros.shouldConfirm({
messages: ['with an object', 'and they forgot the description'],
prop: { description: 'a custom message' },
response: 'Y'
})
).addBatch(
macros.shouldConfirm({
messages: ['with an object', 'and custom validators'],
prop: {
description: 'node or jitsu?',
pattern: /^(node|jitsu)/i,
yes: /^node/i
},
response: 'node'
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with an object', 'and custom validators'],
prop: {
description: 'node or jitsu?',
pattern: /^(node|jitsu)/i,
yes: /^node/i
},
response: 'jitsu'
})
).addBatch(
macros.shouldConfirm({
messages: ['with multiple strings'],
prop: ["test", "test2", "test3"],
response: ['Y\n', 'y\n', 'YES\n']
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with multiple strings'],
prop: ["test", "test2", "test3"],
response: ['Y\n', 'N\n', 'YES\n']
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with multiple strings'],
prop: ["test", "test2", "test3"],
response: ['n\n', 'NO\n', 'N\n']
})
).addBatch(
macros.shouldConfirm({
messages: ['with multiple objects'],
prop: [
{ message: "test" },
{ message: "test2" }
],
response: ['y\n', 'y\n']
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with multiple objects'],
prop: [
{ message: "test" },
{ message: "test2" }
],
response: ['n\n', 'n\n']
})
).addBatch(
macros.shouldNotConfirm({
messages: ['with multiple objects'],
prop: [
{ message: "test" },
{ message: "test2" }
],
response: ['n\n', 'y\n']
})
).export(module);