cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From shaz...@apache.org
Subject ios commit: Updating unit tests + unit test runner:\ - moved jasmine.json to tests/spec, next to all the unit tests. elimiantes the need to have an extra spec/ dir at the top level.\ - updated package.json scripts to use the new jasmine config file. also
Date Wed, 14 Jun 2017 22:51:33 GMT
Repository: cordova-ios
Updated Branches:
  refs/heads/master 8c77a0b99 -> df5441df8


Updating unit tests + unit test runner:\
- moved jasmine.json to tests/spec, next to all the unit tests. elimiantes the need to have an extra spec/ dir at the top level.\
- updated package.json scripts to use the new jasmine config file. also updated code coverage command to run the right thing.\
- moved bin/lib/check_reqs.js and bin/lib/versions.js to the project template, and had the commands that are runnable globally (i.e. not from within a generated project) be able to reference them. as such, had to update create.js to change the require paths on the fly for these scripts. this, however, allows us to reference the build js modules directly, opening them up to unit testing.\
- added unit tests for platform API addPlugin method.
- added start of unit tests for cordova/lib scripts. modified `run` module to expose its helper functions for easier unit testing. eliminated a `run --list` end to end test and instead converted to new unit tests for it. refactored Api.spec.js and added very simple tests for the `run` method delegation.
- only run the list-emulator-images, lib/run and Api.prototype.run tests on darwin - simply `require`ing ios-sim has side effects that trigger OS checks, which blow up Windows and Linux test runs.

 This closes #319


Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/df5441df
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/df5441df
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/df5441df

Branch: refs/heads/master
Commit: df5441df874183d3d36b64e84969ebc7f0838f05
Parents: 8c77a0b
Author: filmaj <maj.fil@gmail.com>
Authored: Tue Jun 13 15:56:12 2017 -0500
Committer: Shazron Abdullah <shazron@gmail.com>
Committed: Wed Jun 14 15:51:16 2017 -0700

----------------------------------------------------------------------
 bin/apple_ios_version                           |   2 +-
 bin/apple_osx_version                           |   2 +-
 bin/apple_xcode_version                         |   2 +-
 bin/check_reqs                                  |   2 +-
 bin/lib/check_reqs.js                           | 227 -------------------
 bin/lib/create.js                               |  13 +-
 bin/lib/versions.js                             | 196 ----------------
 bin/templates/scripts/cordova/Api.js            |  11 +-
 bin/templates/scripts/cordova/lib/build.js      |   8 +-
 bin/templates/scripts/cordova/lib/check_reqs.js | 227 +++++++++++++++++++
 bin/templates/scripts/cordova/lib/run.js        |  26 ++-
 bin/templates/scripts/cordova/lib/versions.js   | 196 ++++++++++++++++
 package.json                                    |   4 +-
 spec/support/jasmine.json                       |   8 -
 tests/spec/create.spec.js                       |  19 --
 tests/spec/jasmine.json                         |   8 +
 tests/spec/unit/Api.spec.js                     | 152 ++++++++++++-
 tests/spec/unit/lib/list-devices.spec.js        |  48 ++++
 .../spec/unit/lib/list-emulator-images.spec.js  |  39 ++++
 tests/spec/unit/lib/run.spec.js                 |  59 +++++
 20 files changed, 768 insertions(+), 481 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/apple_ios_version
----------------------------------------------------------------------
diff --git a/bin/apple_ios_version b/bin/apple_ios_version
index d397bb6..ec3cbec 100755
--- a/bin/apple_ios_version
+++ b/bin/apple_ios_version
@@ -19,7 +19,7 @@
     under the License.
 */
 
-var versions = require('./lib/versions.js');
+var versions = require('./templates/scripts/cordova/lib/versions.js');
 
 versions.get_apple_ios_version().done(null, function(err) {
     console.log(err);

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/apple_osx_version
----------------------------------------------------------------------
diff --git a/bin/apple_osx_version b/bin/apple_osx_version
index 6e697ad..f22abec 100755
--- a/bin/apple_osx_version
+++ b/bin/apple_osx_version
@@ -19,7 +19,7 @@
     under the License.
 */
 
-var versions = require('./lib/versions.js');
+var versions = require('./templates/scripts/cordova/lib/versions.js');
 
 versions.get_apple_osx_version().done(null, function(err) {
     console.log(err);

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/apple_xcode_version
----------------------------------------------------------------------
diff --git a/bin/apple_xcode_version b/bin/apple_xcode_version
index 112eba3..d21285c 100755
--- a/bin/apple_xcode_version
+++ b/bin/apple_xcode_version
@@ -19,7 +19,7 @@
     under the License.
 */
 
-var versions = require('./lib/versions.js');
+var versions = require('./templates/scripts/cordova/lib/versions.js');
 
 versions.get_apple_xcode_version().done(function (version) {
     console.log(version);

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/check_reqs
----------------------------------------------------------------------
diff --git a/bin/check_reqs b/bin/check_reqs
index d101ccd..eaaabaf 100755
--- a/bin/check_reqs
+++ b/bin/check_reqs
@@ -19,7 +19,7 @@
        under the License.
 */
 
-var check_reqs = require('./lib/check_reqs');
+var check_reqs = require('./templates/scripts/cordova/lib/check_reqs');
 
 // check for help flag
 if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) > -1) {

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/lib/check_reqs.js
----------------------------------------------------------------------
diff --git a/bin/lib/check_reqs.js b/bin/lib/check_reqs.js
deleted file mode 100644
index 97877af..0000000
--- a/bin/lib/check_reqs.js
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
-*/
-'use strict';
-
-const Q   = require('q'),
-    shell = require('shelljs'),
-    util  = require('util'),
-    versions = require('./versions');
-
-const SUPPORTED_OS_PLATFORMS = [ 'darwin' ];
-
-const XCODEBUILD_MIN_VERSION = '7.0.0';
-const XCODEBUILD_NOT_FOUND_MESSAGE =
-    'Please install version ' + XCODEBUILD_MIN_VERSION + ' or greater from App Store';
-
-const IOS_DEPLOY_MIN_VERSION = '1.9.0';
-const IOS_DEPLOY_NOT_FOUND_MESSAGE =
-    'Please download, build and install version ' + IOS_DEPLOY_MIN_VERSION + ' or greater' +
-    ' from https://github.com/phonegap/ios-deploy into your path, or do \'npm install -g ios-deploy\'';
-
-const COCOAPODS_MIN_VERSION = '1.0.1';
-const COCOAPODS_NOT_FOUND_MESSAGE =
-    'Please install version ' + COCOAPODS_MIN_VERSION + ' or greater from https://cocoapods.org/';
-const COCOAPODS_NOT_SYNCED_MESSAGE =
-    'The CocoaPods repo has not been synced yet, this will take a long time (approximately 500MB as of Sept 2016). Please run `pod setup` first to sync the repo.';
-const COCOAPODS_SYNCED_MIN_SIZE = 475; // in megabytes
-const COCOAPODS_SYNC_ERROR_MESSAGE =
-    'The CocoaPods repo has been created, but there appears to be a sync error. The repo size should be at least ' + COCOAPODS_SYNCED_MIN_SIZE + '. Please run `pod setup --verbose` to sync the repo.';
-const COCOAPODS_REPO_NOT_FOUND_MESSAGE = 'The CocoaPods repo at ~/.cocoapods was not found.';
-
-/**
- * Checks if xcode util is available
- * @return {Promise} Returns a promise either resolved with xcode version or rejected
- */
-module.exports.run = module.exports.check_xcodebuild = function () {
-    return checkTool('xcodebuild', XCODEBUILD_MIN_VERSION, XCODEBUILD_NOT_FOUND_MESSAGE);
-};
-
-/**
- * Checks if ios-deploy util is available
- * @return {Promise} Returns a promise either resolved with ios-deploy version or rejected
- */
-module.exports.check_ios_deploy = function () {
-    return checkTool('ios-deploy', IOS_DEPLOY_MIN_VERSION, IOS_DEPLOY_NOT_FOUND_MESSAGE);
-};
-
-module.exports.check_os = function () {
-    // Build iOS apps available for OSX platform only, so we reject on others platforms
-    return os_platform_is_supported() ?
-        Q.resolve(process.platform) :
-        Q.reject('Cordova tooling for iOS requires Apple macOS');
-};
-
-function os_platform_is_supported() {
-    return (SUPPORTED_OS_PLATFORMS.indexOf(process.platform) != -1);
-}
-
-function check_cocoapod_tool(toolChecker) {
-    toolChecker = toolChecker || checkTool;
-    if (os_platform_is_supported()) { // CB-12856
-        return toolChecker('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods');
-    } else {
-        return Q.resolve({ 
-            'ignore': true, 
-            'ignoreMessage': `CocoaPods check and installation ignored on ${process.platform}`
-        });
-    }   
-}
-
-/**
- * Checks if cocoapods repo size is what is expected
- * @return {Promise} Returns a promise either resolved or rejected
- */
-module.exports.check_cocoapods_repo_size = function () {
-    return check_cocoapod_tool()
-    .then(function(toolOptions) {
-        // check size of ~/.cocoapods repo
-        let commandString = util.format('du -sh %s/.cocoapods', process.env.HOME);
-        let command = shell.exec(commandString,  { silent:true });
-        // command.output is e.g "750M   path/to/.cocoapods", we just scan the number
-        let size = toolOptions.ignore? 0 : parseFloat(command.output);
-
-        if (toolOptions.ignore || command.code === 0) { // success, parse output
-            return Q.resolve(size, toolOptions);
-        } else { // error, perhaps not found 
-            return Q.reject(util.format('%s (%s)', COCOAPODS_REPO_NOT_FOUND_MESSAGE, command.output));
-        }
-    })
-    .then(function(repoSize, toolOptions) {
-        if (toolOptions.ignore || COCOAPODS_SYNCED_MIN_SIZE <= repoSize) { // success, expected size
-            return Q.resolve(toolOptions);
-        } else {
-            return Q.reject(COCOAPODS_SYNC_ERROR_MESSAGE);
-        }        
-    });
-};
-
-/**
- * Checks if cocoapods is available, and whether the repo is synced (because it takes a long time to download)
- * @return {Promise} Returns a promise either resolved or rejected
- */
-module.exports.check_cocoapods = function (toolChecker) {
-    return check_cocoapod_tool(toolChecker)
-    // check whether the cocoapods repo has been synced through `pod repo` command
-    // a value of '0 repos' means it hasn't been synced
-    .then(function(toolOptions) {
-        let code = shell.exec('pod repo | grep -e "^0 repos"',  { silent:true }).code;
-        let repoIsSynced = (code !== 0);
-
-        if (toolOptions.ignore || repoIsSynced) {
-            // return check_cocoapods_repo_size();
-            // we could check the repo size above, but it takes too long.
-            return Q.resolve(toolOptions);
-        } else {
-            return Q.reject(COCOAPODS_NOT_SYNCED_MESSAGE);
-        }
-    });
-};
-
-/**
- * Checks if specific tool is available.
- * @param  {String} tool       Tool name to check. Known tools are 'xcodebuild' and 'ios-deploy'
- * @param  {Number} minVersion Min allowed tool version.
- * @param  {String} message    Message that will be used to reject promise.
- * @param  {String} toolFriendlyName  Friendly name of the tool, to report to the user. Optional.
- * @return {Promise}           Returns a promise either resolved with tool version or rejected
- */
-function checkTool (tool, minVersion, message, toolFriendlyName) {
-    toolFriendlyName = toolFriendlyName || tool;
-
-    // Check whether tool command is available at all
-    let tool_command = shell.which(tool);
-    if (!tool_command) {
-        return Q.reject(toolFriendlyName + ' was not found. ' + (message || ''));
-    }
-    
-    // check if tool version is greater than specified one
-    return versions.get_tool_version(tool).then(function (version) {
-        version = version.trim();
-        return versions.compareVersions(version, minVersion) >= 0 ?
-            Q.resolve({ 'version': version }) :
-            Q.reject('Cordova needs ' + toolFriendlyName + ' version ' + minVersion +
-              ' or greater, you have version ' + version + '. ' + (message || ''));
-    });
-}
-
-/**
- * Object that represents one of requirements for current platform.
- * @param {String}  id        The unique identifier for this requirements.
- * @param {String}  name      The name of requirements. Human-readable field.
- * @param {Boolean} isFatal   Marks the requirement as fatal. If such requirement will fail
- *                            next requirements' checks will be skipped.
- */
-let Requirement = function (id, name, isFatal) {
-    this.id = id;
-    this.name = name;
-    this.installed = false;
-    this.metadata = {};
-    this.isFatal = isFatal || false;
-};
-
-/**
- * Methods that runs all checks one by one and returns a result of checks
- * as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
- *
- * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
- */
-module.exports.check_all = function() {
-
-    const requirements = [
-        new Requirement('os', 'Apple macOS', true),
-        new Requirement('xcode', 'Xcode'),
-        new Requirement('ios-deploy', 'ios-deploy'),
-        new Requirement('CocoaPods', 'CocoaPods')
-    ];
-
-    let result = [];
-    let fatalIsHit = false;
-
-    let checkFns = [
-        module.exports.check_os,
-        module.exports.check_xcodebuild,
-        module.exports.check_ios_deploy,
-        module.exports.check_cocoapods
-    ];
-
-    // Then execute requirement checks one-by-one
-    return checkFns.reduce(function (promise, checkFn, idx) {
-        return promise.then(function () {
-            // If fatal requirement is failed,
-            // we don't need to check others
-            if (fatalIsHit) return Q();
-
-            let requirement = requirements[idx];
-            return checkFn()
-            .then(function (version) {
-                requirement.installed = true;
-                requirement.metadata.version = version;
-                result.push(requirement);
-            }, function (err) {
-                if (requirement.isFatal) fatalIsHit = true;
-                requirement.metadata.reason = err;
-                result.push(requirement);
-            });
-        });
-    }, Q())
-    .then(function () {
-        // When chain is completed, return requirements array to upstream API
-        return result;
-    });
-};

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/lib/create.js
----------------------------------------------------------------------
diff --git a/bin/lib/create.js b/bin/lib/create.js
index effa0d8..90de86a 100755
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -88,13 +88,22 @@ function copyScripts(projectPath, projectName) {
 
     // Copy the check_reqs script
     shell.cp(path.join(binDir, 'check_reqs*'), destScriptsDir);
-    shell.cp(path.join(binDir, 'lib', 'check_reqs.js'), path.join(destScriptsDir, 'lib'));
 
     // Copy the version scripts
     shell.cp(path.join(binDir, 'apple_ios_version'), destScriptsDir);
     shell.cp(path.join(binDir, 'apple_osx_version'), destScriptsDir);
     shell.cp(path.join(binDir, 'apple_xcode_version'), destScriptsDir);
-    shell.cp(path.join(binDir, 'lib', 'versions.js'),  path.join(destScriptsDir, 'lib'));
+
+    // TODO: the two files being edited on-the-fly here are shared between
+    // platform and project-level commands. the below `sed` is updating the
+    // `require` path for the two libraries. if there's a better way to share
+    // modules across both the repo and generated projects, we should make sure
+    // to remove/update this.
+    var path_regex = /templates\/scripts\/cordova\//;
+    shell.sed('-i', path_regex, '', path.join(destScriptsDir, 'check_reqs'));
+    shell.sed('-i', path_regex, '', path.join(destScriptsDir, 'apple_ios_version'));
+    shell.sed('-i', path_regex, '', path.join(destScriptsDir, 'apple_osx_version'));
+    shell.sed('-i', path_regex, '', path.join(destScriptsDir, 'apple_xcode_version'));
 
     // CB-11792 do a token replace for __PROJECT_NAME__ in .xcconfig
     var project_name_esc = projectName.replace(/&/g, '\\&');

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/lib/versions.js
----------------------------------------------------------------------
diff --git a/bin/lib/versions.js b/bin/lib/versions.js
deleted file mode 100755
index da31d4f..0000000
--- a/bin/lib/versions.js
+++ /dev/null
@@ -1,196 +0,0 @@
-#!/usr/bin/env node
-
-/*
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-*/
-
-var child_process = require('child_process'),
-    Q = require('q');
-
-exports.get_apple_ios_version = function() {
-    var d = Q.defer();
-    child_process.exec('xcodebuild -showsdks', function(error, stdout, stderr) {
-        if (error) {
-            d.reject(stderr);
-        }
-        else {
-            d.resolve(stdout);
-        }
-    });
-
-    return d.promise.then(function(output) {
-        var regex = /[0-9]*\.[0-9]*/,
-            versions = [],
-            regexIOS = /^iOS \d+/;
-        output = output.split('\n');
-        for (var i = 0; i < output.length; i++) {
-            if (output[i].trim().match(regexIOS)) {
-                versions[versions.length] = parseFloat(output[i].match(regex)[0]);
-                }
-        }
-        versions.sort();
-        console.log(versions[0]);
-        return Q();
-    }, function(stderr) {
-        return Q.reject(stderr);
-    });
-};
-
-exports.get_apple_osx_version = function() {
-    var d = Q.defer();
-    child_process.exec('xcodebuild -showsdks', function(error, stdout, stderr) {
-        if (error) {
-            d.reject(stderr);
-        }
-        else {
-            d.resolve(stdout);
-        }
-    });
-
-    return d.promise.then(function(output) {
-        var regex = /[0-9]*\.[0-9]*/,
-            versions = [],
-            regexOSX = /^OS X \d+/;
-        output = output.split('\n');
-        for (var i = 0; i < output.length; i++) {
-            if (output[i].trim().match(regexOSX)) {
-                versions[versions.length] = parseFloat(output[i].match(regex)[0]);
-            }
-        }
-        versions.sort();
-        console.log(versions[0]);
-        return Q();
-    }, function(stderr) {
-        return Q.reject(stderr);
-    });
-};
-
-exports.get_apple_xcode_version = function() {
-    var d = Q.defer();
-    child_process.exec('xcodebuild -version', function(error, stdout, stderr) {
-        var versionMatch = /Xcode (.*)/.exec(stdout);
-        if (error || !versionMatch) {
-            d.reject(stderr);
-        } else {
-            d.resolve(versionMatch[1]);
-        }
-    });
-    return d.promise;
-};
-
-/**
- * Gets ios-deploy util version
- * @return {Promise} Promise that either resolved with ios-deploy version
- *                           or rejected in case of error
- */
-exports.get_ios_deploy_version = function() {
-    var d = Q.defer();
-    child_process.exec('ios-deploy --version', function(error, stdout, stderr) {
-        if (error) {
-            d.reject(stderr);
-        } else {
-            d.resolve(stdout);
-        }
-    });
-    return d.promise;
-};
-
-/**
- * Gets pod (CocoaPods) util version
- * @return {Promise} Promise that either resolved with pod version
- *                           or rejected in case of error
- */
-exports.get_cocoapods_version = function() {
-    var d = Q.defer();
-    child_process.exec('pod --version', function(error, stdout, stderr) {
-        if (error) {
-            d.reject(stderr);
-        } else {
-            d.resolve(stdout);
-        }
-    });
-    return d.promise;
-};
-
-/**
- * Gets ios-sim util version
- * @return {Promise} Promise that either resolved with ios-sim version
- *                           or rejected in case of error
- */
-exports.get_ios_sim_version = function() {
-    var d = Q.defer();
-    child_process.exec('ios-sim --version', function(error, stdout, stderr) {
-        if (error) {
-            d.reject(stderr);
-        } else {
-            d.resolve(stdout);
-        }
-    });
-    return d.promise;
-};
-
-/**
- * Gets specific tool version
- * @param  {String} toolName Tool name to check. Known tools are 'xcodebuild', 'ios-sim' and 'ios-deploy'
- * @return {Promise}         Promise that either resolved with tool version
- *                                   or rejected in case of error
- */
-exports.get_tool_version = function (toolName) {
-    switch (toolName) {
-        case 'xcodebuild': return exports.get_apple_xcode_version();
-        case 'ios-sim': return exports.get_ios_sim_version();
-        case 'ios-deploy': return exports.get_ios_deploy_version();
-        case 'pod': return exports.get_cocoapods_version();
-        default: return Q.reject(toolName + ' is not valid tool name. Valid names are: \'xcodebuild\', \'ios-sim\', \'ios-deploy\', and \'pod\'');
-    }
-};
-
-/**
- * Compares two semver-notated version strings. Returns number
- * that indicates equality of provided version strings.
- * @param  {String} version1 Version to compare
- * @param  {String} version2 Another version to compare
- * @return {Number}          Negative number if first version is lower than the second,
- *                                    positive otherwise and 0 if versions are equal.
- */
-exports.compareVersions = function (version1, version2) {
-    function parseVer (version) {
-        return version.split('.').map(function (value) {
-            // try to convert version segment to Number
-            var parsed = Number(value);
-            // Number constructor is strict enough and will return NaN
-            // if conversion fails. In this case we won't be able to compare versions properly
-            if (isNaN(parsed)) {
-                throw 'Version should contain only numbers and dots';
-            }
-            return parsed;
-        });
-    }
-    var parsedVer1 = parseVer(version1);
-    var parsedVer2 = parseVer(version2);
-
-    // Compare corresponding segments of each version
-    for (var i = 0; i < Math.max(parsedVer1.length, parsedVer2.length); i++) {
-        // if segment is not specified, assume that it is 0
-        // E.g. 3.1 is equal to 3.1.0
-        var ret = (parsedVer1[i] || 0) - (parsedVer2[i] || 0);
-        // if segments are not equal, we're finished
-        if (ret !== 0) return ret;
-    }
-    return 0;
-};

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/templates/scripts/cordova/Api.js
----------------------------------------------------------------------
diff --git a/bin/templates/scripts/cordova/Api.js b/bin/templates/scripts/cordova/Api.js
index b95f8e8..d7e84c0 100644
--- a/bin/templates/scripts/cordova/Api.js
+++ b/bin/templates/scripts/cordova/Api.js
@@ -23,6 +23,7 @@ var fs = require('fs');
 var path = require('path');
 var unorm = require('unorm');
 var projectFile = require('./lib/projectFile');
+var check_reqs = require('./lib/check_reqs');
 var CordovaError = require('cordova-common').CordovaError;
 var CordovaLogger = require('cordova-common').CordovaLogger;
 var events = require('cordova-common').events;
@@ -287,7 +288,6 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
                 podfileFile.write();
                 events.emit('verbose', 'Running `pod install` (to install plugins)');
 
-                var check_reqs = require('./lib/check_reqs');
                 return podfileFile.install(check_reqs.check_cocoapods);
             } else {
                 events.emit('verbose', 'Podfile unchanged, skipping `pod install`');
@@ -367,7 +367,6 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) {
                 podfileFile.write();
                 events.emit('verbose', 'Running `pod install` (to uninstall pods)');
 
-                var check_reqs = require('./lib/check_reqs');
                 return podfileFile.install(check_reqs.check_cocoapods);
             } else {
                 events.emit('verbose', 'Podfile unchanged, skipping `pod install`');
@@ -412,7 +411,7 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) {
  */
 Api.prototype.build = function (buildOptions) {
     var self = this;
-    return require('./lib/check_reqs').run()
+    return check_reqs.run()
     .then(function () {
         return require('./lib/build').run.call(self, buildOptions);
     });
@@ -432,7 +431,7 @@ Api.prototype.build = function (buildOptions) {
  */
 Api.prototype.run = function(runOptions) {
     var self = this;
-    return require('./lib/check_reqs').run()
+    return check_reqs.run()
     .then(function () {
         return require('./lib/run').run.call(self, runOptions);
     });
@@ -446,7 +445,7 @@ Api.prototype.run = function(runOptions) {
  */
 Api.prototype.clean = function(cleanOptions) {
     var self = this;
-    return require('./lib/check_reqs').run()
+    return check_reqs.run()
     .then(function () {
         return require('./lib/clean').run.call(self, cleanOptions);
     })
@@ -464,7 +463,7 @@ Api.prototype.clean = function(cleanOptions) {
  *   objects for current platform.
  */
 Api.prototype.requirements = function() {
-    return require('./lib/check_reqs').check_all();
+    return check_reqs.check_all();
 };
 
 module.exports = Api;

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/templates/scripts/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/bin/templates/scripts/cordova/lib/build.js b/bin/templates/scripts/cordova/lib/build.js
index 29d808a..e2b8312 100644
--- a/bin/templates/scripts/cordova/lib/build.js
+++ b/bin/templates/scripts/cordova/lib/build.js
@@ -27,13 +27,7 @@ var Q     = require('q'),
     plist = require('plist'),
     util = require('util');
 
-var check_reqs;
-try {
-    check_reqs = require('./check_reqs');
-} catch (err) {
-    // For unit tests, check_reqs.js is not a sibling to build.js
-    check_reqs = require('../../../../lib/check_reqs');
-}
+var check_reqs = require('./check_reqs');
 
 var events = require('cordova-common').events;
 

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/templates/scripts/cordova/lib/check_reqs.js
----------------------------------------------------------------------
diff --git a/bin/templates/scripts/cordova/lib/check_reqs.js b/bin/templates/scripts/cordova/lib/check_reqs.js
new file mode 100644
index 0000000..97877af
--- /dev/null
+++ b/bin/templates/scripts/cordova/lib/check_reqs.js
@@ -0,0 +1,227 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+'use strict';
+
+const Q   = require('q'),
+    shell = require('shelljs'),
+    util  = require('util'),
+    versions = require('./versions');
+
+const SUPPORTED_OS_PLATFORMS = [ 'darwin' ];
+
+const XCODEBUILD_MIN_VERSION = '7.0.0';
+const XCODEBUILD_NOT_FOUND_MESSAGE =
+    'Please install version ' + XCODEBUILD_MIN_VERSION + ' or greater from App Store';
+
+const IOS_DEPLOY_MIN_VERSION = '1.9.0';
+const IOS_DEPLOY_NOT_FOUND_MESSAGE =
+    'Please download, build and install version ' + IOS_DEPLOY_MIN_VERSION + ' or greater' +
+    ' from https://github.com/phonegap/ios-deploy into your path, or do \'npm install -g ios-deploy\'';
+
+const COCOAPODS_MIN_VERSION = '1.0.1';
+const COCOAPODS_NOT_FOUND_MESSAGE =
+    'Please install version ' + COCOAPODS_MIN_VERSION + ' or greater from https://cocoapods.org/';
+const COCOAPODS_NOT_SYNCED_MESSAGE =
+    'The CocoaPods repo has not been synced yet, this will take a long time (approximately 500MB as of Sept 2016). Please run `pod setup` first to sync the repo.';
+const COCOAPODS_SYNCED_MIN_SIZE = 475; // in megabytes
+const COCOAPODS_SYNC_ERROR_MESSAGE =
+    'The CocoaPods repo has been created, but there appears to be a sync error. The repo size should be at least ' + COCOAPODS_SYNCED_MIN_SIZE + '. Please run `pod setup --verbose` to sync the repo.';
+const COCOAPODS_REPO_NOT_FOUND_MESSAGE = 'The CocoaPods repo at ~/.cocoapods was not found.';
+
+/**
+ * Checks if xcode util is available
+ * @return {Promise} Returns a promise either resolved with xcode version or rejected
+ */
+module.exports.run = module.exports.check_xcodebuild = function () {
+    return checkTool('xcodebuild', XCODEBUILD_MIN_VERSION, XCODEBUILD_NOT_FOUND_MESSAGE);
+};
+
+/**
+ * Checks if ios-deploy util is available
+ * @return {Promise} Returns a promise either resolved with ios-deploy version or rejected
+ */
+module.exports.check_ios_deploy = function () {
+    return checkTool('ios-deploy', IOS_DEPLOY_MIN_VERSION, IOS_DEPLOY_NOT_FOUND_MESSAGE);
+};
+
+module.exports.check_os = function () {
+    // Build iOS apps available for OSX platform only, so we reject on others platforms
+    return os_platform_is_supported() ?
+        Q.resolve(process.platform) :
+        Q.reject('Cordova tooling for iOS requires Apple macOS');
+};
+
+function os_platform_is_supported() {
+    return (SUPPORTED_OS_PLATFORMS.indexOf(process.platform) != -1);
+}
+
+function check_cocoapod_tool(toolChecker) {
+    toolChecker = toolChecker || checkTool;
+    if (os_platform_is_supported()) { // CB-12856
+        return toolChecker('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods');
+    } else {
+        return Q.resolve({ 
+            'ignore': true, 
+            'ignoreMessage': `CocoaPods check and installation ignored on ${process.platform}`
+        });
+    }   
+}
+
+/**
+ * Checks if cocoapods repo size is what is expected
+ * @return {Promise} Returns a promise either resolved or rejected
+ */
+module.exports.check_cocoapods_repo_size = function () {
+    return check_cocoapod_tool()
+    .then(function(toolOptions) {
+        // check size of ~/.cocoapods repo
+        let commandString = util.format('du -sh %s/.cocoapods', process.env.HOME);
+        let command = shell.exec(commandString,  { silent:true });
+        // command.output is e.g "750M   path/to/.cocoapods", we just scan the number
+        let size = toolOptions.ignore? 0 : parseFloat(command.output);
+
+        if (toolOptions.ignore || command.code === 0) { // success, parse output
+            return Q.resolve(size, toolOptions);
+        } else { // error, perhaps not found 
+            return Q.reject(util.format('%s (%s)', COCOAPODS_REPO_NOT_FOUND_MESSAGE, command.output));
+        }
+    })
+    .then(function(repoSize, toolOptions) {
+        if (toolOptions.ignore || COCOAPODS_SYNCED_MIN_SIZE <= repoSize) { // success, expected size
+            return Q.resolve(toolOptions);
+        } else {
+            return Q.reject(COCOAPODS_SYNC_ERROR_MESSAGE);
+        }        
+    });
+};
+
+/**
+ * Checks if cocoapods is available, and whether the repo is synced (because it takes a long time to download)
+ * @return {Promise} Returns a promise either resolved or rejected
+ */
+module.exports.check_cocoapods = function (toolChecker) {
+    return check_cocoapod_tool(toolChecker)
+    // check whether the cocoapods repo has been synced through `pod repo` command
+    // a value of '0 repos' means it hasn't been synced
+    .then(function(toolOptions) {
+        let code = shell.exec('pod repo | grep -e "^0 repos"',  { silent:true }).code;
+        let repoIsSynced = (code !== 0);
+
+        if (toolOptions.ignore || repoIsSynced) {
+            // return check_cocoapods_repo_size();
+            // we could check the repo size above, but it takes too long.
+            return Q.resolve(toolOptions);
+        } else {
+            return Q.reject(COCOAPODS_NOT_SYNCED_MESSAGE);
+        }
+    });
+};
+
+/**
+ * Checks if specific tool is available.
+ * @param  {String} tool       Tool name to check. Known tools are 'xcodebuild' and 'ios-deploy'
+ * @param  {Number} minVersion Min allowed tool version.
+ * @param  {String} message    Message that will be used to reject promise.
+ * @param  {String} toolFriendlyName  Friendly name of the tool, to report to the user. Optional.
+ * @return {Promise}           Returns a promise either resolved with tool version or rejected
+ */
+function checkTool (tool, minVersion, message, toolFriendlyName) {
+    toolFriendlyName = toolFriendlyName || tool;
+
+    // Check whether tool command is available at all
+    let tool_command = shell.which(tool);
+    if (!tool_command) {
+        return Q.reject(toolFriendlyName + ' was not found. ' + (message || ''));
+    }
+    
+    // check if tool version is greater than specified one
+    return versions.get_tool_version(tool).then(function (version) {
+        version = version.trim();
+        return versions.compareVersions(version, minVersion) >= 0 ?
+            Q.resolve({ 'version': version }) :
+            Q.reject('Cordova needs ' + toolFriendlyName + ' version ' + minVersion +
+              ' or greater, you have version ' + version + '. ' + (message || ''));
+    });
+}
+
+/**
+ * Object that represents one of requirements for current platform.
+ * @param {String}  id        The unique identifier for this requirements.
+ * @param {String}  name      The name of requirements. Human-readable field.
+ * @param {Boolean} isFatal   Marks the requirement as fatal. If such requirement will fail
+ *                            next requirements' checks will be skipped.
+ */
+let Requirement = function (id, name, isFatal) {
+    this.id = id;
+    this.name = name;
+    this.installed = false;
+    this.metadata = {};
+    this.isFatal = isFatal || false;
+};
+
+/**
+ * Methods that runs all checks one by one and returns a result of checks
+ * as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
+ *
+ * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
+ */
+module.exports.check_all = function() {
+
+    const requirements = [
+        new Requirement('os', 'Apple macOS', true),
+        new Requirement('xcode', 'Xcode'),
+        new Requirement('ios-deploy', 'ios-deploy'),
+        new Requirement('CocoaPods', 'CocoaPods')
+    ];
+
+    let result = [];
+    let fatalIsHit = false;
+
+    let checkFns = [
+        module.exports.check_os,
+        module.exports.check_xcodebuild,
+        module.exports.check_ios_deploy,
+        module.exports.check_cocoapods
+    ];
+
+    // Then execute requirement checks one-by-one
+    return checkFns.reduce(function (promise, checkFn, idx) {
+        return promise.then(function () {
+            // If fatal requirement is failed,
+            // we don't need to check others
+            if (fatalIsHit) return Q();
+
+            let requirement = requirements[idx];
+            return checkFn()
+            .then(function (version) {
+                requirement.installed = true;
+                requirement.metadata.version = version;
+                result.push(requirement);
+            }, function (err) {
+                if (requirement.isFatal) fatalIsHit = true;
+                requirement.metadata.reason = err;
+                result.push(requirement);
+            });
+        });
+    }, Q())
+    .then(function () {
+        // When chain is completed, return requirements array to upstream API
+        return result;
+    });
+};

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/templates/scripts/cordova/lib/run.js
----------------------------------------------------------------------
diff --git a/bin/templates/scripts/cordova/lib/run.js b/bin/templates/scripts/cordova/lib/run.js
index 0caadf0..d3a2cd1 100644
--- a/bin/templates/scripts/cordova/lib/run.js
+++ b/bin/templates/scripts/cordova/lib/run.js
@@ -40,11 +40,11 @@ module.exports.run = function (runOptions) {
 
     // support for CB-8168 `cordova/run --list`
     if (runOptions.list) {
-        if (runOptions.device) return listDevices();
-        if (runOptions.emulator) return listEmulators();
+        if (runOptions.device) return module.exports.listDevices();
+        if (runOptions.emulator) return module.exports.listEmulators();
         // if no --device or --emulator flag is specified, list both devices and emulators
-        return listDevices().then(function () {
-            return listEmulators();
+        return module.exports.listDevices().then(function () {
+            return module.exports.listEmulators();
         });
     }
 
@@ -74,7 +74,7 @@ module.exports.run = function (runOptions) {
         // select command to run and arguments depending whether
         // we're running on device/emulator
         if (useDevice) {
-            return checkDeviceConnected()
+            return module.exports.checkDeviceConnected()
             .then(function() {
                 // Unpack IPA
                 var ipafile = path.join(buildOutputDir, projectName + '.ipa');
@@ -104,19 +104,27 @@ module.exports.run = function (runOptions) {
                 var extraArgs = [];
                 if (runOptions.argv) {
                      // argv.slice(2) removes node and run.js, filterSupportedArgs removes the run.js args
-                     extraArgs = filterSupportedArgs(runOptions.argv.slice(2));
+                     extraArgs = module.exports.filterSupportedArgs(runOptions.argv.slice(2));
                 }
-                return deployToDevice(appPath, runOptions.target, extraArgs);
+                return module.exports.deployToDevice(appPath, runOptions.target, extraArgs);
             }, function () {
                 // if device connection check failed use emulator then
-                return deployToSim(appPath, runOptions.target);
+                return module.exports.deployToSim(appPath, runOptions.target);
             });
         } else {
-            return deployToSim(appPath, runOptions.target);
+            return module.exports.deployToSim(appPath, runOptions.target);
         }
     });
 };
 
+module.exports.filterSupportedArgs = filterSupportedArgs;
+module.exports.checkDeviceConnected = checkDeviceConnected;
+module.exports.deployToDevice = deployToDevice;
+module.exports.deployToSim = deployToSim;
+module.exports.startSim = startSim;
+module.exports.listDevices = listDevices;
+module.exports.listEmulators = listEmulators;
+
 /**
  * Filters the args array and removes supported args for the 'run' command.
  *

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/bin/templates/scripts/cordova/lib/versions.js
----------------------------------------------------------------------
diff --git a/bin/templates/scripts/cordova/lib/versions.js b/bin/templates/scripts/cordova/lib/versions.js
new file mode 100755
index 0000000..da31d4f
--- /dev/null
+++ b/bin/templates/scripts/cordova/lib/versions.js
@@ -0,0 +1,196 @@
+#!/usr/bin/env node
+
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var child_process = require('child_process'),
+    Q = require('q');
+
+exports.get_apple_ios_version = function() {
+    var d = Q.defer();
+    child_process.exec('xcodebuild -showsdks', function(error, stdout, stderr) {
+        if (error) {
+            d.reject(stderr);
+        }
+        else {
+            d.resolve(stdout);
+        }
+    });
+
+    return d.promise.then(function(output) {
+        var regex = /[0-9]*\.[0-9]*/,
+            versions = [],
+            regexIOS = /^iOS \d+/;
+        output = output.split('\n');
+        for (var i = 0; i < output.length; i++) {
+            if (output[i].trim().match(regexIOS)) {
+                versions[versions.length] = parseFloat(output[i].match(regex)[0]);
+                }
+        }
+        versions.sort();
+        console.log(versions[0]);
+        return Q();
+    }, function(stderr) {
+        return Q.reject(stderr);
+    });
+};
+
+exports.get_apple_osx_version = function() {
+    var d = Q.defer();
+    child_process.exec('xcodebuild -showsdks', function(error, stdout, stderr) {
+        if (error) {
+            d.reject(stderr);
+        }
+        else {
+            d.resolve(stdout);
+        }
+    });
+
+    return d.promise.then(function(output) {
+        var regex = /[0-9]*\.[0-9]*/,
+            versions = [],
+            regexOSX = /^OS X \d+/;
+        output = output.split('\n');
+        for (var i = 0; i < output.length; i++) {
+            if (output[i].trim().match(regexOSX)) {
+                versions[versions.length] = parseFloat(output[i].match(regex)[0]);
+            }
+        }
+        versions.sort();
+        console.log(versions[0]);
+        return Q();
+    }, function(stderr) {
+        return Q.reject(stderr);
+    });
+};
+
+exports.get_apple_xcode_version = function() {
+    var d = Q.defer();
+    child_process.exec('xcodebuild -version', function(error, stdout, stderr) {
+        var versionMatch = /Xcode (.*)/.exec(stdout);
+        if (error || !versionMatch) {
+            d.reject(stderr);
+        } else {
+            d.resolve(versionMatch[1]);
+        }
+    });
+    return d.promise;
+};
+
+/**
+ * Gets ios-deploy util version
+ * @return {Promise} Promise that either resolved with ios-deploy version
+ *                           or rejected in case of error
+ */
+exports.get_ios_deploy_version = function() {
+    var d = Q.defer();
+    child_process.exec('ios-deploy --version', function(error, stdout, stderr) {
+        if (error) {
+            d.reject(stderr);
+        } else {
+            d.resolve(stdout);
+        }
+    });
+    return d.promise;
+};
+
+/**
+ * Gets pod (CocoaPods) util version
+ * @return {Promise} Promise that either resolved with pod version
+ *                           or rejected in case of error
+ */
+exports.get_cocoapods_version = function() {
+    var d = Q.defer();
+    child_process.exec('pod --version', function(error, stdout, stderr) {
+        if (error) {
+            d.reject(stderr);
+        } else {
+            d.resolve(stdout);
+        }
+    });
+    return d.promise;
+};
+
+/**
+ * Gets ios-sim util version
+ * @return {Promise} Promise that either resolved with ios-sim version
+ *                           or rejected in case of error
+ */
+exports.get_ios_sim_version = function() {
+    var d = Q.defer();
+    child_process.exec('ios-sim --version', function(error, stdout, stderr) {
+        if (error) {
+            d.reject(stderr);
+        } else {
+            d.resolve(stdout);
+        }
+    });
+    return d.promise;
+};
+
+/**
+ * Gets specific tool version
+ * @param  {String} toolName Tool name to check. Known tools are 'xcodebuild', 'ios-sim' and 'ios-deploy'
+ * @return {Promise}         Promise that either resolved with tool version
+ *                                   or rejected in case of error
+ */
+exports.get_tool_version = function (toolName) {
+    switch (toolName) {
+        case 'xcodebuild': return exports.get_apple_xcode_version();
+        case 'ios-sim': return exports.get_ios_sim_version();
+        case 'ios-deploy': return exports.get_ios_deploy_version();
+        case 'pod': return exports.get_cocoapods_version();
+        default: return Q.reject(toolName + ' is not valid tool name. Valid names are: \'xcodebuild\', \'ios-sim\', \'ios-deploy\', and \'pod\'');
+    }
+};
+
+/**
+ * Compares two semver-notated version strings. Returns number
+ * that indicates equality of provided version strings.
+ * @param  {String} version1 Version to compare
+ * @param  {String} version2 Another version to compare
+ * @return {Number}          Negative number if first version is lower than the second,
+ *                                    positive otherwise and 0 if versions are equal.
+ */
+exports.compareVersions = function (version1, version2) {
+    function parseVer (version) {
+        return version.split('.').map(function (value) {
+            // try to convert version segment to Number
+            var parsed = Number(value);
+            // Number constructor is strict enough and will return NaN
+            // if conversion fails. In this case we won't be able to compare versions properly
+            if (isNaN(parsed)) {
+                throw 'Version should contain only numbers and dots';
+            }
+            return parsed;
+        });
+    }
+    var parsedVer1 = parseVer(version1);
+    var parsedVer2 = parseVer(version2);
+
+    // Compare corresponding segments of each version
+    for (var i = 0; i < Math.max(parsedVer1.length, parsedVer2.length); i++) {
+        // if segment is not specified, assume that it is 0
+        // E.g. 3.1 is equal to 3.1.0
+        var ret = (parsedVer1[i] || 0) - (parsedVer2[i] || 0);
+        // if segments are not equal, we're finished
+        if (ret !== 0) return ret;
+    }
+    return 0;
+};

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 0947bd3..c61e86f 100644
--- a/package.json
+++ b/package.json
@@ -20,13 +20,13 @@
   "scripts": {
     "test": "npm run e2e-tests && npm run objc-tests && npm run unit-tests",
     "posttest": "npm run jshint",
-    "cover": "istanbul cover --root bin/templates/cordova --print detail jasmine",
+    "cover": "istanbul cover --root bin/templates/scripts/cordova --print detail jasmine -- --config=tests/spec/jasmine.json",
     "e2e-tests": "jasmine tests/spec/create.spec.js",
     "objc-tests": "npm run objc-tests-lib && npm run objc-tests-framework",
     "objc-tests-lib": "xcodebuild test -workspace tests/cordova-ios.xcworkspace -scheme CordovaLibTests -destination \"platform=iOS Simulator,name=iPhone 5\" CONFIGURATION_BUILD_DIR=\"`mktemp -d 2>/dev/null || mktemp -d -t 'cordova-ios'`\"",
     "objc-tests-framework": "xcodebuild test -workspace tests/cordova-ios.xcworkspace -scheme CordovaFrameworkApp -destination \"platform=iOS Simulator,name=iPhone 5\" CONFIGURATION_BUILD_DIR=\"`mktemp -d 2>/dev/null || mktemp -d -t 'cordova-ios'`\"",
     "preobjc-tests": "tests/scripts/killsim.js",
-    "unit-tests": "jasmine",
+    "unit-tests": "jasmine --config=tests/spec/jasmine.json",
     "jshint": "jshint bin tests"
   },
   "author": "Apache Software Foundation",

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/spec/support/jasmine.json
----------------------------------------------------------------------
diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json
deleted file mode 100644
index 6824f85..0000000
--- a/spec/support/jasmine.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "spec_dir": "spec",
-    "spec_files": [
-        "../tests/spec/unit/**/*[sS]pec.js"
-    ],
-    "stopSpecOnExpectationFailure": false,
-    "random": false
-}

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/tests/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/tests/spec/create.spec.js b/tests/spec/create.spec.js
index 0791632..f12b717 100644
--- a/tests/spec/create.spec.js
+++ b/tests/spec/create.spec.js
@@ -108,23 +108,4 @@ describe('create', function() {
 
        createAndBuild(projectname, projectid);
     });
-
-});
-
-describe('end-to-end list validation', function(){
-    it('Test#008 : handles list parameter', function() {
-        shell.cp('-f', path.join(cordova_bin, 'check_reqs'), path.join(cordova_bin, 'templates', 'scripts', 'cordova', 'check_reqs'));
-        shell.cp('-f', path.join(cordova_bin, 'lib', 'check_reqs.js'), path.join(cordova_bin, 'templates', 'scripts', 'cordova', 'lib', 'check_reqs.js'));
-        shell.cp('-f', path.join(cordova_bin, 'lib', 'versions.js'), path.join(cordova_bin, 'templates', 'scripts', 'cordova', 'lib', 'versions.js'));
-        // create empty .xcodeproj folder to mimic Cordova app structure, otherwise scripts will fail
-        shell.mkdir('-p', path.join(cordova_bin, 'templates', 'scripts', 'HelloCordova.xcodeproj'));
-        var command = '"' + path.join(cordova_bin, 'templates', 'scripts', 'cordova', 'run') + '" --list';
-        var output = shell.exec(command, {silent: true}).output;
-        expect(output).toMatch(/Available iOS Simulators/);
-        expect(output).toMatch(/Available iOS Devices/);
-        shell.rm('-f', path.join(cordova_bin, 'templates', 'scripts', 'cordova', 'check_reqs'));
-        shell.rm('-f', path.join(cordova_bin, 'templates', 'scripts', 'cordova', 'lib', 'check_reqs.js'));
-        shell.rm('-f', path.join(cordova_bin, 'templates', 'scripts', 'cordova', 'lib', 'versions.js'));
-        shell.rm('-rf', path.join(cordova_bin, 'templates', 'scripts', 'HelloCordova.xcodeproj'));
-    });
 });

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/tests/spec/jasmine.json
----------------------------------------------------------------------
diff --git a/tests/spec/jasmine.json b/tests/spec/jasmine.json
new file mode 100644
index 0000000..b95d161
--- /dev/null
+++ b/tests/spec/jasmine.json
@@ -0,0 +1,8 @@
+{
+    "spec_dir": "tests/spec",
+    "spec_files": [
+        "unit/**/*[sS]pec.js"
+    ],
+    "stopSpecOnExpectationFailure": false,
+    "random": false
+}

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/tests/spec/unit/Api.spec.js
----------------------------------------------------------------------
diff --git a/tests/spec/unit/Api.spec.js b/tests/spec/unit/Api.spec.js
index 6792bcd..a08b32e 100644
--- a/tests/spec/unit/Api.spec.js
+++ b/tests/spec/unit/Api.spec.js
@@ -18,8 +18,25 @@
  */
 
 var path = require('path');
+var fs = require('fs');
+var PluginManager = require('cordova-common').PluginManager;
+var events = require('cordova-common').events;
 var Api = require('../../../bin/templates/scripts/cordova/Api');
-var check_reqs = require('../../../bin/lib/check_reqs');
+var check_reqs = require('../../../bin/templates/scripts/cordova/lib/check_reqs');
+
+// The lib/run module pulls in ios-sim, which has a hard requirement that it
+// be run on a Mac OS - simply requiring the module is enough to trigger the
+// environment checks. These checks will blow up on Windows + Linux.
+// So, conditionally pull in the module, and conditionally test the `run`
+// method (more below).
+var run_mod;
+if (process.platform === 'darwin') {
+    run_mod = require('../../../bin/templates/scripts/cordova/lib/run');
+}
+
+var projectFile = require('../../../bin/templates/scripts/cordova/lib/projectFile');
+var Podfile_mod = require('../../../bin/templates/scripts/cordova/lib/Podfile');
+var PodsJson_mod = require('../../../bin/templates/scripts/cordova/lib/PodsJson');
 var Q = require('q');
 var FIXTURES = path.join(__dirname, 'fixtures');
 var iosProjectFixture = path.join(FIXTURES, 'ios-config-xml');
@@ -107,4 +124,137 @@ describe('Platform Api', function () {
 
         });
     });
+
+    describe('.prototype', function () {
+        var api;
+        var projectRoot = '/some/path';
+        beforeEach(function () {
+            spyOn(fs, 'readdirSync').and.returnValue([projectRoot + '/cordova.xcodeproj']);
+            spyOn(projectFile, 'parse').and.returnValue({
+                getPackageName: function () { return 'ios.cordova.io'; }
+            });
+            api = new Api('ios', projectRoot);
+        });
+
+        // See the comment at the top of this file, in the list of requires,
+        // for information on why we conditionall run this test.
+        // tl;dr run_mod requires the ios-sim module, which requires mac OS.
+        if (process.platform === 'darwin') {
+            describe('run', function () {
+                beforeEach(function () {
+                    spyOn(check_reqs, 'run').and.returnValue(Q.resolve());
+                });
+                it('should call into lib/run module', function (done) {
+                    spyOn(run_mod, 'run');
+                    api.run().then(function () {
+                        expect(run_mod.run).toHaveBeenCalled();
+                    }).fail(function (err) {
+                        fail('run fail handler unexpectedly invoked');
+                        console.error(err);
+                    }).done(done);
+                });
+            });
+        }
+
+        describe('addPlugin', function () {
+            var my_plugin = {
+                getFrameworks: function () {}
+            };
+            beforeEach(function () {
+                spyOn(PluginManager, 'get').and.returnValue({
+                    addPlugin: function () { return Q(); }
+                });
+                spyOn(Podfile_mod, 'Podfile');
+                spyOn(PodsJson_mod, 'PodsJson');
+            });
+            it('should assign a package name to plugin variables if one is not explicitly provided via options', function () {
+                var opts = {};
+                api.addPlugin('my cool plugin', opts);
+                expect(opts.variables.PACKAGE_NAME).toEqual('ios.cordova.io');
+            });
+            describe('with frameworks of `podspec` type', function () {
+                var podsjson_mock;
+                var podfile_mock;
+                var my_pod_json = {
+                    type: 'podspec',
+                    src: 'podsource!',
+                    spec: 'podspec!'
+                };
+                beforeEach(function () {
+                    podsjson_mock = jasmine.createSpyObj('podsjson mock', ['get', 'increment', 'write', 'setJson']);
+                    podfile_mock = jasmine.createSpyObj('podfile mock', ['isDirty', 'addSpec', 'write', 'install']);
+                    spyOn(my_plugin, 'getFrameworks').and.returnValue([my_pod_json]);
+                    PodsJson_mod.PodsJson.and.callFake(function () {
+                        return podsjson_mock;
+                    });
+                    Podfile_mod.Podfile.and.callFake(function () {
+                        return podfile_mock;
+                    });
+                });
+                // TODO: a little help with clearly labeling / describing the tests below? :(
+                it('should warn if Pods JSON contains name/src but differs in spec', function (done) {
+                    podsjson_mock.get.and.returnValue({
+                        spec: 'something different from ' + my_pod_json.spec
+                    });
+                    spyOn(events, 'emit');
+                    api.addPlugin(my_plugin)
+                    .then(function () {
+                        expect(events.emit).toHaveBeenCalledWith('warn', jasmine.stringMatching(/which conflicts with another plugin/g));
+                    }).fail(function (err) {
+                        fail('unexpected addPlugin fail handler invoked');
+                        console.error(err);
+                    }).done(done);
+                });
+                it('should increment Pods JSON file if pod name/src already exists in file', function (done) {
+                    podsjson_mock.get.and.returnValue({
+                        spec: my_pod_json.spec
+                    });
+                    api.addPlugin(my_plugin)
+                    .then(function () {
+                        expect(podsjson_mock.increment).toHaveBeenCalledWith('podsource!');
+                    }).fail(function (err) {
+                        fail('unexpected addPlugin fail handler invoked');
+                        console.error(err);
+                    }).done(done);
+                });
+                it('on a new framework/pod name/src/key, it should add a new json to podsjson and add a new spec to podfile', function (done) {
+                    api.addPlugin(my_plugin)
+                    .then(function () {
+                        expect(podsjson_mock.setJson).toHaveBeenCalledWith(my_pod_json.src, jasmine.any(Object));
+                        expect(podfile_mock.addSpec).toHaveBeenCalledWith(my_pod_json.src, my_pod_json.spec);
+                    }).fail(function (err) {
+                        fail('unexpected addPlugin fail handler invoked');
+                        console.error(err);
+                    }).done(done);
+                });
+                it('should write out podfile and install if podfile was changed', function (done) {
+                    podfile_mock.isDirty.and.returnValue(true);
+                    api.addPlugin(my_plugin)
+                    .then(function () {
+                        expect(podfile_mock.write).toHaveBeenCalled();
+                        expect(podfile_mock.install).toHaveBeenCalled();
+                    }).fail(function (err) {
+                        fail('unexpected addPlugin fail handler invoked');
+                        console.error(err);
+                    }).done(done);
+                });
+                it('if two frameworks with the same name are added, should honour the spec of the first-installed plugin', function (done) {
+                    spyOn(events, 'emit');
+                    podsjson_mock.get.and.returnValue({
+                        spec: 'something different from ' + my_pod_json.spec
+                    });
+                    api.addPlugin(my_plugin)
+                    .then(function () {
+                        // Increment will non-destructively set the spec to keep it as it was...
+                        expect(podsjson_mock.increment).toHaveBeenCalledWith(my_pod_json.src);
+                        // ...whereas setJson would overwrite it completely.
+                        expect(podsjson_mock.setJson).not.toHaveBeenCalled();
+                    }).fail(function (err) {
+                        fail('unexpected addPlugin fail handler invoked');
+                        console.error(err);
+                    }).done(done);
+                });
+            });
+        });
+    });
 });

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/tests/spec/unit/lib/list-devices.spec.js
----------------------------------------------------------------------
diff --git a/tests/spec/unit/lib/list-devices.spec.js b/tests/spec/unit/lib/list-devices.spec.js
new file mode 100644
index 0000000..0a5b293
--- /dev/null
+++ b/tests/spec/unit/lib/list-devices.spec.js
@@ -0,0 +1,48 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var list_devices = require('../../../../bin/templates/scripts/cordova/lib/list-devices');
+var Q = require('q');
+
+describe('cordova/lib/list-devices', function () {
+    describe('run method', function () {
+        beforeEach(function () {
+            spyOn(Q, 'all').and.returnValue(Q.resolve());
+            spyOn(Q, 'nfcall');
+        });
+        it('should invoke proper system calls to retrieve connected devices', function () {
+            list_devices.run();
+            expect(Q.nfcall).toHaveBeenCalledWith(jasmine.any(Function), jasmine.stringMatching(/system_profiler.*iPad/g));
+            expect(Q.nfcall).toHaveBeenCalledWith(jasmine.any(Function), jasmine.stringMatching(/system_profiler.*iPod/g));
+            expect(Q.nfcall).toHaveBeenCalledWith(jasmine.any(Function), jasmine.stringMatching(/system_profiler.*iPhone/g));
+        });
+        it('should trim and split standard output and return as array', function (done) {
+            Q.all.and.returnValue(Q.resolve([['   this is\nmy sweet\nstdout\n    ']]));
+            list_devices.run()
+            .then(function (results) {
+                expect(results).toContain('this is');
+                expect(results).toContain('my sweet');
+                expect(results).toContain('stdout');
+            }).fail(function (err) {
+                fail('list-devices fail handler unexpectedly invoked');
+                console.error(err);
+            }).done(done);
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/tests/spec/unit/lib/list-emulator-images.spec.js
----------------------------------------------------------------------
diff --git a/tests/spec/unit/lib/list-emulator-images.spec.js b/tests/spec/unit/lib/list-emulator-images.spec.js
new file mode 100644
index 0000000..2936512
--- /dev/null
+++ b/tests/spec/unit/lib/list-emulator-images.spec.js
@@ -0,0 +1,39 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+// Requiring ios-sim below has some side effects, mainly,
+// it ends up requiring the specific macOS environment bits that
+// allow for interacting with iOS Simulators. On Windows+Linux we are
+// bound to not-have-that.
+if (process.platform === 'darwin') {
+    var list_emus = require('../../../../bin/templates/scripts/cordova/lib/list-emulator-images');
+    var iossim = require('ios-sim');
+
+    describe('cordova/lib/list-emulator-images', function () {
+        describe('run method', function () {
+            beforeEach(function () {
+                spyOn(iossim, 'getdevicetypes');
+            });
+            it('should delegate to the ios-sim getdevicetypes method', function () {
+                list_emus.run();
+                expect(iossim.getdevicetypes).toHaveBeenCalled();
+            });
+        });
+    });
+}

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/df5441df/tests/spec/unit/lib/run.spec.js
----------------------------------------------------------------------
diff --git a/tests/spec/unit/lib/run.spec.js b/tests/spec/unit/lib/run.spec.js
new file mode 100644
index 0000000..4566e15
--- /dev/null
+++ b/tests/spec/unit/lib/run.spec.js
@@ -0,0 +1,59 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+// Requiring lib/run below has some side effects, mainly,
+// it ends up pulling in the ios-sim module and requiring the specific macOS
+// environment bits that allow for interacting with iOS Simulators. On
+// Windows+Linux we are bound to not-have-that.
+if (process.platform === 'darwin') {
+    var run = require('../../../../bin/templates/scripts/cordova/lib/run');
+    var Q = require('q');
+
+    describe('cordova/lib/run', function () {
+        describe('--list option', function () {
+            var deferred;
+            beforeEach(function () {
+                deferred = Q.defer();
+                deferred.resolve();
+                spyOn(run, 'listDevices').and.returnValue(deferred.promise);
+                spyOn(run, 'listEmulators').and.returnValue(deferred.promise);
+            });
+            it('should delegate to listDevices method if `options.device` specified', function () {
+                run.run({list: true, device: true});
+                expect(run.listDevices).toHaveBeenCalled();
+                expect(run.listEmulators).not.toHaveBeenCalled();
+            });
+            it('should delegate to listEmulators method if `options.device` specified', function () {
+                run.run({list: true, emulator: true});
+                expect(run.listDevices).not.toHaveBeenCalled();
+                expect(run.listEmulators).toHaveBeenCalled();
+            });
+            it('should delegate to to both listEmulators and listDevices methods if neither `options.device` nor `options.emulator` are specified', function (done) {
+                run.run({list: true})
+                .then(function () {
+                    expect(run.listDevices).toHaveBeenCalled();
+                    expect(run.listEmulators).toHaveBeenCalled();
+                }).fail(function (err) {
+                    fail('run fail handler unexpectedly invoked');
+                    console.error(err);
+                }).done(done);
+            });
+        });
+    });
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


Mime
View raw message