ionic
Version:
A tool for creating and developing Ionic Framework mobile apps.
1,031 lines (867 loc) • 35.4 kB
JavaScript
;
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);
});
});
});