UNPKG

ionic

Version:

A tool for creating and developing Ionic Framework mobile apps.

1,031 lines (867 loc) • 35.4 kB
'use strict'; var IonicAppLib = require('ionic-app-lib'); var semver = require('semver'); var optimist = require('optimist'); var Ionitron = require('../lib/utils/ionitron'); var Q = require('q'); var helpUtils = require('../lib/utils/help'); var IonicStore = require('../lib/utils/store'); var IonicStats = require('../lib/utils/stats'); var Info = IonicAppLib.info; var Utils = IonicAppLib.utils; var Project = IonicAppLib.project; var Logging = IonicAppLib.logging; var log = Logging.logger; var fs = require('fs'); var path = require('path'); var rewire = require('rewire'); var IonicCli = rewire('../lib/cli'); var gulp = require('gulp'); describe('Cli', function() { beforeEach(function() { spyOn(IonicStats, 't'); spyOn(IonicCli, 'processExit'); spyOn(helpUtils, 'printTaskListShortUsage'); spyOn(helpUtils, 'printTaskListUsage'); spyOn(IonicAppLib.events, 'on'); spyOn(process, 'on'); spyOn(Info, 'checkRuntime'); spyOn(Utils, 'cdIonicRoot'); spyOn(Project, 'load'); spyOn(Utils, 'fail').andCallFake(function(err) { console.log(err); console.log(err.stack); }); }); it('should have cli defined', function() { expect(IonicCli).toBeDefined(); }); it('should have cli tasks defined', function() { expect(IonicCli.ALL_TASKS).toBeDefined(); }); describe('#run', function() { beforeEach(function() { spyOn(IonicCli, 'doRuntimeCheck'); }); describe('#Cli methods', function() { it('should run checkLatestVersion on run', function(done) { spyOn(IonicCli, 'checkLatestVersion').andReturn(Q(true)); IonicCli.run(['node', 'bin/ionic', '--h']) .then(function() { expect(IonicCli.checkLatestVersion).toHaveBeenCalled(); done(); }); }); it('should run info doRuntimeCheck on run', function(done) { IonicCli.run(['node', 'bin/ionic', '--h']) .then(function() { expect(IonicCli.doRuntimeCheck).toHaveBeenCalled(); done(); }); }); it('should run ionitron when argument is passed', function(done) { spyOn(Ionitron, 'print'); IonicCli.run(['node', 'bin/ionic', '--ionitron']) .then(function() { expect(Ionitron.print).toHaveBeenCalled(); done(); }); }); it('should change log level to debug when verbose arg is passed', function(done) { expect(IonicAppLib.logging.logger.level).toBe('info'); IonicCli.run(['node', 'bin/ionic', '--verbose']) .then(function() { expect(IonicAppLib.logging.logger.level).toBe('debug'); done(); }); }); it('should get version when version flag passed', function(done) { spyOn(IonicCli, 'version'); IonicCli.run(['node', 'bin/ionic', '--version']) .then(function() { expect(IonicCli.version).toHaveBeenCalled(); done(); }); }); it('should call help when help argument passed', function(done) { IonicCli.run(['node', 'bin/ionic', '--help']) .then(function() { expect(helpUtils.printTaskListUsage).toHaveBeenCalled(); done(); }); }); it('should call help when help shorthand argument passed', function(done) { IonicCli.run(['node', 'bin/ionic', '--h']) .then(function() { expect(helpUtils.printTaskListUsage).toHaveBeenCalled(); done(); }); }); it('should print available tasks if no valid command is passed', function(done) { IonicCli.run(['node', 'bin/ionic']) .then(function() { expect(helpUtils.printTaskListShortUsage).toHaveBeenCalled(); done(); }); }); it('should get the correct task by name', function() { var task = IonicCli.getTaskSettingsByName('start'); expect(task).toBeDefined(); expect(task.name).toBe('start'); expect(task.args).toBeDefined(); }); it('should call attachErrorHandling', function(done) { spyOn(IonicCli, 'attachErrorHandling'); IonicCli.run(['node', 'bin/ionic']) .then(function() { expect(IonicCli.attachErrorHandling).toHaveBeenCalled(); done(); }); }); it('should get boolean options from start task', function() { var task = IonicCli.getTaskSettingsByName('start'); var booleanOptions = IonicCli.getListOfBooleanOptions(task.options); // We expect 6 total = 3 options, each with short hand notation. expect(booleanOptions.length).toBe(9); }); it('should track stats for cli', function(done) { IonicCli.run(['node', 'bin/ionic', 'help']) .then(function() { expect(IonicStats.t).toHaveBeenCalled(); done(); }); }); it('should not track stats for cli for a bogus command', function(done) { IonicCli.run(['node', 'bin/ionic', 'helper']) .then(function() { expect(IonicStats.t).not.toHaveBeenCalled(); done(); }); }); it('should change cwd to project root for project tasks', function(done) { var processArguments = ['node', 'bin/ionic', 'fake']; var rawCliArguments = processArguments.slice(2); var argv = optimist(rawCliArguments).argv; var FakeTask = { name: 'fake', title: 'fake', run: function() { return Q(true); }, isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(FakeTask, 'run').andReturn(Q(true)); IonicCli.run(processArguments) .then(function() { expect(Utils.cdIonicRoot).toHaveBeenCalled(); expect(FakeTask.run).toHaveBeenCalledWith(IonicCli, argv, rawCliArguments); done(); }); }); it('should skip loading gulpfile if node_modules does not exist', function(done) { var processArguments = ['node', 'bin/ionic', 'fake']; var rawCliArguments = processArguments.slice(2); var argv = optimist(rawCliArguments).argv; var FakeTask = { name: 'fake', title: 'fake', run: function() { return Q(true); }, isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(fs, 'existsSync').andReturn(false); spyOn(FakeTask, 'run').andReturn(Q(true)); spyOn(IonicCli, 'loadGulpfile'); spyOn(IonicCli, 'runWithGulp'); IonicCli.run(processArguments) .then(function() { expect(IonicCli.loadGulpfile).not.toHaveBeenCalled(); expect(IonicCli.runWithGulp).not.toHaveBeenCalled(); expect(FakeTask.run).toHaveBeenCalledWith(IonicCli, argv, rawCliArguments); done(); }); }); it('should skip runWithGulp if a gulpfile does not exist', function(done) { var processArguments = ['node', 'bin/ionic', 'fake']; var rawCliArguments = processArguments.slice(2); var argv = optimist(rawCliArguments).argv; var FakeTask = { name: 'fake', title: 'fake', run: function() { return Q(true); }, isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(fs, 'existsSync').andReturn(true); spyOn(IonicCli, 'loadGulpfile').andReturn(false); spyOn(FakeTask, 'run').andReturn(Q(true)); spyOn(IonicCli, 'runWithGulp'); IonicCli.run(processArguments) .then(function() { expect(IonicCli.loadGulpfile).toHaveBeenCalled(); expect(IonicCli.runWithGulp).not.toHaveBeenCalled(); expect(FakeTask.run).toHaveBeenCalledWith(IonicCli, argv, rawCliArguments); done(); }); }); it('should not change cwd to project root for non project tasks', function(done) { var processArguments = ['node', 'bin/ionic', 'fake']; var rawCliArguments = processArguments.slice(2); var argv = optimist(rawCliArguments).argv; var FakeTask = { name: 'fake', title: 'fake', run: function() { return Q(true); }, isProjectTask: false }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(FakeTask, 'run').andReturn(Q(true)); IonicCli.run(processArguments) .then(function() { expect(Utils.cdIonicRoot).not.toHaveBeenCalled(); expect(FakeTask.run).toHaveBeenCalledWith(IonicCli, argv, rawCliArguments); done(); }); }); it('should print a warning if node_modules doesn\'t exist and using v2', function(done) { spyOn(fs, 'existsSync').andReturn(false); Project.load = function() { return { get: function() { return true; } // return v2 === true }; }; var FakeTask = { name: 'fake', title: 'fake', run: function() { return Q(true); }, isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(IonicCli, 'runWithGulp'); spyOn(log, 'warn'); IonicCli.run(['node', 'bin/ionic', 'fake']) .then(function() { expect(log.warn.calls[0].args[0]).toMatch( 'WARN: No node_modules directory found, do you need to run npm install?' ); expect(IonicCli.runWithGulp).not.toHaveBeenCalled(); done(); }); }); it('should warn if cmd requires build step and gulpfile doesn\'t exist and using v2', function(done) { var FakeTask = { name: 'build', title: 'build', run: function() {}, isProjectTask: true }; Project.load = function() { return { get: function() { return true; } // return v2 === true }; }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(FakeTask, 'run').andReturn(Q(true)); spyOn(fs, 'existsSync').andReturn(true); spyOn(IonicCli, 'loadGulpfile').andReturn(false); spyOn(IonicCli, 'loadNpmScripts').andReturn(false); spyOn(log, 'warn'); IonicCli.run(['node', 'bin/ionic', 'build']) .then(function() { expect(log.warn).toHaveBeenCalledWith('WARN: No build file found!'); done(); }); }); it('should not runWithGulp if a gulpfile doesn\'t exist', function(done) { var FakeTask = { name: 'fake', title: 'fake', run: function() {}, isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(IonicCli, 'runWithGulp'); spyOn(FakeTask, 'run').andReturn(Q(true)); spyOn(fs, 'existsSync').andReturn(true); spyOn(IonicCli, 'loadGulpfile').andReturn(false); spyOn(IonicCli, 'loadNpmScripts').andReturn(false); IonicCli.run(['node', 'bin/ionic', 'fake']) .then(function() { expect(IonicCli.loadGulpfile).toHaveBeenCalled(); expect(IonicCli.runWithGulp).not.toHaveBeenCalled(); done(); }); }); it('should not runWithGulp if npmScripts exist', function(done) { var FakeTask = { name: 'fake', title: 'fake', run: function() {}, isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(IonicCli, 'runWithGulp'); spyOn(FakeTask, 'run').andReturn(Q(true)); spyOn(fs, 'existsSync').andReturn(true); spyOn(IonicCli, 'loadGulpfile').andReturn(false); spyOn(IonicCli, 'loadNpmScripts').andReturn(true); IonicCli.run(['node', 'bin/ionic', 'fake']) .then(function() { expect(IonicCli.loadGulpfile).toHaveBeenCalled(); expect(IonicCli.runWithGulp).not.toHaveBeenCalled(); done(); }); }); it('should runWithGulp', function(done) { var FakeTask = { name: 'fake', isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(IonicCli, 'runWithGulp').andReturn(Q(true)); spyOn(IonicCli, 'runWithNpmScripts').andReturn(Q(true)); spyOn(fs, 'existsSync').andReturn(true); spyOn(IonicCli, 'loadGulpfile').andReturn(true); spyOn(IonicCli, 'loadNpmScripts').andReturn({}); IonicCli.run(['node', 'bin/ionic', 'fake']) .then(function() { expect(IonicCli.runWithGulp).toHaveBeenCalled(); expect(IonicCli.runWithNpmScripts).not.toHaveBeenCalled(); done(); }); }); it('should runWithNpmScripts without Gulpfile', function(done) { var FakeTask = { name: 'fake', isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(IonicCli, 'runWithGulp').andReturn(Q(true)); spyOn(IonicCli, 'runWithNpmScripts').andReturn(Q(true)); spyOn(fs, 'existsSync').andReturn(true); spyOn(IonicCli, 'loadGulpfile').andReturn(false); spyOn(IonicCli, 'loadNpmScripts').andReturn({ 'fake:before': true }); IonicCli.run(['node', 'bin/ionic', 'fake']) .then(function() { expect(IonicCli.runWithGulp).not.toHaveBeenCalled(); expect(IonicCli.runWithNpmScripts).toHaveBeenCalled(); done(); }); }); it('should runWithNpmScripts even with Gulpfile', function(done) { var FakeTask = { name: 'fake', isProjectTask: true }; spyOn(IonicCli, 'getTaskSettingsByName').andReturn(FakeTask); spyOn(IonicCli, 'runWithGulp').andReturn(Q(true)); spyOn(IonicCli, 'runWithNpmScripts').andReturn(Q(true)); spyOn(fs, 'existsSync').andReturn(true); spyOn(IonicCli, 'loadGulpfile').andReturn(true); spyOn(IonicCli, 'loadNpmScripts').andReturn({ 'fake:before': true }); IonicCli.run(['node', 'bin/ionic', 'fake']) .then(function() { expect(IonicCli.runWithGulp).not.toHaveBeenCalled(); expect(IonicCli.runWithNpmScripts).toHaveBeenCalled(); done(); }); }); it('should call Utils.fail if an exception occurrs within run', function(done) { var error = new Error('error happened'); spyOn(IonicCli, 'checkLatestVersion').andCallFake(function() { return Q.reject(error); }); IonicCli.run(['node', 'bin/ionic', '--stats-opt-out']).fin(function() { expect(Utils.fail).toHaveBeenCalledWith(error); done(); }); }); it('should save to the config if stats-opt-out is passed', function(done) { spyOn(IonicStore.prototype, 'set'); spyOn(IonicStore.prototype, 'save'); IonicCli.run(['node', 'bin/ionic', '--stats-opt-out']) .then(function() { expect(IonicStore.prototype.set).toHaveBeenCalledWith('statsOptOut', true); expect(IonicStore.prototype.save).toHaveBeenCalled(); done(); }); }); }); }); describe('#commands options', function() { beforeEach(function() { spyOn(IonicCli, 'doRuntimeCheck'); }); it('should parse start options correctly', function(done) { var Start = require('../lib/ionic/start'); spyOn(Start, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'start', 's1', '-w', '--appname', 'asdf']; IonicCli.run(processArgs).then(function() { var taskArgs = Start.run.mostRecentCall.args; var taskArgv = taskArgs[1]; expect(taskArgv._.length).toBe(2); expect(taskArgv._[0]).toBe('start'); expect(taskArgv._[1]).toBe('s1'); expect(taskArgv.appname).toBe('asdf'); expect(taskArgv.s).toBe(false); expect(taskArgv.sass).toBe(false); expect(taskArgv.l).toBe(false); expect(taskArgv.list).toBe(false); expect(taskArgv['no-cordova']).toBe(false); expect(taskArgv.w).toBe(true); expect(taskArgv.id).toBeUndefined(); expect(taskArgv.i).toBeUndefined(); done(); }); }); it('should parse serve options correctly', function(done) { var Serve = require('../lib/ionic/serve'); spyOn(Serve, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'serve', '--nogulp', '--all', '--browser', 'firefox']; IonicCli.run(processArgs).then(function() { var taskArgs = Serve.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(1); expect(taskArgv.browser).toBe('firefox'); expect(taskArgv.nogulp).toBe(true); expect(taskArgv.all).toBe(true); expect(taskArgv.lab).toBe(false); expect(taskArgv.nobrowser).toBe(false); done(); }); }); it('should parse upload options correctly', function(done) { var Upload = require('../lib/ionic/upload'); spyOn(Upload, 'run').andReturn(Q(true)); var note = 'A note for notes'; var processArgs = ['node', '/usr/local/bin/ionic', 'upload', '--email', 'user@ionic.io', '--password', 'pass', '--note', note]; IonicCli.run(processArgs).then(function() { var taskArgs = Upload.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(1); expect(taskArgv.note).toBe(note); expect(taskArgv.email).toBe('user@ionic.io'); expect(taskArgv.password).toBe('pass'); done(); }); }); it('should parse login options correctly', function(done) { var Login = require('../lib/ionic/login'); spyOn(Login, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'login', '--email', 'user@ionic.io', '--password', 'pass']; IonicCli.run(processArgs).then(function() { var taskArgs = Login.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(1); expect(taskArgv.email).toBe('user@ionic.io'); expect(taskArgv.password).toBe('pass'); done(); }).catch(done); }); it('should parse run options correctly', function(done) { var Run = require('../lib/ionic/run'); spyOn(Run, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'run', 'ios', '--livereload', '--port', '5000', '-r', '35730', '--consolelogs', '--serverlogs', '--device']; IonicCli.run(processArgs).then(function() { var taskArgs = Run.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(2); expect(taskArgv.r).toBe(35730); expect(taskArgv.port).toBe(5000); expect(taskArgv.consolelogs).toBe(true); expect(taskArgv.serverlogs).toBe(true); expect(taskArgv.livereload).toBe(true); expect(taskArgv.device).toBe(true); done(); }); }); it('should parse emulate options correctly', function(done) { var Emulate = require('../lib/ionic/emulate'); spyOn(Emulate, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'emulate', 'android', '--livereload', '--address', 'localhost', '--port', '5000', '-r', '35730', '--consolelogs', '--serverlogs']; IonicCli.run(processArgs).then(function() { var taskArgs = Emulate.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(2); expect(taskArgv._[1]).toBe('android'); expect(taskArgv.r).toBe(35730); expect(taskArgv.address).toBe('localhost'); expect(taskArgv.port).toBe(5000); expect(taskArgv.consolelogs).toBe(true); expect(taskArgv.serverlogs).toBe(true); expect(taskArgv.livereload).toBe(true); done(); }); }); it('should parse state options correctly', function(done) { var State = require('../lib/ionic/state'); spyOn(State, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'state', 'save', '--plugins']; IonicCli.run(processArgs).then(function() { var taskArgs = State.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(2); expect(taskArgv._[1]).toBe('save'); expect(taskArgv.plugins).toBe(true); expect(taskArgv.platforms).toBe(false); done(); }); }); it('should parse plugin options correctly', function(done) { var Plugin = require('../lib/ionic/plugin'); spyOn(Plugin, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'plugin', 'add', 'org.apache.cordova.splashscreen', '--nosave', '--searchpath', '../']; IonicCli.run(processArgs).then(function() { var taskArgs = Plugin.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(3); expect(taskArgv._[0]).toBe('plugin'); expect(taskArgv._[1]).toBe('add'); expect(taskArgv._[2]).toBe('org.apache.cordova.splashscreen'); expect(taskArgv.nosave).toBe(true); expect(taskArgv.searchpath).toBe('../'); done(); }); }); it('should parse build options correctly', function(done) { var Build = require('../lib/ionic/build'); spyOn(Build, 'run').andReturn(Q(true)); var processArgs = ['node', '/usr/local/bin/ionic', 'build', 'ios', '--nohooks']; IonicCli.run(processArgs).then(function() { var taskArgs = Build.run.mostRecentCall.args; var taskArgv = taskArgs[1]; // should only have serve in the command args expect(taskArgv._.length).toBe(2); expect(taskArgv._[0]).toBe('build'); expect(taskArgv._[1]).toBe('ios'); expect(taskArgv.nohooks).toBe(true); done(); }); }); describe('version checking for checkRuntime', function() { var IonicCli; beforeEach(function() { IonicCli = rewire('../lib/cli'); }); xit('should do runtime check when version is not checked', function() { var IonicConfigSpy = jasmine.createSpyObj('IonicConfig', ['get', 'set', 'save']); IonicConfigSpy.get.andReturn('1.6.4'); var revertConfig = IonicCli.__set__('IonicConfig', IonicConfigSpy); IonicCli.doRuntimeCheck('1.6.4'); expect(Info.checkRuntime).not.toHaveBeenCalled(); expect(IonicConfigSpy.set).not.toHaveBeenCalled(); expect(IonicConfigSpy.save).not.toHaveBeenCalled(); revertConfig(); }); xit('should do runtime check when version is not checked', function() { var IonicConfigSpy = jasmine.createSpyObj('IonicConfig', ['get', 'set', 'save']); IonicConfigSpy.get.andReturn('1.6.4'); var revertConfig = IonicCli.__set__('IonicConfig', IonicConfigSpy); IonicCli.doRuntimeCheck('1.6.5'); expect(Info.checkRuntime).toHaveBeenCalled(); expect(IonicConfigSpy.get).toHaveBeenCalled(); expect(IonicConfigSpy.set).toHaveBeenCalledWith('lastVersionChecked', '1.6.5'); expect(IonicConfigSpy.save).toHaveBeenCalled(); revertConfig(); }); }); }); describe('runWithGulp function', function() { var fakeTask; var argv; var rawCliArguments; var qCallbacks; beforeEach(function() { fakeTask = { name: 'fake', title: 'fake', run: function() { return Q(true); }, isProjectTask: true }; argv = { _: ['fake'], v2: true }; rawCliArguments = ['fake', '--v2']; gulp.tasks = { 'fake:before': function() {}, 'fake:after': function() {} }; qCallbacks = []; // gulp.start gets called with nfcall because it's async with a callback // so we stub our own function with a callback instead of creating a spy // (which is sync). We also track the callbacks because they are created // at runtime by Q.nfcall so we can tell jasmine what to expect. gulp.start = function(taskName, cb) { qCallbacks.push(cb); cb(); }; spyOn(gulp, 'start').andCallThrough(); spyOn(IonicCli, 'loadGulpfile').andReturn(true); spyOn(fakeTask, 'run').andCallThrough(); spyOn(process, 'exit'); spyOn(IonicCli, 'logEvents'); spyOn(log, 'error'); spyOn(fs, 'existsSync'); }); it('should try to load gulp, exit if it fails', function() { spyOn(path, 'resolve').andReturn('./wrong_path'); IonicCli.runWithGulp(argv, fakeTask, rawCliArguments); expect(log.error).toHaveBeenCalledWith('\nGulpfile detected, but gulp is not installed'.red); expect(log.error).toHaveBeenCalledWith('Do you need to run `npm install`?\n'.red); expect(process.exit).toHaveBeenCalled(); expect(IonicCli.logEvents).not.toHaveBeenCalled(); expect(fakeTask.run).not.toHaveBeenCalled(); expect(gulp.start).not.toHaveBeenCalled(); }); it('should run logEvents, the command and the gulp hooks', function(done) { IonicCli.runWithGulp(argv, fakeTask, rawCliArguments).then(function() { expect(IonicCli.logEvents).toHaveBeenCalled(); expect(gulp.start).toHaveBeenCalledWith('fake:before', qCallbacks[0]); expect(gulp.start).toHaveBeenCalledWith('fake:after', qCallbacks[1]); expect(fakeTask.run).toHaveBeenCalledWith(IonicCli, argv, rawCliArguments); expect(log.error).not.toHaveBeenCalled(); expect(process.exit).not.toHaveBeenCalled(); expect(fs.existsSync).not.toHaveBeenCalled(); done(); }).catch(done); }); it('should warn if no gulp task and using v2 and cmd requires build', function(done) { argv._[0] = 'build'; spyOn(log, 'warn'); gulp.start = function(taskName, cb) { cb({ missingTask: true }); }; IonicCli.runWithGulp(argv, fakeTask).then(function() { expect(log.warn).toHaveBeenCalledWith(('WARN: No \'build:before\' gulp task found!').yellow); done(); }); }); }); describe('loadGulpfile function', function() { it('should return true if gulpfile found', function() { var mock = require('mock-require'); var gulpfilePath = path.resolve(process.cwd() + '/gulpfile.js'); mock(gulpfilePath, {}); var result = IonicCli.loadGulpfile(); expect(result).toBe(true); mock.stop(gulpfilePath); }); it('should return false if gulpfile not found', function() { var result = IonicCli.loadGulpfile(); expect(result).toBe(false); }); }); describe('processExit method', function() { }); describe('printVersionWarning method', function() { it('should write out a warning if the version is not equal to version specified by the cli', function() { spyOn(log, 'warn'); IonicCli.printVersionWarning('2.0.1', '2.0.2'); expect(log.warn).toHaveBeenCalled(); }); it('should not write out a warning if the version is equal to version specified by the cli', function() { spyOn(log, 'warn'); IonicCli.printVersionWarning('2.0.1', '2.0.1'); expect(log.warn).not.toHaveBeenCalled(); }); it('should not write out a warning if the version is in beta', function() { spyOn(log, 'warn'); IonicCli.printVersionWarning('2.0.1-beta', '2.0.1'); expect(log.warn).not.toHaveBeenCalled(); }); it('should not write out a warning if the version is in alpha', function() { spyOn(log, 'warn'); IonicCli.printVersionWarning('2.0.1-alpha', '2.0.1'); expect(log.warn).not.toHaveBeenCalled(); }); }); describe('formatGulpError function', function() { it('should return e.message if e.err is null', function() { var error = new Error('gulp broke'); error.err = null; var results = IonicCli.formatGulpError(error); expect(results).toEqual(error.message); }); it('should return a string if the error is in a plugin', function() { var error = { err: { showStack: 'boolean' } }; var results = IonicCli.formatGulpError(error); expect(results).toEqual(jasmine.any(String)); }); it('should return a stack if it exists', function() { var testError = new Error('gulp broke'); var error = { err: testError }; var results = IonicCli.formatGulpError(error); expect(results).toEqual(testError.stack); }); it('should return a new error if it does not understand the error', function() { var error = { err: 'Something broke somewhere' }; var results = IonicCli.formatGulpError(error); expect(results).toContain(error.err); }); }); describe('checkLatestVersion method', function() { it('should not check npm if current version is a beta', function() { spyOn(IonicStore.prototype, 'get'); spyOn(IonicStore.prototype, 'set'); spyOn(IonicStore.prototype, 'save'); var npmVersion = IonicCli.npmVersion; var result = IonicCli.checkLatestVersion('2.0.1-beta'); expect(result).toEqual(null); expect(npmVersion).toEqual(IonicCli.npmVersion); expect(IonicStore.prototype.get).not.toHaveBeenCalled(); expect(IonicStore.prototype.set).not.toHaveBeenCalled(); expect(IonicStore.prototype.save).not.toHaveBeenCalled(); }); it('should not check npm if timestamp is recent', function() { spyOn(IonicStore.prototype, 'get').andReturn(new Date().getTime()); spyOn(IonicStore.prototype, 'set'); spyOn(IonicStore.prototype, 'save'); var npmVersion = IonicCli.npmVersion; var result = IonicCli.checkLatestVersion('2.0.1'); expect(result).toEqual(null); expect(npmVersion).toEqual(IonicCli.npmVersion); expect(IonicStore.prototype.set).not.toHaveBeenCalled(); expect(IonicStore.prototype.save).not.toHaveBeenCalled(); }); it('should check npm if timestamp is recent', function(done) { spyOn(IonicStore.prototype, 'get').andReturn(new Date(2016, 1, 1).getTime()); spyOn(IonicStore.prototype, 'set'); spyOn(IonicStore.prototype, 'save'); var revertRequest = IonicCli.__set__('request', function(options, callback) { callback(null, null, '{ "version": "1.0.1" }'); }); IonicCli.checkLatestVersion('2.0.1').then(function() { expect(IonicStore.prototype.set).toHaveBeenCalledWith('versionCheck', jasmine.any(Number)); expect(IonicStore.prototype.save).toHaveBeenCalled(); revertRequest(); done(); }); }); }); describe('printNewsUpdates method', function() { it('should log request info if a valid response is returned', function(done) { spyOn(log, 'info'); var revertRequest = IonicCli.__set__('request', function(options, callback) { callback(null, { statusCode: '200' }, '{ "version": "1.0.1" }'); }); IonicCli.printNewsUpdates().then(function() { expect(log.info).toHaveBeenCalled(); revertRequest(); done(); }); }); }); describe('doRuntimeCheck method', function(done) { it('should update IonicConfig if semver is not met', function() { var version = '0.2.0'; var error = new Error('semver failure'); spyOn(IonicStore.prototype, 'get').andReturn('0.1.0'); spyOn(IonicStore.prototype, 'set'); spyOn(IonicStore.prototype, 'save'); spyOn(semver, 'satisfies').andCallFake(function() { throw error; }); IonicCli.doRuntimeCheck(version).then(function() { expect(IonicStore.prototype.set).toHaveBeenCalledWith('lastVersionChecked', version); expect(IonicStore.prototype.save).toHaveBeenCalled(); done(); }); }); it('should update IonicConfig if lastVersionChecked from IonicConfig is not available', function(done) { var version = '0.2.0'; spyOn(IonicStore.prototype, 'get').andReturn(null); spyOn(IonicStore.prototype, 'set'); spyOn(IonicStore.prototype, 'save'); IonicCli.doRuntimeCheck(version).then(function() { expect(IonicStore.prototype.set).toHaveBeenCalledWith('lastVersionChecked', version); expect(IonicStore.prototype.save).toHaveBeenCalled(); done(); }); }); it('should not update IonicConfig if lastVersionChecked is available and semver is met', function(done) { var version = '0.2.0'; spyOn(IonicStore.prototype, 'get').andReturn('0.2.0'); spyOn(IonicStore.prototype, 'set'); spyOn(IonicStore.prototype, 'save'); spyOn(semver, 'satisfies').andReturn(true); IonicCli.doRuntimeCheck(version).then(function() { expect(IonicStore.prototype.set).not.toHaveBeenCalled(); expect(IonicStore.prototype.save).not.toHaveBeenCalled(); done(); }); }); }); describe('getContentSrc method', function() { it('should call getContentSrc util for process cwd.', function() { spyOn(process, 'cwd').andReturn('/some/dir'); spyOn(Utils, 'getContentSrc').andCallFake(function(param) { return param; }); var result = IonicCli.getContentSrc(); expect(process.cwd).toHaveBeenCalled(); expect(Utils.getContentSrc).toHaveBeenCalledWith('/some/dir'); expect(result).toEqual('/some/dir'); }); }); describe('fail method', function() { it('should call fail util.', function() { IonicCli.fail('some error', 'task help text'); expect(Utils.fail).toHaveBeenCalledWith('some error', 'task help text'); }); }); describe('handleUncaughtExceptions method', function() { it('log an error and then exit if param is a string', function() { spyOn(log, 'error'); spyOn(process, 'exit'); spyOn(Utils, 'errorHandler'); IonicCli.handleUncaughtExceptions('error message'); expect(Utils.errorHandler).toHaveBeenCalledWith('error message'); expect(process.exit).toHaveBeenCalledWith(1); }); it('log an error and then exit if param is an object', function() { spyOn(log, 'error'); spyOn(process, 'exit'); spyOn(Utils, 'errorHandler'); IonicCli.handleUncaughtExceptions({ message: 'error message' }); expect(Utils.errorHandler).toHaveBeenCalledWith('error message'); expect(process.exit).toHaveBeenCalledWith(1); }); }); });