UNPKG

canonical

Version:

Canonical code style linter and formatter for JavaScript, SCSS, CSS and JSON.

1,569 lines (1,351 loc) 47.1 kB
/* global beforeEach, describe, it */ require('chai').should() var expect = require('chai').expect var fs = require('fs') var parser = require('../') var path = require('path') describe('yargs-parser', function () { it('should parse a "short boolean"', function () { var parse = parser([ '-b' ]) parse.should.have.property('b').to.be.ok.and.be.a('boolean') parse.should.have.property('_').with.length(0) }) it('should parse a "long boolean"', function () { var parse = parser('--bool') parse.should.have.property('bool', true) parse.should.have.property('_').with.length(0) }) it('should place bare options in the _ array', function () { var parse = parser('foo bar baz') parse.should.have.property('_').and.deep.equal(['foo', 'bar', 'baz']) }) it('should set the value of the final option in a group to the next supplied value', function () { var parse = parser(['-cats', 'meow']) parse.should.have.property('c', true) parse.should.have.property('a', true) parse.should.have.property('t', true) parse.should.have.property('s', 'meow') parse.should.have.property('_').with.length(0) }) it('should set the value of a single long option to the next supplied value', function () { var parse = parser(['--pow', 'xixxle']) parse.should.have.property('pow', 'xixxle') parse.should.have.property('_').with.length(0) }) it('should set the value of a single long option if an = was used', function () { var parse = parser(['--pow=xixxle']) parse.should.have.property('pow', 'xixxle') parse.should.have.property('_').with.length(0) }) it('should set the value of multiple long options to the next supplied values relative to each', function () { var parse = parser(['--host', 'localhost', '--port', '555']) parse.should.have.property('host', 'localhost') parse.should.have.property('port', 555) parse.should.have.property('_').with.length(0) }) it('should set the value of multiple long options if = signs were used', function () { var parse = parser(['--host=localhost', '--port=555']) parse.should.have.property('host', 'localhost') parse.should.have.property('port', 555) parse.should.have.property('_').with.length(0) }) it('should still set values appropriately if a mix of short, long, and grouped short options are specified', function () { var parse = parser(['-h', 'localhost', '-fp', '555', 'script.js']) parse.should.have.property('f', true) parse.should.have.property('p', 555) parse.should.have.property('h', 'localhost') parse.should.have.property('_').and.deep.equal(['script.js']) }) it('should still set values appropriately if a mix of short and long options are specified', function () { var parse = parser(['-h', 'localhost', '--port', '555']) parse.should.have.property('h', 'localhost') parse.should.have.property('port', 555) parse.should.have.property('_').with.length(0) }) it('should explicitly set a boolean option to false if preceeded by "--no-"', function () { var parse = parser(['--no-moo']) parse.should.have.property('moo', false) parse.should.have.property('_').with.length(0) }) it('should still set values appropriately if we supply a comprehensive list of various types of options', function () { var parse = parser([ '--name=meowmers', 'bare', '-cats', 'woo', '-h', 'awesome', '--multi=quux', '--key', 'value', '-b', '--bool', '--no-meep', '--multi=baz', '--', '--not-a-flag', '-', '-h', '-multi', '--', 'eek' ]) parse.should.have.property('c', true) parse.should.have.property('a', true) parse.should.have.property('t', true) parse.should.have.property('s', 'woo') parse.should.have.property('h', 'awesome') parse.should.have.property('b', true) parse.should.have.property('bool', true) parse.should.have.property('key', 'value') parse.should.have.property('multi').and.deep.equal(['quux', 'baz']) parse.should.have.property('meep', false) parse.should.have.property('name', 'meowmers') parse.should.have.property('_').and.deep.equal(['bare', '--not-a-flag', '-', '-h', '-multi', '--', 'eek']) }) it('should parse numbers appropriately', function () { var argv = parser([ '-x', '1234', '-y', '5.67', '-z', '1e7', '-w', '10f', '--hex', '0xdeadbeef', '789' ]) argv.should.have.property('x', 1234).and.be.a('number') argv.should.have.property('y', 5.67).and.be.a('number') argv.should.have.property('z', 1e7).and.be.a('number') argv.should.have.property('w', '10f').and.be.a('string') argv.should.have.property('hex', 0xdeadbeef).and.be.a('number') argv.should.have.property('_').and.deep.equal([789]) argv._[0].should.be.a('number') }) it('should not set the next value as the value of a short option if that option is explicitly defined as a boolean', function () { var parse = parser([ '-t', 'moo' ], { boolean: 't' }) parse.should.have.property('t', true).and.be.a('boolean') parse.should.have.property('_').and.deep.equal(['moo']) }) it('should set boolean options values if the next value is "true" or "false"', function () { var parse = parser(['--verbose', 'false', 'moo', '-t', 'true'], { boolean: ['t', 'verbose'], default: { verbose: true } }) parse.should.have.property('verbose', false).and.be.a('boolean') parse.should.have.property('t', true).and.be.a('boolean') parse.should.have.property('_').and.deep.equal(['moo']) }) it('should allow defining options as boolean in groups', function () { var parse = parser([ '-x', '-z', 'one', 'two', 'three' ], { boolean: ['x', 'y', 'z'] }) parse.should.have.property('x', true).and.be.a('boolean') parse.should.have.property('y', false).and.be.a('boolean') parse.should.have.property('z', true).and.be.a('boolean') parse.should.have.property('_').and.deep.equal(['one', 'two', 'three']) }) it('should preserve newlines in option values', function () { var args = parser(['-s', 'X\nX']) args.should.have.property('_').with.length(0) args.should.have.property('s', 'X\nX') // reproduce in bash: // VALUE="new // line" // node program.js --s="$VALUE" args = parser(['--s=X\nX']) args.should.have.property('_').with.length(0) args.should.have.property('s', 'X\nX') }) it('should not convert numbers to type number if explicitly defined as strings', function () { var s = parser([ '-s', '0001234' ], { string: 's' }).s s.should.be.a('string').and.equal('0001234') var x = parser([ '-x', '56' ], { string: ['x'] }).x x.should.be.a('string').and.equal('56') }) it('should default numbers to undefined', function () { var n = parser([ '-n' ], { number: ['n'] }).n expect(n).to.equal(undefined) }) it('should default number to NaN if value is not a valid number', function () { var n = parser([ '-n', 'string' ], { number: ['n'] }).n expect(n).to.deep.equal(NaN) }) // Fixes: https://github.com/bcoe/yargs/issues/68 it('should parse flag arguments with no right-hand-value as strings, if defined as strings', function () { var s = parser([ '-s' ], { string: ['s'] }).s s.should.be.a('string').and.equal('') s = parser([ '-sf' ], { string: ['s'] }).s s.should.be.a('string').and.equal('') s = parser([ '--string' ], { string: ['string'] }).string s.should.be.a('string').and.equal('') }) it('should leave all non-hyphenated values as strings if _ is defined as a string', function () { var s = parser([ ' ', ' ' ], { string: ['_'] })._ s.should.have.length(2) s[0].should.be.a('string').and.equal(' ') s[1].should.be.a('string').and.equal(' ') }) describe('normalize', function () { it('should normalize redundant paths', function () { var a = parser([ '-s', ['', 'tmp', '..', ''].join(path.sep) ], { alias: { s: ['save'] }, normalize: 's' }) a.should.have.property('s', path.sep) a.should.have.property('save', path.sep) }) it('should normalize redundant paths when a value is later assigned', function () { var a = parser(['-s'], { normalize: ['s'] }) a.should.have.property('s', true) a.s = ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep) a.s.should.equal(['', 'path', 'to', ''].join(path.sep)) }) }) describe('alias', function () { it('should set alias value to the same value as the full option', function () { var argv = parser([ '-f', '11', '--zoom', '55' ], { alias: { z: ['zoom'] } }) argv.should.have.property('zoom', 55) argv.should.have.property('z', 55) argv.should.have.property('f', 11) }) it('should allow multiple aliases to be specified', function () { var argv = parser([ '-f', '11', '--zoom', '55' ], { alias: { z: ['zm', 'zoom'] } }) argv.should.have.property('zoom', 55) argv.should.have.property('z', 55) argv.should.have.property('zm', 55) argv.should.have.property('f', 11) }) // regression, see https://github.com/chevex/yargs/issues/63 it('should not add the same key to argv multiple times, when creating camel-case aliases', function () { var argv = parser(['--health-check=banana', '--second-key', 'apple', '-t=blarg'], { alias: { h: ['health-check'], 'second-key': ['s'], 'third-key': ['t'] }, default: { h: 'apple', 'second-key': 'banana', 'third-key': 'third' } }) // before this fix, yargs failed parsing // one but not all forms of an arg. argv.secondKey.should.eql('apple') argv.s.should.eql('apple') argv['second-key'].should.eql('apple') argv.healthCheck.should.eql('banana') argv.h.should.eql('banana') argv['health-check'].should.eql('banana') argv.thirdKey.should.eql('blarg') argv.t.should.eql('blarg') argv['third-key'].should.eql('blarg') }) it('should allow transitive aliases to be specified', function () { var argv = parser([ '-f', '11', '--zoom', '55' ], { alias: { z: 'zm', zm: 'zoom' } }) argv.should.have.property('zoom', 55) argv.should.have.property('z', 55) argv.should.have.property('zm', 55) argv.should.have.property('f', 11) }) it('should merge two lists of aliases if they collide', function () { var argv = parser(['-f', '11', '--zoom', '55'], { alias: { z: 'zm', zoom: 'zoop', zm: 'zoom' } }) argv.should.have.property('zoom', 55) argv.should.have.property('zoop', 55) argv.should.have.property('z', 55) argv.should.have.property('zm', 55) argv.should.have.property('f', 11) }) }) it('should assign data after forward slash to the option before the slash', function () { var parse = parser(['-I/foo/bar/baz']) parse.should.have.property('_').with.length(0) parse.should.have.property('I', '/foo/bar/baz') parse = parser(['-xyz/foo/bar/baz']) parse.should.have.property('x', true) parse.should.have.property('y', true) parse.should.have.property('z', '/foo/bar/baz') parse.should.have.property('_').with.length(0) }) describe('config', function () { var jsonPath = path.resolve(__dirname, './fixtures/config.json') // See: https://github.com/chevex/yargs/issues/12 it('should load options and values from default config if specified', function () { var argv = parser([ '--foo', 'bar' ], { alias: { z: 'zoom' }, default: { settings: jsonPath }, config: 'settings' }) argv.should.have.property('herp', 'derp') argv.should.have.property('zoom', 55) argv.should.have.property('foo').and.deep.equal('bar') }) it('should use value from config file, if argv value is using default value', function () { var argv = parser([], { alias: { z: 'zoom' }, config: ['settings'], default: { settings: jsonPath, foo: 'banana' } }) argv.should.have.property('herp', 'derp') argv.should.have.property('zoom', 55) argv.should.have.property('foo').and.deep.equal('baz') }) it('should use value from config file, if argv key is a boolean', function () { var argv = parser([], { config: ['settings'], default: { settings: jsonPath }, boolean: ['truthy'] }) argv.should.have.property('truthy', true) }) it('should use value from cli, if cli overrides boolean argv key', function () { var argv = parser(['--no-truthy'], { config: ['settings'], default: { settings: jsonPath }, boolean: ['truthy'] }) argv.should.have.property('truthy', false) }) it('should use cli value, if cli value is set and both cli and default value match', function () { var argv = parser(['--foo', 'banana'], { alias: { z: 'zoom' }, config: ['settings'], default: { settings: jsonPath, foo: 'banana' } }) argv.should.have.property('herp', 'derp') argv.should.have.property('zoom', 55) argv.should.have.property('foo').and.deep.equal('banana') }) it('should load options and values from a file when config is used', function () { var argv = parser([ '--settings', jsonPath, '--foo', 'bar' ], { alias: { z: 'zoom' }, config: ['settings'] }) argv.should.have.property('herp', 'derp') argv.should.have.property('zoom', 55) argv.should.have.property('foo').and.deep.equal('bar') }) it("should allow config to be set as flag in 'option'", function () { var argv = parser([ '--settings', jsonPath, '--foo', 'bar' ], { alias: { z: 'zoom' }, config: ['settings'] }) argv.should.have.property('herp', 'derp') argv.should.have.property('zoom', 55) argv.should.have.property('foo').and.deep.equal('bar') }) it('should load options and values from a JS file when config has .js extention', function () { var jsPath = path.resolve(__dirname, './fixtures/settings.js') var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], { config: ['settings'] }) argv.should.have.property('herp', 'derp') argv.should.have.property('foo', 'bar') argv.should.have.property('calculate').and.be.a('function') }) it('should raise an appropriate error if JSON file is not found', function () { var argv = parser.detailed(['--settings', 'fake.json', '--foo', 'bar'], { alias: { z: 'zoom' }, config: ['settings'] }) argv.error.message.should.equal('Invalid JSON config file: fake.json') }) // see: https://github.com/bcoe/yargs/issues/172 it('should not raise an exception if config file is set as default argument value', function () { var argv = parser.detailed([], { default: { config: 'foo.json' }, config: ['config'] }) expect(argv.error).to.equal(null) }) it('allows a custom parsing function to be provided', function () { var jsPath = path.resolve(__dirname, './fixtures/config.txt') var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], { config: { settings: function (configPath) { // as an example, parse an environment // variable style config: // FOO=99 // BATMAN=grumpy var config = {} var txt = fs.readFileSync(configPath, 'utf-8') txt.split(/\r?\n/).forEach(function (l) { var kv = l.split('=') config[kv[0].toLowerCase()] = kv[1] }) return config } } }) argv.batman.should.equal('grumpy') argv.awesome.should.equal('banana') argv.foo.should.equal('bar') }) it('allows a custom parsing function to be provided as an alias', function () { var jsPath = path.resolve(__dirname, './fixtures/config.json') var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], { config: { s: function (configPath) { return JSON.parse(fs.readFileSync(configPath, 'utf-8')) } }, alias: { s: ['settings'] } }) argv.should.have.property('herp', 'derp') argv.should.have.property('foo', 'bar') }) it('outputs an error returned by the parsing function', function () { var argv = parser.detailed(['--settings=./package.json'], { config: { settings: function (configPath) { return Error('someone set us up the bomb') } } }) argv.error.message.should.equal('someone set us up the bomb') }) it('outputs an error if thrown by the parsing function', function () { var argv = parser.detailed(['--settings=./package.json'], { config: { settings: function (configPath) { throw Error('someone set us up the bomb') } } }) argv.error.message.should.equal('someone set us up the bomb') }) }) describe('dot notation', function () { it('should allow object graph traversal via dot notation', function () { var argv = parser([ '--foo.bar', '3', '--foo.baz', '4', '--foo.quux.quibble', '5', '--foo.quux.o_O', '--beep.boop' ]) argv.should.have.property('foo').and.deep.equal({ bar: 3, baz: 4, quux: { quibble: 5, o_O: true } }) argv.should.have.property('beep').and.deep.equal({ boop: true }) }) it('should apply defaults to dot notation arguments', function () { var argv = parser([], { default: { 'foo.bar': 99 } }) argv.foo.bar.should.eql(99) }) // see #279 it('should allow default to be overridden when an alias is provided', function () { var argv = parser(['--foo.bar', '200'], { default: { 'foo.bar': 99 } }) argv.foo.bar.should.eql(200) }) // see #279 it('should also override alias', function () { var argv = parser(['--foo.bar', '200'], { alias: { 'foo.bar': ['f'] }, default: { 'foo.bar': 99 } }) argv.f.should.eql(200) }) // see #279 it('should not set an undefined dot notation key', function () { var argv = parser(['--foo.bar', '200'], { default: { 'foo.bar': 99 }, alias: { 'foo.bar': ['f'] } }) ;('foo.bar' in argv).should.equal(false) }) it('should respect .string() for dot notation arguments', function () { var argv = parser(['--foo.bar', '99', '--bar.foo=99'], { string: ['foo.bar'] }) argv.foo.bar.should.eql('99') argv.bar.foo.should.eql(99) }) it('should populate aliases when dot notation is used', function () { var argv = parser(['--foo.bar', '99'], { alias: { foo: ['f'] } }) argv.f.bar.should.eql(99) }) it('should populate aliases when nested dot notation is used', function () { var argv = parser(['--foo.bar.snuh', '99', '--foo.apple', '33', '--foo.bar.cool', '11'], { alias: { foo: ['f'] } }) argv.f.bar.snuh.should.eql(99) argv.foo.bar.snuh.should.eql(99) argv.f.apple.should.eql(33) argv.foo.apple.should.eql(33) argv.f.bar.cool.should.eql(11) argv.foo.bar.cool.should.eql(11) }) it("should allow flags to use dot notation, when seperated by '='", function () { var argv = parser(['-f.foo=99']) argv.f.foo.should.eql(99) }) it("should allow flags to use dot notation, when seperated by ' '", function () { var argv = parser(['-f.foo', '99']) argv.f.foo.should.eql(99) }) it('should allow flags to use dot notation when no right-hand-side is given', function () { var argv = parser(['-f.foo', '99', '-f.bar']) argv.f.foo.should.eql(99) argv.f.bar.should.eql(true) }) }) it('should set boolean and alias using explicit true', function () { var aliased = [ '-h', 'true' ] var aliasedArgv = parser(aliased, { boolean: ['h'], alias: { h: ['herp'] } }) aliasedArgv.should.have.property('herp', true) aliasedArgv.should.have.property('h', true) aliasedArgv.should.have.property('_').with.length(0) }) // regression, see https://github.com/substack/node-optimist/issues/71 it('should set boolean and --x=true', function () { var parsed = parser(['--boool', '--other=true'], { boolean: ['boool'] }) parsed.should.have.property('boool', true) parsed.should.have.property('other', 'true') parsed = parser(['--boool', '--other=false'], { boolean: ['boool'] }) parsed.should.have.property('boool', true) parsed.should.have.property('other', 'false') }) // regression, see https://github.com/chevex/yargs/issues/66 it('should set boolean options values if next value is "true" or "false" with = as separator', function () { var argv = parser(['--bool=false'], { boolean: ['b'], alias: { b: ['bool'] }, default: { b: true } }) argv.bool.should.eql(false) }) describe('short options', function () { it('should set the value of multiple single short options to the next supplied values relative to each', function () { var parse = parser(['-h', 'localhost', '-p', '555']) parse.should.have.property('h', 'localhost') parse.should.have.property('p', 555) parse.should.have.property('_').with.length(0) }) it('should set the value of a single short option to the next supplied value', function () { var parse = parser(['-h', 'localhost']) parse.should.have.property('h', 'localhost') parse.should.have.property('_').with.length(0) }) it('should expand grouped short options to a hash with a key for each', function () { var parse = parser(['-cats']) parse.should.have.property('c', true) parse.should.have.property('a', true) parse.should.have.property('t', true) parse.should.have.property('s', true) parse.should.have.property('_').with.length(0) }) it('should set n to the numeric value 123', function () { var argv = parser([ '-n123' ]) argv.should.have.property('n', 123) }) it('should set option "1" to true, option "2" to true, and option "3" to numeric value 456', function () { var argv = parser([ '-123', '456' ]) argv.should.have.property('1', true) argv.should.have.property('2', true) argv.should.have.property('3', 456) }) }) describe('whitespace', function () { it('should be whitespace', function () { var argv = parser([ '-x', '\t' ]) argv.should.have.property('x', '\t') }) }) describe('boolean modifier function', function () { it('should prevent yargs from sucking in the next option as the value of the first option', function () { // Arrange & Act var result = parser(['-b', '123'], { boolean: ['b'] }) // Assert result.should.have.property('b').that.is.a('boolean').and.is.true result.should.have.property('_').and.deep.equal([123]) }) }) describe('defaults', function () { function checkNoArgs (opts, hasAlias) { it('should set defaults if no args', function () { var result = parser([], opts) result.should.have.property('flag', true) if (hasAlias) { result.should.have.property('f', true) } }) } function checkExtraArg (opts, hasAlias) { it('should set defaults if one extra arg', function () { var result = parser(['extra'], opts) result.should.have.property('flag', true) result.should.have.property('_').and.deep.equal(['extra']) if (hasAlias) { result.should.have.property('f', true) } }) } function checkStringArg (opts, hasAlias) { it('should set defaults even if arg looks like a string', function () { var result = parser([ '--flag', 'extra' ], opts) result.should.have.property('flag', true) result.should.have.property('_').and.deep.equal(['extra']) if (hasAlias) { result.should.have.property('f', true) } }) } describe('for options with aliases', function () { var opts = { alias: { flag: ['f'] }, default: { flag: true } } checkNoArgs(opts, true) checkExtraArg(opts, true) }) describe('for typed options without aliases', function () { var opts = { boolean: ['flag'], default: { flag: true } } checkNoArgs(opts) checkExtraArg(opts) checkStringArg(opts) }) describe('for typed options with aliases', function () { var opts = { alias: { flag: ['f'] }, boolean: ['flag'], default: { flag: true } } checkNoArgs(opts, true) checkExtraArg(opts, true) checkStringArg(opts, true) }) describe('for boolean options', function () { [true, false, undefined].forEach(function (def) { describe('with explicit ' + def + ' default', function () { var opts = { default: { flag: def }, boolean: ['flag'] } it('should set true if --flag in arg', function () { parser(['--flag'], opts).flag.should.be.true }) it('should set false if --no-flag in arg', function () { parser(['--no-flag'], opts).flag.should.be.false }) it('should set ' + def + ' if no flag in arg', function () { expect(parser([], opts).flag).to.equal(def) }) }) }) describe('with implied false default', function () { var opts = null beforeEach(function () { opts = { boolean: ['flag'] } }) it('should set true if --flag in arg', function () { parser(['--flag'], opts).flag.should.be.true }) it('should set false if --no-flag in arg', function () { parser(['--no-flag'], opts).flag.should.be.false }) it('should set false if no flag in arg', function () { parser([], opts).flag.should.be.false }) }) // Fixes: https://github.com/bcoe/yargs/issues/341 it('should apply defaults to camel-case form of argument', function () { var argv = parser([], { default: { 'foo-bar': 99 } }) argv.fooBar.should.equal(99) }) }) it('should define option as boolean and set default to true', function () { var argv = parser([], { boolean: ['sometrue'], default: { sometrue: true } }) argv.should.have.property('sometrue', true) }) it('should define option as boolean and set default to false', function () { var argv = parser([], { default: { somefalse: false }, boolean: ['somefalse'] }) argv.should.have.property('somefalse', false) }) it('should set boolean options to false by default', function () { var parse = parser(['moo'], { boolean: ['t', 'verbose'], default: { verbose: false, t: false } }) parse.should.have.property('verbose', false).and.be.a('boolean') parse.should.have.property('t', false).and.be.a('boolean') parse.should.have.property('_').and.deep.equal(['moo']) }) }) describe('camelCase', function () { function runTests (strict) { if (!strict) { // Skip this test in strict mode because this option is not specified it('should provide options with dashes as camelCase properties', function () { var result = parser(['--some-option']) result.should.have.property('some-option').that.is.a('boolean').and.is.true result.should.have.property('someOption').that.is.a('boolean').and.is.true }) } it('should provide count options with dashes as camelCase properties', function () { var result = parser([ '--some-option', '--some-option', '--some-option' ], { count: ['some-option'] }) result.should.have.property('some-option', 3) result.should.have.property('someOption', 3) }) it('should provide options with dashes and aliases as camelCase properties', function () { var result = parser(['--some-option'], { alias: { 'some-horse': 'o' } }) result.should.have.property('some-option').that.is.a('boolean').and.is.true result.should.have.property('someOption').that.is.a('boolean').and.is.true }) it('should provide defaults of options with dashes as camelCase properties', function () { var result = parser([], { default: { 'some-option': 'asdf' } }) result.should.have.property('some-option', 'asdf') result.should.have.property('someOption', 'asdf') }) it('should provide aliases of options with dashes as camelCase properties', function () { var result = parser([], { default: { 'some-option': 'asdf' }, alias: { 'some-option': ['o'] } }) result.should.have.property('o', 'asdf') result.should.have.property('some-option', 'asdf') result.should.have.property('someOption', 'asdf') }) it('should provide aliases of options with dashes as camelCase properties', function () { var result = parser([], { alias: { o: ['some-option'] }, default: { o: 'asdf' } }) result.should.have.property('o', 'asdf') result.should.have.property('some-option', 'asdf') result.should.have.property('someOption', 'asdf') }) it('should provide aliases with dashes as camelCase properties', function () { var result = parser(['--some-option', 'val'], { alias: { o: 'some-option' } }) result.should.have.property('o').that.is.a('string').and.equals('val') result.should.have.property('some-option').that.is.a('string').and.equals('val') result.should.have.property('someOption').that.is.a('string').and.equals('val') }) } describe('dashes and camelCase', function () { runTests() }) describe('dashes and camelCase (strict)', function () { runTests(true) }) }) describe('-', function () { it('should set - as value of n', function () { var argv = parser(['-n', '-']) argv.should.have.property('n', '-') argv.should.have.property('_').with.length(0) }) it('should set - as a non-hyphenated value', function () { var argv = parser(['-']) argv.should.have.property('_').and.deep.equal(['-']) }) it('should set - as a value of f', function () { var argv = parser(['-f-']) argv.should.have.property('f', '-') argv.should.have.property('_').with.length(0) }) it('should set b to true and set - as a non-hyphenated value when b is set as a boolean', function () { var argv = parser(['-b', '-'], { boolean: ['b'] }) argv.should.have.property('b', true) argv.should.have.property('_').and.deep.equal(['-']) }) it('should set - as the value of s when s is set as a string', function () { var argv = parser([ '-s', '-' ], { string: ['s'] }) argv.should.have.property('s', '-') argv.should.have.property('_').with.length(0) }) }) describe('count', function () { it('should count the number of times a boolean is present', function () { var parsed parsed = parser(['-x'], { count: ['verbose'] }) parsed.verbose.should.equal(0) parsed = parser(['--verbose'], { count: ['verbose'] }) parsed.verbose.should.equal(1) parsed = parser(['--verbose', '--verbose'], { count: ['verbose'] }) parsed.verbose.should.equal(2) parsed = parser(['-vvv'], { alias: { v: ['verbose'] }, count: ['verbose'] }) parsed.verbose.should.equal(3) parsed = parser(['--verbose', '--verbose', '-v', '--verbose'], { count: ['verbose'], alias: { v: ['verbose'] } }) parsed.verbose.should.equal(4) parsed = parser(['--verbose', '--verbose', '-v', '-vv'], { count: ['verbose'], alias: { v: ['verbose'] } }) parsed.verbose.should.equal(5) }) it('should not consume the next argument', function () { var parsed = parser([ '-v', 'moo' ], { count: 'v' }) parsed.v.should.equal(1) parsed.should.have.property('_').and.deep.equal(['moo']) parsed = parser([ '--verbose', 'moomoo', '--verbose' ], { count: 'verbose' }) parsed.verbose.should.equal(2) parsed.should.have.property('_').and.deep.equal(['moomoo']) }) }) describe('array', function () { it('should group values into an array if the same option is specified multiple times', function () { var parse = parser(['-v', 'a', '-v', 'b', '-v', 'c']) parse.should.have.property('v').and.deep.equal(['a', 'b', 'c']) parse.should.have.property('_').with.length(0) }) it('should default argument to empty array if no value given', function () { var result = parser(['-b'], { array: 'b' }) Array.isArray(result.b).should.equal(true) }) it('should place value of argument in array, when one argument provided', function () { var result = parser(['-b', '33'], { array: ['b'] }) Array.isArray(result.b).should.equal(true) result.b[0].should.equal(33) }) it('should add multiple argument values to the array', function () { var result = parser(['-b', '33', '-b', 'hello'], { array: 'b' }) Array.isArray(result.b).should.equal(true) result.b.should.include(33) result.b.should.include('hello') }) it('should allow array: true, to be set inside an option block', function () { var result = parser(['-b', '33'], { array: 'b' }) Array.isArray(result.b).should.equal(true) result.b.should.include(33) }) // issue #103 it('should default camel-case alias to array type', function () { var result = parser(['--ca-path', 'http://www.example.com'], { array: ['ca-path'] }) Array.isArray(result['ca-path']).should.equal(true) Array.isArray(result.caPath).should.equal(true) }) it('should default alias to array type', function () { var result = parser(['--ca-path', 'http://www.example.com'], { array: 'ca-path', alias: { 'ca-path': 'c' } }) Array.isArray(result['ca-path']).should.equal(true) Array.isArray(result.caPath).should.equal(true) Array.isArray(result.c).should.equal(true) }) // see: https://github.com/bcoe/yargs/issues/162 it('should eat non-hyphenated arguments until hyphenated option is hit', function () { var result = parser(['-a=hello', 'world', '-b', '33', '22', '--foo', 'red', 'green', '--bar=cat', 'dog'], { array: ['a', 'b', 'foo', 'bar'] }) Array.isArray(result.a).should.equal(true) result.a.should.include('hello') result.a.should.include('world') Array.isArray(result.b).should.equal(true) result.b.should.include(33) result.b.should.include(22) Array.isArray(result.foo).should.equal(true) result.foo.should.include('red') result.foo.should.include('green') Array.isArray(result.bar).should.equal(true) result.bar.should.include('cat') result.bar.should.include('dog') }) }) describe('nargs', function () { it('should allow the number of arguments following a key to be specified', function () { var result = parser([ '--foo', 'apple', 'bar' ], { narg: { foo: 2 } }) Array.isArray(result.foo).should.equal(true) result.foo[0].should.equal('apple') result.foo[1].should.equal('bar') }) it('should raise an exception if there are not enough arguments following key', function () { var argv = parser.detailed('--foo apple', { narg: { foo: 2 } }) argv.error.message.should.equal('Not enough arguments following: foo') }) it('nargs is applied to aliases', function () { var result = parser(['--bar', 'apple', 'bar'], { narg: { foo: 2 }, alias: { foo: 'bar' } }) Array.isArray(result.foo).should.equal(true) result.foo[0].should.equal('apple') result.foo[1].should.equal('bar') }) it('should apply nargs to flag arguments', function () { var result = parser([ '-f', 'apple', 'bar', 'blerg' ], { narg: { f: 2 } }) result.f[0].should.equal('apple') result.f[1].should.equal('bar') result._[0].should.equal('blerg') }) it('should support nargs for -f= and --bar= format arguments', function () { var result = parser(['-f=apple', 'bar', 'blerg', '--bar=monkey', 'washing', 'cat'], { narg: { f: 2, bar: 2 } }) result.f[0].should.equal('apple') result.f[1].should.equal('bar') result._[0].should.equal('blerg') result.bar[0].should.equal('monkey') result.bar[1].should.equal('washing') result._[1].should.equal('cat') }) it('should not modify the input args if an = was used', function () { var expected = ['-f=apple', 'bar', 'blerg', '--bar=monkey', 'washing', 'cat'] var args = expected.slice() parser(args, { narg: { f: 2, bar: 2 } }) args.should.deep.equal(expected) parser.detailed(args, { narg: { f: 2, bar: 2 } }) args.should.deep.equal(expected) }) it('allows multiple nargs to be set at the same time', function () { var result = parser([ '--foo', 'apple', 'bar', '--bar', 'banana', '-f' ], { narg: { foo: 2, bar: 1 } }) Array.isArray(result.foo).should.equal(true) result.foo[0].should.equal('apple') result.foo[1].should.equal('bar') result.bar.should.equal('banana') result.f.should.equal(true) }) }) describe('env vars', function () { it('should apply all env vars if prefix is empty', function () { process.env.ONE_FISH = 'twofish' process.env.RED_FISH = 'bluefish' var result = parser([], { envPrefix: '' }) result.oneFish.should.equal('twofish') result.redFish.should.equal('bluefish') }) it('should apply only env vars matching prefix if prefix is valid string', function () { process.env.ONE_FISH = 'twofish' process.env.RED_FISH = 'bluefish' process.env.GREEN_EGGS = 'sam' process.env.GREEN_HAM = 'iam' var result = parser([], { envPrefix: 'GREEN' }) result.eggs.should.equal('sam') result.ham.should.equal('iam') expect(result.oneFish).to.be.undefined expect(result.redFish).to.be.undefined }) it('should set aliases for options defined by env var', function () { process.env.AIRFORCE_ONE = 'two' var result = parser([], { envPrefix: 'AIRFORCE', alias: { '1': ['one', 'uno'] } }) result['1'].should.equal('two') result.one.should.equal('two') result.uno.should.equal('two') }) it('should prefer command line value over env var', function () { process.env.FOO_BAR = 'ignore' var result = parser(['--foo-bar', 'baz'], { envPrefix: '' }) result.fooBar.should.equal('baz') }) it('should respect type for args defined by env var', function () { process.env.MY_TEST_STRING = '1' process.env.MY_TEST_NUMBER = '2' var result = parser([], { string: 'string', envPrefix: 'MY_TEST_' }) result.string.should.equal('1') result.number.should.equal(2) }) it('should set option from aliased env var', function () { process.env.SPACE_X = 'awesome' var result = parser([], { alias: { xactly: 'x' }, envPrefix: 'SPACE' }) result.xactly.should.equal('awesome') }) it('should prefer env var value over configured default', function () { process.env.FOO_BALL = 'wut' process.env.FOO_BOOL = 'true' var result = parser([], { envPrefix: 'FOO', default: { ball: 'baz', bool: false }, boolean: 'bool', string: 'ball' }) result.ball.should.equal('wut') result.bool.should.equal(true) }) var jsonPath = path.resolve(__dirname, './fixtures/config.json') it('should prefer config file value over env var', function () { process.env.CFG_HERP = 'zerp' var result = parser(['--cfg', jsonPath], { envPrefix: 'CFG', config: 'cfg', string: 'herp', default: { herp: 'nerp' } }) result.herp.should.equal('derp') }) it('should support an env var value as config file option', function () { process.env.TUX_CFG = jsonPath var result = parser([], { envPrefix: 'TUX', config: ['cfg'], default: { z: 44 } }) result.should.have.property('herp') result.should.have.property('foo') result.should.have.property('version') result.should.have.property('truthy') result.z.should.equal(55) }) it('should prefer cli config file option over env var config file option', function () { process.env.MUX_CFG = path.resolve(__dirname, '../package.json') var result = parser(['--cfg', jsonPath], { envPrefix: 'MUX', config: 'cfg' }) result.should.have.property('herp') result.should.have.property('foo') result.should.have.property('version') result.should.have.property('truthy') result.z.should.equal(55) }) }) describe('configuration', function () { describe('short option groups', function () { it('allows short-option-groups to be disabled', function () { var parse = parser(['-cats=meow'], { configuration: { 'short-option-groups': false } }) parse.cats.should.equal('meow') parse = parser(['-cats', 'meow'], { configuration: { 'short-option-groups': false } }) parse.cats.should.equal('meow') }) }) describe('camel-case expansion', function () { it('does not expand camel-case aliases', function () { var parsed = parser.detailed([], { alias: { 'foo-bar': ['x'] }, configuration: { 'camel-case-expansion': false } }) expect(parsed.newAliases.fooBar).to.equal(undefined) expect(parsed.aliases.fooBar).to.equal(undefined) }) it('does not expand camel-case keys', function () { var parsed = parser.detailed(['--foo-bar=apple'], { configuration: { 'camel-case-expansion': false } }) expect(parsed.argv.fooBar).to.equal(undefined) expect(parsed.argv['foo-bar']).to.equal('apple') }) }) describe('dot notation', function () { it('does not expand dot notation defaults', function () { var parsed = parser([], { default: { 'foo.bar': 'x' }, configuration: { 'dot-notation': false } }) expect(parsed['foo.bar']).to.equal('x') }) it('does not expand dot notation arguments', function () { var parsed = parser(['--foo.bar', 'banana'], { configuration: { 'dot-notation': false } }) expect(parsed['foo.bar']).to.equal('banana') parsed = parser(['--foo.bar=banana'], { configuration: { 'dot-notation': false } }) expect(parsed['foo.bar']).to.equal('banana') }) }) describe('parse numbers', function () { it('does not coerce defaults into numbers', function () { var parsed = parser([], { default: { 'foo': '5' }, configuration: { 'parse-numbers': false } }) expect(parsed['foo']).to.equal('5') }) it('does not coerce arguments into numbers', function () { var parsed = parser(['--foo', '5'], { configuration: { 'parse-numbers': false } }) expect(parsed['foo']).to.equal('5') }) it('does not coerce positional arguments into numbers', function () { var parsed = parser(['5'], { configuration: { 'parse-numbers': false } }) expect(parsed._[0]).to.equal('5') }) }) describe('boolean negation', function () { it('does not negate arguments prefixed with --no-', function () { var parsed = parser(['--no-dice'], { configuration: { 'boolean-negation': false } }) parsed['no-dice'].should.equal(true) expect(parsed.dice).to.equal(undefined) }) }) }) })