UNPKG

ember-cli-ajh

Version:

Command line tool for developing ambitious ember.js apps

525 lines (480 loc) 16.5 kB
'use strict'; /*jshint expr: true*/ var expect = require('chai').expect; var commandOptions = require('../../factories/command-options'); var Command = require('../../../lib/models/command'); var assign = require('lodash/object/assign'); var Yam = require('yam'); var ServeCommand = Command.extend({ name: 'serve', aliases: ['server', 's'], availableOptions: [ { name: 'port', type: Number, default: 4200 }, { name: 'host', type: String, default: '0.0.0.0' }, { name: 'proxy', type: String }, { name: 'live-reload', type: Boolean, default: true, aliases: ['lr'] }, { name: 'live-reload-port', type: Number, description: '(Defaults to port number + 31529)' }, { name: 'environment', type: String, default: 'development' } ], run: function() {} }); var DevelopEmberCLICommand = Command.extend({ name: 'develop-ember-cli', works: 'everywhere', availableOptions: [ { name: 'package-name', key: 'packageName', type: String, required: true } ], run: function() {} }); var InsideProjectCommand = Command.extend({ name: 'inside-project', works: 'insideProject', run: function() {} }); var OutsideProjectCommand = Command.extend({ name: 'outside-project', works: 'outsideProject', run: function() {} }); var OptionsAliasCommand = Command.extend({ name: 'options-alias', availableOptions: [{ name: 'taco', type: String, default: 'traditional', aliases: [ { 'hard-shell': 'hard-shell' }, { 'soft-shell': 'soft-shell' } ] }, { name: 'spicy', type: Boolean, default: true, aliases: [ { 'mild': false } ] }, { name: 'display-message', type: String, aliases: [ 'dm', { 'hw': 'Hello world' } ] }], run: function() {} }); describe('models/command.js', function() { var ui; var config; var options; before(function() { config = new Yam('ember-cli', { secondary: process.cwd() + '/tests/fixtures/home', primary: process.cwd() + '/tests/fixtures/project' }); }); beforeEach(function() { options = commandOptions(); ui = options.ui; }); it('parseArgs() should parse the command options.', function() { expect(new ServeCommand(options).parseArgs(['--port', '80'])).to.have.deep.property('options.port', 80); }); it('parseArgs() should get command options from the config file and command line', function() { expect(new ServeCommand(assign(options, { settings: config.getAll() })).parseArgs(['--port', '789'])).to.deep.equal({ options: { port: 789, environment: 'mock-development', host: '0.1.0.1', proxy: 'http://iamstef.net/ember-cli', liveReload: false, checkForUpdates: true }, args: [] }); }); it('parseArgs() should set default option values.', function() { expect(new ServeCommand(options).parseArgs([])).to.have.deep.property('options.port', 4200); }); it('parseArgs() should return args too.', function() { expect(new ServeCommand(assign(options, { settings: config.getAll() })).parseArgs(['foo', '--port', '80'])).to.deep.equal({ args: ['foo'], options: { environment: 'mock-development', host: '0.1.0.1', proxy: 'http://iamstef.net/ember-cli', liveReload: false, port: 80, checkForUpdates: true } }); }); it('parseArgs() should warn if an option is invalid.', function() { new ServeCommand(assign(options, { settings: config.getAll() })).parseArgs(['foo', '--envirmont', 'production']); expect(ui.output).to.match(/The option '--envirmont' is not registered with the serve command. Run `ember serve --help` for a list of supported options./); }); it('parseArgs() should parse shorthand options.', function() { expect(new ServeCommand(options).parseArgs(['-e', 'tacotown'])).to.have.deep.property('options.environment', 'tacotown'); }); it('parseArgs() should parse shorthand dasherized options.', function() { expect(new ServeCommand(options).parseArgs(['-lr', 'false'])).to.have.deep.property('options.liveReload', false); }); it('validateAndRun() should print a message if a required option is missing.', function() { return new DevelopEmberCLICommand(options).validateAndRun([]).then(function() { expect(ui.output).to.match(/requires the option.*package-name/); }); }); it('validateAndRun() should print a message if outside a project and command is not valid there.', function() { return new InsideProjectCommand(assign(options, { project: { isEmberCLIProject: function() { return false; } } })).validateAndRun([]).catch(function(reason) { expect(reason.message).to.match(/You have to be inside an ember-cli project/); }); }); it('validateAndRun() should print a message if inside a project and command is not valid there.', function() { return new OutsideProjectCommand(options).validateAndRun([]).catch(function(reason) { expect(reason.message).to.match(/You cannot use.*inside an ember-cli project/); }); }); it('availableOptions with aliases should work.', function() { expect(new OptionsAliasCommand(options).parseArgs(['-soft-shell'])).to.deep.equal({ options: { taco: 'soft-shell', spicy: true }, args: [] }); }); it('availableOptions with aliases should work with minimum characters.', function() { expect(new OptionsAliasCommand(options).parseArgs(['-so'])).to.deep.equal({ options: { taco: 'soft-shell', spicy: true }, args: [] }); }); it('availableOptions with aliases should work with hyphenated options', function() { expect(new OptionsAliasCommand(options).parseArgs(['-dm', 'hi'])).to.deep.equal({ options: { taco: 'traditional', spicy: true, displayMessage: 'hi' }, args: [] }); expect(new OptionsAliasCommand(options).parseArgs(['-hw'])).to.deep.equal({ options: { taco: 'traditional', spicy: true, displayMessage: 'Hello world' }, args: [] }); }); it('registerOptions() should allow adding availableOptions.', function() { var optionsAlias = new OptionsAliasCommand(options); var extendedAvailableOptions = [{ name: 'filling', type: String, default: 'adobada', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }]; optionsAlias.registerOptions({ availableOptions: extendedAvailableOptions }); // defaults expect(optionsAlias.parseArgs([])).to.deep.equal({ options: { taco: 'traditional', spicy: true, filling: 'adobada' }, args: [] }); // shorthand expect(optionsAlias.parseArgs(['-carne'])).to.deep.equal({ options: { taco: 'traditional', spicy: true, filling: 'carne-asada' }, args: [] }); // last argument wins expect(optionsAlias.parseArgs(['-carne','-fish'])).to.deep.equal({ options: { taco: 'traditional', spicy: true, filling: 'fish' }, args: [] }); }); it('registerOptions() should allow overriding availableOptions.', function() { var optionsAlias = new OptionsAliasCommand(options); var extendedAvailableOptions = [{ name: 'filling', type: String, default: 'adobada', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }]; var duplicateExtendedAvailableOptions = [{ name: 'filling', type: String, default: 'carnitas', aliases: [ { 'pollo-asado': 'pollo-asado' }, { 'carne-asada': 'carne-asada' } ] }]; optionsAlias.registerOptions({ availableOptions: extendedAvailableOptions }); // default expect(optionsAlias.parseArgs([])).to.deep.equal({ options: { taco: 'traditional', spicy: true, filling: 'adobada' }, args: [] }); // shorthand expect(optionsAlias.parseArgs(['-carne'])).to.deep.equal({ options: { taco: 'traditional', spicy: true, filling: 'carne-asada' }, args: [] }); optionsAlias.registerOptions({ availableOptions: duplicateExtendedAvailableOptions }); // override default expect(optionsAlias.parseArgs([])).to.deep.equal({ options: { taco: 'traditional', spicy: true, filling: 'carnitas' }, args: [] }); // last argument wins expect(optionsAlias.parseArgs(['-fish', '-pollo'])).to.deep.equal({ options: { taco: 'traditional', spicy: true, filling: 'pollo-asado' }, args: [] }); }); it('registerOptions() should not allow aliases with the same name.', function() { var optionsAlias = new OptionsAliasCommand(options); var extendedAvailableOptions = [ { name: 'filling', type: String, default: 'adobada', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }, { name: 'favorite', type: String, default: 'adobada', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] } ]; var register = optionsAlias.registerOptions.bind(optionsAlias); optionsAlias.availableOptions = extendedAvailableOptions; expect(register).to.throw('The "carne-asada" alias is already in use by the "--filling" option and ' + 'cannot be used by the "--favorite" option. Please use a different alias.'); }); it('registerOptions() should warn on options override attempts.', function() { var optionsAlias = new OptionsAliasCommand(options); var extendedAvailableOptions = [ { name: 'spicy', type: Boolean, default: true, aliases: [ { 'mild': true } ] } ]; optionsAlias.registerOptions({ availableOptions: extendedAvailableOptions }); expect(ui.output).to.match(/The ".*" alias cannot be overridden. Please use a different alias./); }); it('registerOptions() should handle invalid alias definitions.', function() { //check for different types, validate proper errors are thrown var optionsAlias = new OptionsAliasCommand(options); var badArrayAvailableOptions = [{ name: 'filling', type: String, default: 'adobada', aliases: [ 'meat', [{ 'carne-asada': 'carne-asada' }], { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }]; var badObjectAvailableOptions = [{ name: 'filling', type: String, default: 'adobada', aliases: [ 'meat', { 'carne-asada': ['steak','grilled']}, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }]; var register = optionsAlias.registerOptions.bind(optionsAlias); optionsAlias.availableOptions = badArrayAvailableOptions; expect(register).to.throw('The "[object Object]" [type:array] alias is not an acceptable value. ' + 'It must be a string or single key object with a string value (for example, "value" or { "key" : "value" }).'); optionsAlias.availableOptions = badObjectAvailableOptions; expect(register).to.throw('The "[object Object]" [type:object] alias is not an acceptable value. ' + 'It must be a string or single key object with a string value (for example, "value" or { "key" : "value" }).'); }); it('parseAlias() should parse aliases and return an object', function() { var optionsAlias = new OptionsAliasCommand(options); var option = { name: 'filling', type: String, key: 'filling', default: 'adobada', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }; var alias = { 'carnitas': 'carnitas' }; expect(optionsAlias.parseAlias(option, alias)).to.deep.equal({ key: 'carnitas', value: ['--filling','carnitas'], original: { 'carnitas': 'carnitas' } }); }); it('validateOption() should validate options', function() { var option = { name: 'filling', type: String, default: 'adobada', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }; var dupe = { name: 'spicy', type: Boolean, default: true, aliases: [{ 'mild': false }] }; var noAlias = { name: 'reload', type: Boolean, default: false }; expect(new OptionsAliasCommand(options).validateOption(option)).to.be.ok; expect(new ServeCommand(options).validateOption(noAlias)).to.be.false; expect(new OptionsAliasCommand(options).validateOption(dupe)).to.be.false; }); it('validateOption() should throw an error when option is missing name or type', function() { var optionsAlias = new OptionsAliasCommand(options); var notype = { name: 'taco' }; var noname = { type: Boolean }; expect(optionsAlias.validateOption.bind(optionsAlias, notype)).to.throw('The command "options-alias" has an ' + 'option without the required type and name fields.'); expect(optionsAlias.validateOption.bind(optionsAlias, noname)).to.throw('The command "options-alias" has an ' + 'option without the required type and name fields.'); }); it('validateOption() should throw an error when option name is camelCase or capitalized', function() { var optionsAlias = new OptionsAliasCommand(options); var capital = { name: 'Taco', type: Boolean }; var camel = { name: 'tacoTown', type: Boolean }; expect(optionsAlias.validateOption.bind(optionsAlias, capital)).to.throw('The "Taco" option\'s name of the "options-alias"' + ' command contains a capital letter.'); expect(optionsAlias.validateOption.bind(optionsAlias, camel)).to.throw('The "tacoTown" option\'s name of the "options-alias"' + ' command contains a capital letter.'); }); it('mergeDuplicateOption() should merge duplicate options together', function() { var optionsAlias = new OptionsAliasCommand(options); var garbageAvailableOptions = [ { name: 'spicy', type: Boolean, default: true, aliases: [{ 'mild': true }] } ]; optionsAlias.registerOptions({ availableOptions: garbageAvailableOptions }); var extendedAvailableOptions = [{ name: 'filling', type: String, default: 'adobada', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' } ] }]; var duplicateExtendedAvailableOptions = [{ name: 'filling', type: String, default: 'carnitas', aliases: [ { 'pollo-asado': 'pollo-asado' }, { 'carne-asada': 'carne-asada' } ] }]; optionsAlias.registerOptions({ availableOptions: extendedAvailableOptions }); optionsAlias.availableOptions.push(duplicateExtendedAvailableOptions[0]); expect(optionsAlias.mergeDuplicateOption('filling')).to.deep.equal([ { name: 'taco', type: String, default: 'traditional', aliases: [ { 'hard-shell': 'hard-shell' }, { 'soft-shell': 'soft-shell' } ], key: 'taco', required: false }, { name: 'display-message', type: String, aliases: [ 'dm', { 'hw': 'Hello world' } ], key: 'displayMessage', required: false }, { name: 'spicy', type: Boolean, default: true, aliases: [ { 'mild': false } ], key: 'spicy', required: false }, { name: 'filling', type: String, default: 'carnitas', aliases: [ { 'carne-asada': 'carne-asada' }, { 'carnitas': 'carnitas' }, { 'fish': 'fish' }, { 'pollo-asado': 'pollo-asado' } ], key: 'filling', required: false } ]); }); it('implicit shorthands work with values.', function() { expect(new OptionsAliasCommand(options).parseArgs(['-s', 'false', '-t', 'hard-shell'])).to.deep.equal({ options: { taco: 'hard-shell', spicy: false }, args: [] }); }); });