@alexbosworth/caporal
Version:
A full-featured framework for building command line applications (cli) with node.js
253 lines (209 loc) • 8.61 kB
JavaScript
"use strict";
/* global Program, logger, should, makeArgv, sinon */
const InvalidArgumentValueError = require('../lib/error/invalid-argument-value');
const WrongNumberOfArgumentError = require('../lib/error/wrong-num-of-arg');
const program = new Program();
program
.logger(logger)
.version('1.0.0')
.reset()
.command('foo', 'Fooooo')
.argument('<foo>', 'My bar', /^[a-z]+$/)
.action(function(){});
describe("Argument validation", function() {
beforeEach(function () {
this.fatalError = sinon.stub(program, "fatalError");
this.action = sinon.spy();
});
afterEach(function () {
this.fatalError.restore();
program.reset();
});
it(`should throw InvalidArgumentValueError for an invalid required argument value (Regex validator)`, function() {
program.parse(makeArgv(['foo', '827E92']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(InvalidArgumentValueError))).be.ok();
});
it(`should throw InvalidArgumentValueError for an invalid optional argument value (Regex validator)`, function() {
program
.command('foo', 'Fooooo')
.argument('[foo]', 'My bar', /^[a-z]+$/)
.action(this.action);
program.parse(makeArgv(['foo', '827E92']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(InvalidArgumentValueError))).be.ok();
});
it(`should throw InvalidArgumentValueError for an invalid optional argument value (Array validator)`, function() {
program
.command('foo', 'Fooooo')
.argument('[foo]', 'My bar', ["bim", "bam", "boom"])
.action(this.action);
program.parse(makeArgv(['foo', '827E92']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(InvalidArgumentValueError))).be.ok();
});
it(`should throw InvalidArgumentValueError for an invalid required argument value (Array validator)`, function() {
program
.command('foo', 'Fooooo')
.argument('<foo>', 'My bar', ["bim", "bam", "boom"])
.action(this.action);
program.parse(makeArgv(['foo', '827E92']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(InvalidArgumentValueError))).be.ok();
});
it(`should not throw InvalidArgumentValueError for an valid required argument value (Array validator)`, function() {
program
.command('foo', 'Fooooo')
.argument('<foo>', 'My bar', ["bim", "bam", "boom"])
.action(this.action);
program.parse(makeArgv(['foo', 'bam']));
should(this.fatalError.callCount).eql(0);
});
it(`should throw InvalidArgumentValueError for an invalid required argument value (Function validator)`, function() {
program
.command('foo', 'Fooooo')
.argument('<foo>', 'My bar', arg => {
const options = ["bim", "bam", "boom"];
if (options.includes(arg)) {
return arg;
}
throw new Error();
})
.action(this.action);
program.parse(makeArgv(['foo', '827E92']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(InvalidArgumentValueError))).be.ok();
});
it(`should not throw InvalidArgumentValueError for a valid required argument value (Function validator)`, function() {
program
.command('foo', 'Fooooo')
.argument('<foo>', 'My bar', arg => {
const options = ["bim", "bam", "boom"];
if (options.includes(arg)) {
return arg;
}
throw new Error();
})
.action(this.action);
program.parse(makeArgv(['foo', 'bam']));
should(this.fatalError.callCount).eql(0);
});
it(`should throw InvalidArgumentValueError for an invalid required argument value (Promise validator)`, function(done) {
program
.command('foo', 'Fooooo')
.argument('<foo>', 'My bar', arg => new Promise((resolve, reject) => {
const options = ["bim", "bam", "boom"];
setTimeout(() => {
if (options.includes(arg)) {
resolve(arg)
} else {
reject(new Error())
}
}, 10);
}))
.action(this.action);
program.parse(makeArgv(['foo', '827E92']))
.catch(e => {
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(InvalidArgumentValueError))).be.ok();
done()
});
});
it(`should not throw InvalidArgumentValueError for a valid required argument value (Promise validator)`, function(done) {
program
.command('foo', 'Fooooo')
.argument('<foo>', 'My bar', arg => new Promise((resolve, reject) => {
const options = ["bim", "bam", "boom"];
setTimeout(() => {
if (options.includes(arg)) {
resolve(arg)
} else {
reject(new Error())
}
}, 10);
}))
.action(this.action);
program.parse(makeArgv(['foo', 'bam'])).then(arg => {
should(this.fatalError.callCount).eql(0);
done();
})
});
it(`should take default value if not passed when setting up a default argument value`, function() {
program
.command('foo', 'Fooooo')
.argument('[foo]', 'My bar', /^[a-z]+$/, 'bar')
.action(this.action);
program.parse(makeArgv(['foo']));
should(this.action.callCount).eql(1);
should(this.action.calledWith({foo:"bar"}));
should(this.fatalError.callCount).eql(0);
});
it(`should throw WrongNumberOfArgumentError when passing an unknown argument for a command that does not accept arguments`, function() {
program
.command('foo', 'Fooooo')
.action(this.action);
program.parse(makeArgv(['foo', '827E92']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(WrongNumberOfArgumentError))).be.ok();
});
it(`should throw WrongNumberOfArgumentError for a known command when forgetting an argument`, function() {
program
.command('foo', 'Fooooo')
.argument('<joe>', 'max')
.argument('<jiji...>', 'jiji')
.action(this.action);
program.parse(makeArgv(['foo']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(WrongNumberOfArgumentError))).be.ok();
});
it(`should throw WrongNumberOfArgumentError for a default command when forgetting an argument`, function() {
program
.argument('<joe>', 'max')
.argument('<jiji...>', 'jiji')
.action(this.action);
program.parse(makeArgv(['foo']));
should(this.fatalError.callCount).eql(1);
should(this.fatalError.calledWith(sinon.match.instanceOf(WrongNumberOfArgumentError))).be.ok();
});
it(`should not throw any error when passing an argument without validator`, function() {
program
.command('foo', 'Fooooo')
.argument('<foo>', 'My foo')
.action(this.action);
program.parse(makeArgv(['foo', '827E-Z92']));
should(this.fatalError.callCount).eql(0);
});
it(`should return an array for variadic arguments without validator`, function() {
program
.command('foo', 'Fooooo')
.argument('[foo]', 'My bar', /^[a-z]+$/, 'bar')
.argument('[other-foo...]', 'Other foo')
.action(this.action);
program.parse(makeArgv(['foo', 'bar', 'im', 'a', 'variadic', 'arg']));
should(this.fatalError.callCount).eql(0);
should(this.action.calledWith({foo: "bar", otherFoo: ['im', 'a', 'variadic', 'arg']}))
});
it(`should handled optional arguments with no default and no validator`, function() {
program
.command('foo', 'Fooooo')
.argument('[foo]', 'My bar', /^[a-z]+$/)
.action(this.action);
program.parse(makeArgv(['foo']));
should(this.action.callCount).eql(1);
});
it(`should hanldle negative numbers in quoted arguments`, function() {
program
.command('order', 'Order something')
.argument('<what>', 'What to order', ["pizza", "burger", "smoothie"])
.argument('<how-much>', 'How much', program.INT)
.action(this.action);
program.parse(makeArgv(['order', "pizza", '-1']));
should(this.fatalError.callCount).eql(0);
should(this.action.callCount).eql(1);
should(this.action.args[0][0]).eql({ what: 'pizza', howMuch: -1 });
});
it(`should not throw any error when passing an handled argument to completion`, function() {
program.parse(makeArgv(['completion', 'zsh']));
should(this.fatalError.callCount).eql(0);
});
});