You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ra...@apache.org on 2018/06/22 13:33:05 UTC

[cordova-lib] branch master updated: Let Jasmine handle async test results (#619)

This is an automated email from the ASF dual-hosted git repository.

raphinesse pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-lib.git


The following commit(s) were added to refs/heads/master by this push:
     new da4b4b3  Let Jasmine handle async test results (#619)
da4b4b3 is described below

commit da4b4b371203777d1f951ee9580c1348ddb36659
Author: Raphael von der GrĂ¼n <ra...@gmail.com>
AuthorDate: Fri Jun 22 15:33:01 2018 +0200

    Let Jasmine handle async test results (#619)
    
    There was a lot of sub-optimal error handling in the tests.
    
    Instead of handling Promise rejection and resolution ourselves, we now
    just return them from the test functions and let Jasmine handle them.
    
    Moreover, this also fixes tons of negative tests that looked something like this:
    
        f().then(function () {
            expect('foo').toBe('bar');
        }).catch(function (err) {
            expect('' + err).toMatch('some message');
        });
    
    Problems being:
    - `expect('foo').toBe('bar')` is less obvious than `fail(...)`
    - catches its own Error from the `.then` only to fail because `err` is missing
    - Does not check that err is an Error and that the message is in `.message`
    
    So these were normalized to look like this:
    
        f().then(function () {
            fail('Expected promise to be rejected');
        }).catch(function (err) {
            expect(err).toEqual(jasmine.any(Error));
            expect(err.message).toMatch('some message');
        });
    
    All in all, this commit has the following benefits:
    - Removes 700 LOC w/out removing any testing
    - Improves output when async tests fail
    - Should make async tests less error prone
    - Reduces Q-API usage to prepare for removal of Q (CB-14159)
---
 integration-tests/HooksRunner.spec.js              | 151 +++--------
 integration-tests/fetch.spec.js                    |  44 ++--
 integration-tests/pkgJson-restore.spec.js          | 128 ++++------
 integration-tests/pkgJson.spec.js                  | 124 +++------
 integration-tests/platform.spec.js                 |  69 ++---
 integration-tests/plugin.spec.js                   |  97 +++----
 integration-tests/plugin_fetch.spec.js             | 162 ++++++------
 integration-tests/plugman_fetch.spec.js            |  65 +++--
 integration-tests/plugman_uninstall.spec.js        |  98 +++----
 spec/cordova/build.spec.js                         |  52 ++--
 spec/cordova/compile.spec.js                       |  94 +++----
 spec/cordova/create.spec.js                        |  34 ++-
 spec/cordova/emulate.spec.js                       | 107 +++-----
 spec/cordova/platform/addHelper.spec.js            | 215 ++++++----------
 spec/cordova/platform/check.spec.js                |  36 +--
 .../platform/getPlatformDetailsFromDir.spec.js     |  38 ++-
 spec/cordova/platform/index.spec.js                |  97 +++----
 spec/cordova/platform/list.spec.js                 |  22 +-
 spec/cordova/platform/platform.spec.js             |  35 ++-
 spec/cordova/platform/remove.spec.js               |  53 ++--
 spec/cordova/plugin/add.spec.js                    | 283 ++++++++-------------
 spec/cordova/plugin/index.spec.js                  |  94 +++----
 spec/cordova/plugin/list.spec.js                   |  63 ++---
 spec/cordova/plugin/remove.spec.js                 |  98 +++----
 spec/cordova/plugin/save.spec.js                   |  48 ++--
 spec/cordova/plugin/search.spec.js                 |  36 +--
 spec/cordova/prepare.spec.js                       | 134 ++++------
 spec/cordova/project-metadata-apis.spec.js         |  12 +-
 spec/cordova/run.spec.js                           | 128 +++++-----
 spec/cordova/util.spec.js                          |   6 +-
 spec/plugman/add_platform.spec.js                  |  28 +-
 spec/plugman/create.spec.js                        |  23 +-
 spec/plugman/install.spec.js                       | 175 +++++--------
 33 files changed, 1070 insertions(+), 1779 deletions(-)

diff --git a/integration-tests/HooksRunner.spec.js b/integration-tests/HooksRunner.spec.js
index 34d3e1b..cd91744 100644
--- a/integration-tests/HooksRunner.spec.js
+++ b/integration-tests/HooksRunner.spec.js
@@ -100,15 +100,11 @@ describe('HooksRunner', function () {
         }).not.toThrow();
     });
 
-    it('Test 003 : should init test fixtures', function (done) {
+    it('Test 003 : should init test fixtures', function () {
         hooksRunner = new HooksRunner(project);
 
         // Add the testing platform.
-        cordova.platform('add', [helpers.testPlatform], {'fetch': true}).fail(function (err) {
-            expect(err).toBeUndefined();
-            console.error(err);
-            done();
-        }).then(function () {
+        return cordova.platform('add', [helpers.testPlatform], {'fetch': true}).then(function () {
             // Add the testing plugin
             projectRoot = cordovaUtil.isCordova();
 
@@ -121,12 +117,8 @@ describe('HooksRunner', function () {
             options = cordovaUtil.preProcessOptions(options);
             hookOptions = { projectRoot: project, cordova: options };
 
-            cordova.plugin('add', testPluginFixturePath, {'fetch': true}).fail(function (err) {
-                expect(err && err.stack).toBeUndefined();
-                done();
-            }).then(function () {
+            return cordova.plugin('add', testPluginFixturePath, {'fetch': true}).then(function () {
                 testPluginInstalledPath = path.join(projectRoot, 'plugins', 'com.plugin.withhooks');
-                done();
             });
         });
     }, 100000);
@@ -232,7 +224,7 @@ describe('HooksRunner', function () {
         }
 
         describe('application hooks', function () {
-            it('Test 004 : should execute hook scripts serially', function (done) {
+            it('Test 004 : should execute hook scripts serially', function () {
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
                 var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
@@ -241,14 +233,10 @@ describe('HooksRunner', function () {
                     expect(hooksOrderFile).toExist();
 
                     expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
-                }).then(function () {
-                    done();
                 });
             });
 
-            it('Test 005 : should execute hook scripts serially from .cordova/hooks/hook_type and hooks/hook_type directories', function (done) {
+            it('Test 005 : should execute hook scripts serially from .cordova/hooks/hook_type and hooks/hook_type directories', function () {
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
                 var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
@@ -260,14 +248,10 @@ describe('HooksRunner', function () {
                     expect(hooksOrderFile).toExist();
 
                     expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
-                }).then(function () {
-                    done();
                 });
             }, 60000);
 
-            it('Test 006 : should execute hook scripts serially from config.xml', function (done) {
+            it('Test 006 : should execute hook scripts serially from config.xml', function () {
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
                 var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
@@ -278,15 +262,12 @@ describe('HooksRunner', function () {
                     expect(hooksOrderFile).toExist();
 
                     expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
                 }).then(function () {
                     restoreAppConfig(projectRoot);
-                    done();
                 });
             });
 
-            it('Test 007 : should execute hook scripts serially from config.xml including platform scripts', function (done) {
+            it('Test 007 : should execute hook scripts serially from config.xml including platform scripts', function () {
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
                 var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
@@ -297,15 +278,12 @@ describe('HooksRunner', function () {
                     expect(hooksOrderFile).toExist();
 
                     expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
                 }).then(function () {
                     restoreAppConfig(projectRoot);
-                    done();
                 });
             });
 
-            it('Test 008 : should filter hook scripts from config.xml by platform', function (done) {
+            it('Test 008 : should filter hook scripts from config.xml by platform', function () {
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
                 var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
@@ -324,17 +302,14 @@ describe('HooksRunner', function () {
 
                     expect(JSON.stringify(hooksOrderFileContents(hooksOrderFile)) ===
                         JSON.stringify(baseScriptResults.slice(0).concat(androidPlatformScriptsResults))).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
                 }).then(function () {
                     restoreAppConfig(projectRoot);
-                    done();
                 });
             });
         });
 
         describe('plugin hooks', function () {
-            it('Test 011 : should filter hook scripts from plugin.xml by platform', function (done) {
+            it('Test 011 : should filter hook scripts from plugin.xml by platform', function () {
                 shell.chmod('-R', 'ug+x', path.join(testPluginInstalledPath, 'scripts'));
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
@@ -354,24 +329,17 @@ describe('HooksRunner', function () {
 
                     expect(JSON.stringify(hooksOrderFileContents(hooksOrderFile)) ===
                         JSON.stringify(baseScriptResults.slice(0).concat(androidPlatformScriptsResults))).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
                 }).then(function () {
                     restorePluginConfig(projectRoot);
-                    done();
                 });
             });
 
-            it('Test 012 : should run before_plugin_uninstall, before_plugin_install, after_plugin_install hooks for a plugin being installed with correct opts.plugin context', function (done) {
+            it('Test 012 : should run before_plugin_uninstall, before_plugin_install, after_plugin_install hooks for a plugin being installed with correct opts.plugin context', function () {
                 var projectRoot = cordovaUtil.isCordova();
 
                 // remove plugin
-                cordova.plugin('rm', 'com.plugin.withhooks').fail(function (err) {
-                    expect(err.stack).toBeUndefined();
-                }).then(function () {
-                    cordova.plugin('add', testPluginFixturePath, {'fetch': true}).fail(function (err) {
-                        expect(err).toBeUndefined();
-                    }).then(function () {
+                return cordova.plugin('rm', 'com.plugin.withhooks').then(function () {
+                    return cordova.plugin('add', testPluginFixturePath, {'fetch': true}).then(function () {
                         testPluginInstalledPath = path.join(projectRoot, 'plugins', 'com.plugin.withhooks');
                         shell.chmod('-R', 'ug+x', path.join(testPluginInstalledPath, 'scripts'));
 
@@ -414,9 +382,7 @@ describe('HooksRunner', function () {
                                 }
                             }
                         });
-                    }).fail(function (err) {
-                        expect(err).toBeUndefined();
-                    }).fin(done);
+                    });
                 });
             });
         });
@@ -436,7 +402,7 @@ describe('HooksRunner', function () {
 		        });
         	});
 
-            it('Test 009 : should execute hook scripts serially from plugin.xml', function (done) {
+            it('Test 009 : should execute hook scripts serially from plugin.xml', function () {
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
                 var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
@@ -447,15 +413,12 @@ describe('HooksRunner', function () {
                     expect(hooksOrderFile).toExist();
 
                     expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
                 }).then(function () {
                     restorePluginConfig(projectRoot);
-                    done();
                 });
             });
 
-            it('Test 010 : should execute hook scripts serially from plugin.xml including platform scripts', function (done) {
+            it('Test 010 : should execute hook scripts serially from plugin.xml including platform scripts', function () {
                 var test_event = 'before_build';
                 var projectRoot = cordovaUtil.isCordova();
                 var hooksOrderFile = path.join(projectRoot, 'hooks_order.txt');
@@ -466,29 +429,22 @@ describe('HooksRunner', function () {
                     expect(hooksOrderFile).toExist();
 
                     expect(hooksOrderFileIsOrdered(hooksOrderFile)).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
                 }).then(function () {
                     restorePluginConfig(projectRoot);
-                    done();
                 });
             });
 
-            it('Test 013 : should not execute the designated hook when --nohooks option specifies the exact hook name', function (done) {
+            it('Test 013 : should not execute the designated hook when --nohooks option specifies the exact hook name', function () {
                 var test_event = 'before_build';
                 hookOptions.nohooks = ['before_build'];
 
                 return hooksRunner.fire(test_event, hookOptions).then(function (msg) {
                     expect(msg).toBeDefined();
                     expect(msg).toBe('hook before_build is disabled.');
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
-                }).then(function () {
-                    done();
                 });
             });
 
-            it('Test 014 : should not execute a set of matched hooks when --nohooks option specifies the hook pattern.', function (done) {
+            it('Test 014 : should not execute a set of matched hooks when --nohooks option specifies the hook pattern.', function () {
                 var test_events = ['before_build', 'after_plugin_add', 'before_platform_rm', 'before_prepare'];
                 hookOptions.nohooks = ['before*'];
 
@@ -502,14 +458,10 @@ describe('HooksRunner', function () {
                             }
                         });
                     });
-                }, Q()).fail(function (err) {
-                    expect(err).toBeUndefined();
-                }).then(function () {
-                    done();
-                });
+                }, Q());
             });
 
-            it('Test 015 : should not execute all hooks when --nohooks option specifies .', function (done) {
+            it('Test 015 : should not execute all hooks when --nohooks option specifies .', function () {
                 var test_events = ['before_build', 'after_plugin_add', 'before_platform_rm', 'before_prepare'];
                 hookOptions.nohooks = ['.'];
 
@@ -520,11 +472,7 @@ describe('HooksRunner', function () {
                             expect(msg).toBe('hook ' + test_event + ' is disabled.');
                         });
                     });
-                }, Q()).fail(function (err) {
-                    expect(err).toBeUndefined();
-                }).then(function () {
-                    done();
-                });
+                }, Q());
             });
         });
 
@@ -537,37 +485,29 @@ describe('HooksRunner', function () {
                 handler.calls.reset();
             });
 
-            it('Test 016 : should fire handlers using cordova.on', function (done) {
+            it('Test 016 : should fire handlers using cordova.on', function () {
                 cordova.on(test_event, handler);
-                hooksRunner.fire(test_event, hookOptions).then(function () {
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
                     expect(handler).toHaveBeenCalled();
-                }).fail(function (err) {
-                    expect(err).not.toBeDefined();
-                }).fin(done);
+                });
             });
 
-            it('Test 017 : should pass the project root folder as parameter into the module-level handlers', function (done) {
+            it('Test 017 : should pass the project root folder as parameter into the module-level handlers', function () {
                 cordova.on(test_event, handler);
-                hooksRunner.fire(test_event, hookOptions).then(function () {
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
                     expect(handler).toHaveBeenCalledWith(hookOptions);
-                }).fail(function (err) {
-                    console.log(err);
-                    expect(err).not.toBeDefined();
-                }).fin(done);
+                });
             });
 
-            it('Test 018 : should be able to stop listening to events using cordova.off', function (done) {
+            it('Test 018 : should be able to stop listening to events using cordova.off', function () {
                 cordova.on(test_event, handler);
                 cordova.off(test_event, handler);
-                hooksRunner.fire(test_event, hookOptions).then(function () {
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
                     expect(handler).not.toHaveBeenCalled();
-                }).fail(function (err) {
-                    console.log(err);
-                    expect(err).toBeUndefined();
-                }).fin(done);
+                });
             });
 
-            it('Test 019 : should execute event listeners serially', function (done) {
+            it('Test 019 : should execute event listeners serially', function () {
                 var h1_fired = false;
                 var h2_fired;
                 var h1 = function () {
@@ -592,15 +532,11 @@ describe('HooksRunner', function () {
                 return hooksRunner.fire(test_event, hookOptions).then(function () {
                     expect(h1_fired).toBe(true);
                     expect(h2_fired).toBe(true);
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
-                }).then(function () {
                     cordova.removeAllListeners(test_event);
-                    done();
                 });
             });
 
-            it('Test 020 : should allow for hook to opt into asynchronous execution and block further hooks from firing using the done callback', function (done) {
+            it('Test 020 : should allow for hook to opt into asynchronous execution and block further hooks from firing using the done callback', function () {
                 var h1_fired = false;
                 var h2_fired;
                 var h1 = function () {
@@ -617,45 +553,40 @@ describe('HooksRunner', function () {
 
                 cordova.on(test_event, h1);
                 cordova.on(test_event, h2);
-                hooksRunner.fire(test_event, hookOptions).then(function () {
+                return hooksRunner.fire(test_event, hookOptions).then(function () {
                     expect(h1_fired).toBe(true);
                     expect(h2_fired).toBe(true);
-                    done();
                 });
             });
 
-            it('Test 021 : should pass data object that fire calls into async handlers', function (done) {
+            it('Test 021 : should pass data object that fire calls into async handlers', function () {
                 var async = function (opts) {
                     expect(opts).toEqual(hookOptions);
                     return Q();
                 };
                 cordova.on(test_event, async);
-                hooksRunner.fire(test_event, hookOptions).then(function () {
-                    done();
-                });
+                return hooksRunner.fire(test_event, hookOptions);
             }, 80000);
 
-            it('Test 022 : should pass data object that fire calls into sync handlers', function (done) {
+            it('Test 022 : should pass data object that fire calls into sync handlers', function () {
                 var async = function (opts) {
                     expect(opts).toEqual(hookOptions);
                 };
                 cordova.on(test_event, async);
-                hooksRunner.fire(test_event, hookOptions).fin(done);
+                return hooksRunner.fire(test_event, hookOptions);
             });
 
-            it('Test 023 : should error if any script exits with non-zero code', function (done) {
-                hooksRunner.fire('fail', hookOptions).then(function () {
+            it('Test 023 : should error if any script exits with non-zero code', function () {
+                return hooksRunner.fire('fail', hookOptions).then(function () {
                     expect('the call').toBe('a failure');
                 }, function (err) {
                     expect(err).toBeDefined();
-                }).fin(done);
+                });
             });
         });
 
-        it('Test 024 :should not error if the hook is unrecognized', function (done) {
-            hooksRunner.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!', hookOptions).fail(function (err) {
-                expect('Call with unrecognized hook ').toBe('successful.\n' + err);
-            }).fin(done);
+        it('Test 024 :should not error if the hook is unrecognized', function () {
+            return hooksRunner.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!', hookOptions);
         });
     });
 
diff --git a/integration-tests/fetch.spec.js b/integration-tests/fetch.spec.js
index 4d92259..3530078 100644
--- a/integration-tests/fetch.spec.js
+++ b/integration-tests/fetch.spec.js
@@ -47,8 +47,8 @@ describe('end-to-end plugin dependency tests', function () {
         shell.rm('-rf', tmpDir);
     });
 
-    it('Test 029 : should fail if dependency already installed is wrong version', function (done) {
-        cordova.create('hello3')
+    it('Test 029 : should fail if dependency already installed is wrong version', function () {
+        return cordova.create('hello3')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'android', {'fetch': true});
@@ -59,12 +59,11 @@ describe('end-to-end plugin dependency tests', function () {
                 return cordova.plugin('add', plugins['Test1'], {'fetch': true});
             }).fail(function (err) {
                 expect(err.message).toContain('does not satisfy dependency plugin requirement');
-            })
-            .fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test 030 : should pass if dependency already installed is wrong version with --force', function (done) {
-        cordova.create('hello3')
+    it('Test 030 : should pass if dependency already installed is wrong version with --force', function () {
+        return cordova.create('hello3')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'android', {'fetch': true});
@@ -78,16 +77,12 @@ describe('end-to-end plugin dependency tests', function () {
             })
             .then(function () {
                 expect(path.join(pluginsDir, 'Test1')).toExist();
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test 031 : should pass if dependency already installed is same major version (if specific version is specified)', function (done) {
+    it('Test 031 : should pass if dependency already installed is same major version (if specific version is specified)', function () {
         // Test1 requires cordova-plugin-file version 2.0.0 (which should automatically turn into ^2.0.0); we'll install version 2.1.0
-        cordova.create('hello3')
+        return cordova.create('hello3')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'android', {'fetch': true});
@@ -101,18 +96,13 @@ describe('end-to-end plugin dependency tests', function () {
             })
             .then(function () {
                 expect(path.join(pluginsDir, 'Test1')).toExist();
-            })
-            .fail(function (err) {
-                // console.error(err);
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test 032 : should handle two plugins with same dependent plugin', function (done) {
+    it('Test 032 : should handle two plugins with same dependent plugin', function () {
         // Test1 and Test2 have compatible dependencies on cordova-plugin-file
         // Test1 and Test3 have incompatible dependencies on cordova-plugin-file
-        cordova.create('hello3')
+        return cordova.create('hello3')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'android', {'fetch': true});
@@ -132,14 +122,13 @@ describe('end-to-end plugin dependency tests', function () {
                 expect(path.join(pluginsDir, 'Test2')).toExist();
                 expect(path.join(pluginsDir, 'Test3')).not.toExist();
                 expect(err.message).toContain('does not satisfy dependency plugin requirement');
-            }, TIMEOUT)
-            .fin(done);
+            }, TIMEOUT);
     }, TIMEOUT);
 
-    it('Test 033 : should use a dev version of a dependent plugin if it is already installed', function (done) {
+    it('Test 033 : should use a dev version of a dependent plugin if it is already installed', function () {
         // Test4 has this dependency in its plugin.xml:
         // <dependency id="cordova-plugin-file" url="https://github.com/apache/cordova-plugin-file" />
-        cordova.create('hello3')
+        return cordova.create('hello3')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'android', {'fetch': true});
@@ -153,9 +142,6 @@ describe('end-to-end plugin dependency tests', function () {
             .then(function () {
                 expect(path.join(pluginsDir, 'cordova-plugin-file')).toExist();
                 expect(path.join(pluginsDir, 'Test4')).toExist();
-            }, function (error) {
-                fail(error);
-            })
-            .fin(done);
+            });
     }, TIMEOUT);
 });
diff --git a/integration-tests/pkgJson-restore.spec.js b/integration-tests/pkgJson-restore.spec.js
index 1623858..e045e60 100644
--- a/integration-tests/pkgJson-restore.spec.js
+++ b/integration-tests/pkgJson-restore.spec.js
@@ -69,7 +69,7 @@ describe('tests platform/spec restore with --save', function () {
     *   add to pkg.json with a '^' and to config.xml with a '~'. When prepare is run,
     *   pkg.json will have no change and config.xml (first char) will change from a '~' to a '^'.
     */
-    it('Test#000 : tests that the spec (~,^) is added and updated as expected in config.xml', function (done) {
+    it('Test#000 : tests that the spec (~,^) is added and updated as expected in config.xml', function () {
         var cwd = process.cwd();
         var pkgJsonPath = path.join(cwd, 'package.json');
         cordova_util.requireNoCache(pkgJsonPath);
@@ -81,7 +81,7 @@ describe('tests platform/spec restore with --save', function () {
         var engNames;
         var engSpec;
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add platform with save, fetch
             return cordovaPlatform('add', androidPlatform, {'save': true, 'fetch': true});
         }).then(function () {
@@ -128,9 +128,7 @@ describe('tests platform/spec restore with --save', function () {
             expect(firstCharConfig === '^');
             expect(engNames).toEqual([ androidPlatform ]);
             expect(engines.length === 1);
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, 300000);
 
@@ -139,7 +137,7 @@ describe('tests platform/spec restore with --save', function () {
     *   pkg.json and config.xml would add it to their files properly.
     *   When prepare is run with fetch, platform should be installed.
     */
-    it('Test#017 : test to make sure that platform url is added and restored properly', function (done) {
+    it('Test#017 : test to make sure that platform url is added and restored properly', function () {
         var cwd = process.cwd();
         var pkgJsonPath = path.join(cwd, 'package.json');
         var pkgJson;
@@ -149,7 +147,7 @@ describe('tests platform/spec restore with --save', function () {
         var engNames;
         var engSpec;
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add platform with save and fetch
             return cordovaPlatform('add', 'https://github.com/apache/cordova-browser', {'save': true, 'fetch': true});
         }).then(function () {
@@ -195,9 +193,7 @@ describe('tests platform/spec restore with --save', function () {
             pkgJson = cordova_util.requireNoCache(pkgJsonPath);
             expect(pkgJson.cordova.platforms.indexOf('browser')).toBeDefined();
             expect(pkgJson.dependencies['cordova-browser']).toEqual('git+https://github.com/apache/cordova-browser.git');
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 
@@ -206,7 +202,7 @@ describe('tests platform/spec restore with --save', function () {
     *   pkg.json and config.xml would add it to their files properly.
     *   When prepare is run with fetch, plugin should be installed.
     */
-    it('Test#018 : test to make sure that plugin url is added and restored properly', function (done) {
+    it('Test#018 : test to make sure that plugin url is added and restored properly', function () {
         var cwd = process.cwd();
         var pkgJsonPath = path.join(cwd, 'package.json');
         var pkgJson;
@@ -214,7 +210,7 @@ describe('tests platform/spec restore with --save', function () {
         var configXmlPath = path.join(cwd, 'config.xml');
         var configPlugins;
         var configPlugin;
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add plugin with save and fetch.
             return cordovaPlugin('add', ['https://github.com/apache/cordova-plugin-splashscreen'], {'save': true, 'fetch': true});
         }).then(function () {
@@ -265,9 +261,7 @@ describe('tests platform/spec restore with --save', function () {
             expect(pkgJson.cordova.plugins['cordova-plugin-splashscreen']).toBeDefined();
             // Plugin was restored and added to installed plugin list successfully.
             expect(path.join(pluginsFolderPath, 'cordova-plugin-splashscreen')).toExist();
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -318,13 +312,13 @@ describe('tests platform/spec restore with --save', function () {
     *   After running cordova prepare, only the platform added with the 'save' flag is restored
     *   in platforms.json.
     */
-    it('Test#003 : should NOT restore platform that was not saved and removed', function (done) {
+    it('Test#003 : should NOT restore platform that was not saved and removed', function () {
         var cwd = process.cwd();
         var pkgJsonPath = path.join(cwd, 'package.json');
         var pkgJson;
         var secondPlatformAdded = 'ios';
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add 'browser' platform to project without --save
             return cordovaPlatform('add', secondPlatformAdded, {'fetch': true});
         }).then(function () {
@@ -352,9 +346,7 @@ describe('tests platform/spec restore with --save', function () {
             }).then(function () {
                 // Run cordova prepare
                 return prepare({'fetch': true});
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -396,7 +388,7 @@ describe('files should not be modified if their platforms are identical', functi
     *   When both files contain the same platforms and cordova prepare is run,
     *   neither file is modified.
     */
-    it('Test#004 : if pkg.json and config.xml have the same platforms, do not modify either file', function (done) {
+    it('Test#004 : if pkg.json and config.xml have the same platforms, do not modify either file', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var cfg1 = new ConfigParser(configXmlPath);
@@ -408,7 +400,7 @@ describe('files should not be modified if their platforms are identical', functi
         });
         var configEngArray = engNames.slice();
         // Pkg.json and config.xml contain only android at this point (basePkgJson6).
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run cordova prepare.
             return prepare({'fetch': true});
         }).then(function () {
@@ -425,9 +417,7 @@ describe('files should not be modified if their platforms are identical', functi
             // Expect pkg.json and config.xml to have only 1 element each.
             expect(configEngArray.length === 1);
             expect(pkgJson.cordova.platforms.length === 1);
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -470,7 +460,7 @@ describe('update pkg.json to include platforms in config.xml', function () {
     *   is updated with the correct spec/dependencies when restored. Checks that specs are
     *   added properly, too.
     */
-    it('Test#005 : if config.xml has android & browser platforms and pkg.json has android, update pkg.json to also include browser with spec', function (done) {
+    it('Test#005 : if config.xml has android & browser platforms and pkg.json has android, update pkg.json to also include browser with spec', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var cfg = new ConfigParser(configXmlPath);
@@ -494,7 +484,7 @@ describe('update pkg.json to include platforms in config.xml', function () {
         // pkg.json browser/android specs should be undefined.
         expect(pkgJson.dependencies[browserPlatform]).toBeUndefined();
         expect(pkgJson.dependencies[androidPlatform]).toBeUndefined();
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             return prepare({'fetch': true});
         }).then(function () {
             pkgJson = cordova_util.requireNoCache(pkgJsonPath);
@@ -511,9 +501,7 @@ describe('update pkg.json to include platforms in config.xml', function () {
             // Platform specs from config.xml have been added to pkg.json.
             expect(pkgJson.dependencies['cordova-browser']).toEqual('^5.0.3');
             expect(pkgJson.dependencies['cordova-android']).toEqual('7.0.0');
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -554,7 +542,7 @@ describe('update empty package.json to match config.xml', function () {
      *   If it does not and config.xml has a platform(s) installed already, run cordova prepare
      *   and it will add a cordova key and the platform(s) from config.xml to package.json.
      */
-    it('Test#006 : if pkg.json exists without cordova key, create one with same platforms in config.xml ', function (done) {
+    it('Test#006 : if pkg.json exists without cordova key, create one with same platforms in config.xml ', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var pkgJsonPath = path.join(cwd, 'package.json');
@@ -575,7 +563,7 @@ describe('update empty package.json to match config.xml', function () {
         expect(configEngArray.length === 1);
         // Run cordova prepare.
         prepare();
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             var cfg2 = new ConfigParser(configXmlPath);
             engines = cfg2.getEngines();
             engNames = engines.map(function (elem) {
@@ -591,9 +579,7 @@ describe('update empty package.json to match config.xml', function () {
             // Expect both pkg.json and config.xml to each have (only) android in their arrays.
             expect(configEngArray.length === 1);
             expect(pkgJson.cordova.platforms.length === 1);
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -635,7 +621,7 @@ describe('update config.xml to include platforms in pkg.json', function () {
     *   and config.xml is updated to include 'browser'. Also, if there is a specified spec in pkg.json,
     *   it should be added to config.xml during restore.
     */
-    it('Test#007 : if pkgJson has android & browser platforms and config.xml has android, update config to also include browser and spec', function (done) {
+    it('Test#007 : if pkgJson has android & browser platforms and config.xml has android, update config to also include browser and spec', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var cfg1 = new ConfigParser(configXmlPath);
@@ -654,7 +640,7 @@ describe('update config.xml to include platforms in pkg.json', function () {
         expect(configEngArray.length === 1);
         // Pkg.json has cordova-browser in its dependencies.
         expect(pkgJson.dependencies).toEqual({ 'cordova-ios': '^4.5.4', 'cordova-browser': '^5.0.3' });
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run cordova prepare.
             return prepare({ 'fetch': true });
         }).then(function () {
@@ -678,9 +664,7 @@ describe('update config.xml to include platforms in pkg.json', function () {
             expect(pkgJson.dependencies).toEqual({ 'cordova-ios': '^4.5.4', 'cordova-browser': '^5.0.3' });
             expect(pkgJson.dependencies['cordova-ios']).toEqual('^4.5.4');
             expect(pkgJson.dependencies['cordova-browser']).toEqual('^5.0.3');
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -723,7 +707,7 @@ describe('update config.xml to use the variable found in pkg.json', function ()
     *   When pkg.json and config.xml have the same variables, but different values,
     *   pkg.json should win and that value will be used and replaces config's value.
     */
-    it('Test#011 : if pkg.Json has 1 plugin and 1 variable, update config.xml to include these variables', function (done) {
+    it('Test#011 : if pkg.Json has 1 plugin and 1 variable, update config.xml to include these variables', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var pkgJsonPath = path.join(cwd, 'package.json');
@@ -745,7 +729,7 @@ describe('update config.xml to use the variable found in pkg.json', function ()
         expect(configPluginVariables).toEqual({ variable_1: 'config' });
         expect(Object.keys(configPlugin).length === 1);
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run cordova prepare.
             return prepare({'fetch': true, 'save': true});
         }).then(function () {
@@ -765,9 +749,7 @@ describe('update config.xml to use the variable found in pkg.json', function ()
             expect(Object.keys(configPlugin).length === 1);
             // Expect that the camera plugin is restored.
             expect(path.join(pluginsFolderPath, 'cordova-plugin-camera')).toExist();
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -808,7 +790,7 @@ describe('update pkg.json to include plugin and variable found in config.xml', f
     *   When config.xml has a 'camera plugin and 1 variable' and pkg.json has 1 plugins/0 variables,
     *   cordova prepare runs and will update pkg.json to match config.xml's plugins/variables.
     */
-    it('Test#012 : if pkg.Json has 1 plugin and 2 variables, update config.xml to include these plugins/variables', function (done) {
+    it('Test#012 : if pkg.Json has 1 plugin and 2 variables, update config.xml to include these plugins/variables', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var pkgJsonPath = path.join(cwd, 'package.json');
@@ -832,7 +814,7 @@ describe('update pkg.json to include plugin and variable found in config.xml', f
         expect(configPluginVariables).toEqual({ variable_1: 'value_1' });
         expect(Object.keys(configPlugin).length === 1);
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run cordova prepare.
             return prepare({'fetch': true, 'save': true});
         }).then(function () {
@@ -852,9 +834,7 @@ describe('update pkg.json to include plugin and variable found in config.xml', f
             expect(Object.keys(configPlugin).length === 1);
             // Expect camera to be restored and in the installed plugin list.
             expect(path.join(pluginsFolderPath12, 'cordova-plugin-camera')).toExist();
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -897,7 +877,7 @@ describe('update pkg.json AND config.xml to include all plugins and merge unique
     *   Plugins that are unique to that file, will be copied over to the file that is missing it.
     *   Config.xml and pkg.json will have identical plugins and variables after cordova prepare.
     */
-    it('Test#013 : update pkg.json AND config.xml to include all plugins and merge unique variables', function (done) {
+    it('Test#013 : update pkg.json AND config.xml to include all plugins and merge unique variables', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var pkgJsonPath = path.join(cwd, 'package.json');
@@ -936,7 +916,7 @@ describe('update pkg.json AND config.xml to include all plugins and merge unique
         expect(pkgJson.cordova.plugins['cordova-plugin-camera']).toEqual({ variable_1: ' ', variable_2: ' ' });
         expect(pkgJson.cordova.plugins['cordova-plugin-device']).toEqual({ variable_1: 'value_1' });
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run cordova prepare.
             return prepare({'fetch': true, 'save': true});
         }).then(function () {
@@ -977,9 +957,7 @@ describe('update pkg.json AND config.xml to include all plugins and merge unique
             expect(path.join(pluginsFolderPath13, 'cordova-plugin-device')).toExist();
             expect(path.join(pluginsFolderPath13, 'cordova-plugin-camera')).toExist();
             expect(path.join(pluginsFolderPath13, 'cordova-plugin-splashscreen')).toExist();
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -1022,7 +1000,7 @@ describe('update pkg.json AND config.xml to include all plugins/merge variables
     *   If there is a matching plugin name, the variables will be merged and then added
     *   to config and pkg.json.
     */
-    it('Test#014 : update pkg.json AND config.xml to include all plugins and merge variables (no dupes)', function (done) {
+    it('Test#014 : update pkg.json AND config.xml to include all plugins and merge variables (no dupes)', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var pkgJsonPath = path.join(cwd, 'package.json');
@@ -1068,7 +1046,7 @@ describe('update pkg.json AND config.xml to include all plugins/merge variables
         // Pkg.json splashscreen has no variables
         expect(pkgJson.cordova.plugins['cordova-plugin-splashscreen']).toEqual({});
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run cordova prepare
             return prepare({'save': true, 'fetch': true});
         }).then(function () {
@@ -1123,9 +1101,7 @@ describe('update pkg.json AND config.xml to include all plugins/merge variables
             expect(path.join(pluginsFolderPath14, 'cordova-plugin-camera')).toExist();
             expect(path.join(pluginsFolderPath14, 'cordova-plugin-splashscreen')).toExist();
             expect(path.join(pluginsFolderPath14, 'cordova-plugin-device')).toExist();
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -1166,7 +1142,7 @@ describe('update config.xml to include the plugin that is in pkg.json', function
     *   When config has 0 plugins and is restored, the plugins will be restored with the
     *   pkg.json plugins and with the spec from pkg.json dependencies.
     */
-    it('Test#015 : update config.xml to include all plugins/variables from pkg.json', function (done) {
+    it('Test#015 : update config.xml to include all plugins/variables from pkg.json', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var pkgJsonPath = path.join(cwd, 'package.json');
@@ -1190,7 +1166,7 @@ describe('update config.xml to include the plugin that is in pkg.json', function
         // Pkg.json has '^2.3.0' spec for camera plugin.
         expect(pkgJson.dependencies).toEqual({ 'cordova-plugin-camera': '^2.3.0' });
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run cordova prepare.
             return prepare({'fetch': true, 'save': true});
         }).then(function () {
@@ -1224,9 +1200,7 @@ describe('update config.xml to include the plugin that is in pkg.json', function
             expect(pkgJson.cordova.plugins['cordova-plugin-camera']).toEqual({ variable_1: 'value_1' });
             // Check if the camera plugin is in the installed list.
             expect(path.join(pluginsFolderPath15, 'cordova-plugin-camera')).toExist();
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -1266,7 +1240,7 @@ describe('platforms and plugins should be restored with config.xml even without
     /** Test#016 will check that cordova prepare will still restore the correct
     *   platforms and plugins even without package.json file.
     */
-    it('Test#016 : platforms and plugins should be restored with config.xml even without a pkg.json', function (done) {
+    it('Test#016 : platforms and plugins should be restored with config.xml even without a pkg.json', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var cfg1 = new ConfigParser(configXmlPath);
@@ -1287,7 +1261,7 @@ describe('platforms and plugins should be restored with config.xml even without
         // Config.xml contains only 1 plugin at this point.
         expect(Object.keys(configPlugins).length === 1);
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Run platform add.
             return cordovaPlatform('add', browserPlatform, {'save': true, 'fetch': true});
         }).then(function () {
@@ -1359,9 +1333,7 @@ describe('platforms and plugins should be restored with config.xml even without
         }).then(function () {
             // Plugin should be restored and returned to the installed list.
             expect(path.join(pluginsFolderPath16, 'cordova-plugin-device')).toExist();
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -1413,13 +1385,13 @@ describe('tests platform/spec restore with --save', function () {
     *   After running cordova prepare, that platform should be restored in the
     *   installed platform list in platforms.json.
     */
-    it('Test#001 : should restore platform that has been removed from project', function (done) {
+    it('Test#001 : should restore platform that has been removed from project', function () {
         var cwd = process.cwd();
         var pkgJsonPath = path.join(cwd, 'package.json');
         cordova_util.requireNoCache(pkgJsonPath);
         var pkgJson;
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add the testing platform with --save.
             return cordovaPlatform('add', 'android', {'save': true, 'fetch': true});
         }).then(function () {
@@ -1439,9 +1411,7 @@ describe('tests platform/spec restore with --save', function () {
             }).then(function () {
                 // Run cordova prepare.
                 return prepare({'fetch': true});
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 
@@ -1450,13 +1420,13 @@ describe('tests platform/spec restore with --save', function () {
     *   the other platform with the 'save' flag. After running cordova prepare,
     *   the platform removed with the 'save' flag should NOT be restored in platforms.json.
     */
-    it('Test#002 : should NOT restore platform that was removed with --save', function (done) {
+    it('Test#002 : should NOT restore platform that was removed with --save', function () {
         var cwd = process.cwd();
         var pkgJsonPath = path.join(cwd, 'package.json');
         var pkgJson;
         var secondPlatformAdded = 'browser';
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add the testing platform with --save.
             return cordovaPlatform('add', [helpers.testPlatform], {'save': true, 'fetch': true});
         }).then(function () {
@@ -1485,9 +1455,7 @@ describe('tests platform/spec restore with --save', function () {
             }).then(function () {
                 // Run cordova prepare.
                 return prepare({'fetch': true});
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
diff --git a/integration-tests/pkgJson.spec.js b/integration-tests/pkgJson.spec.js
index ca1fd89..2839fe6 100644
--- a/integration-tests/pkgJson.spec.js
+++ b/integration-tests/pkgJson.spec.js
@@ -63,7 +63,7 @@ describe('plugin end-to-end', function () {
         shell.rm('-rf', project);
     });
 
-    it('Test#001 : should successfully add and remove a plugin with save and correct spec', function (done) {
+    it('Test#001 : should successfully add and remove a plugin with save and correct spec', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         var pkgJson = require(pkgJsonPath);
         var cwd = process.cwd();
@@ -103,12 +103,10 @@ describe('plugin end-to-end', function () {
                 expect(pkgJson.cordova.plugins[pluginId]).toBeUndefined();
                 // Spec should be removed from dependencies.
                 expect(pkgJson.dependencies['cordova-plugin-device']).toBeUndefined();
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test#002 : should NOT add a plugin to package.json if --save is not used', function (done) {
+    it('Test#002 : should NOT add a plugin to package.json if --save is not used', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         var pkgJson;
         expect(pkgJsonPath).toExist();
@@ -126,12 +124,10 @@ describe('plugin end-to-end', function () {
                 expect(pkgJson.cordova.plugins['cordova-plugin-geolocation']).toBeDefined();
                 // Expect that the second plugin is not added.
                 expect(pkgJson.cordova.plugins[pluginId]).toBeUndefined();
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test#003 : should NOT remove plugin from package.json if there is no --save', function (done) {
+    it('Test#003 : should NOT remove plugin from package.json if there is no --save', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         var pkgJson;
 
@@ -154,12 +150,10 @@ describe('plugin end-to-end', function () {
                 pkgJson = cordova_util.requireNoCache(pkgJsonPath);
                 // The plugin should still be in package.json.
                 expect(pkgJson.cordova.plugins[pluginId]).toBeDefined();
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test#004 : should successfully add and remove a plugin with variables and save to package.json', function (done) {
+    it('Test#004 : should successfully add and remove a plugin with variables and save to package.json', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         var pkgJson;
         var someKey = 'someKey';
@@ -184,13 +178,11 @@ describe('plugin end-to-end', function () {
                 pkgJson = cordova_util.requireNoCache(pkgJsonPath);
                 // Checking that the plugin and variables were removed successfully.
                 expect(pkgJson.cordova.plugins[pluginId]).toBeUndefined();
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 
     // CB-12170 : Test is commented out because not promisified correctly in cordova-create script
-    xit('Test#005 : should successfully add and remove multiple plugins with save & fetch', function (done) {
+    xit('Test#005 : should successfully add and remove multiple plugins with save & fetch', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         // Delete any previous caches of require(package.json).
         var pkgJson = cordova_util.requireNoCache(pkgJsonPath);
@@ -220,13 +212,11 @@ describe('plugin end-to-end', function () {
                 expect(pkgJson.cordova.plugins['cordova-plugin-device-motion']).toBeUndefined();
                 expect(pkgJson.dependencies[pluginId]).toBeUndefined();
                 expect(pkgJson.dependencies['cordova-plugin-device-motion']).toBeUndefined();
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
     // Test #023 : if pkg.json and config.xml have no platforms/plugins/spec.
     // and --save --fetch is called, use the pinned version or plugin pkg.json version.
-    it('Test#023 : use pinned/lastest version if there is no platform/plugin version passed in and no platform/plugin versions in pkg.json or config.xml', function (done) {
+    it('Test#023 : use pinned/lastest version if there is no platform/plugin version passed in and no platform/plugin versions in pkg.json or config.xml', function () {
         var iosPlatform = 'ios';
         var iosVersion;
         var cwd = process.cwd();
@@ -290,14 +280,12 @@ describe('plugin end-to-end', function () {
                 pkgJson = cordova_util.requireNoCache(pkgJsonPath);
                 // Check that pkg.json and plugin pkg.json versions "satisfy".
                 expect(semver.satisfies(pluginPkgJsonVersion.version, pkgJson.dependencies['cordova-ios']));
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 
     // Test#025: has a pkg.json. Checks if local path is added to pkg.json for platform and plugin add.
-    it('Test#025 : if you add a platform/plugin with local path, pkg.json gets updated', function (done) {
+    it('Test#025 : if you add a platform/plugin with local path, pkg.json gets updated', function () {
 
         var cwd = process.cwd();
         var platformPath = path.join(testRunRoot, 'spec', 'cordova/fixtures/platforms/cordova-browser');
@@ -358,9 +346,7 @@ describe('plugin end-to-end', function () {
                         expect(result).toEqual(true);
                     }
                 });
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 });
 
@@ -405,13 +391,13 @@ describe('platform end-to-end with --save', function () {
         });
     }
 
-    it('Test#006 : platform is added and removed correctly with --save', function (done) {
+    it('Test#006 : platform is added and removed correctly with --save', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         expect(pkgJsonPath).toExist();
         var pkgJson;
 
         // Check there are no platforms yet.
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add the testing platform with --save.
             return cordova.platform('add', [helpers.testPlatform], {'save': true, 'fetch': true});
         }).then(function () {
@@ -428,17 +414,15 @@ describe('platform end-to-end with --save', function () {
                 pkgJson = cordova_util.requireNoCache(pkgJsonPath);
                 // Checking that the platform removed is in not in the platforms key.
                 expect(pkgJson.cordova.platforms.indexOf(helpers.testPlatform)).toEqual(-1);
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test#007 : should not remove platforms from package.json when removing without --save', function (done) {
+    it('Test#007 : should not remove platforms from package.json when removing without --save', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         expect(pkgJsonPath).toExist();
         var pkgJson = cordova_util.requireNoCache(pkgJsonPath);
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add the testing platform with --save.
             return cordova.platform('add', [helpers.testPlatform], {'save': true, 'fetch': true});
         }).then(function () {
@@ -455,13 +439,10 @@ describe('platform end-to-end with --save', function () {
                 pkgJson = cordova_util.requireNoCache(pkgJsonPath);
                 // Check that the platform removed without --save is still in platforms key.
                 expect(pkgJson.cordova.platforms.indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
-            }).then(emptyPlatformList)
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            }).then(emptyPlatformList);
     }, TIMEOUT);
 
-    it('Test#008 : should not add platform to package.json when adding without --save', function (done) {
+    it('Test#008 : should not add platform to package.json when adding without --save', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         expect(pkgJsonPath).toExist();
         // Delete any previous caches of require(package.json).
@@ -469,27 +450,23 @@ describe('platform end-to-end with --save', function () {
         // Pkg.json "platforms" should be empty and helpers.testPlatform should not exist in pkg.json.
         expect(pkgJson.cordova).toBeUndefined();
         // Add platform without --save.
-        cordova.platform('add', [helpers.testPlatform], {'fetch': true})
+        return cordova.platform('add', [helpers.testPlatform], {'fetch': true})
             .then(function () {
                 // Check the platform add was successful, reload, skipping cache.
                 pkgJson = cordova_util.requireNoCache(pkgJsonPath);
                 // PkgJson.cordova should not be defined and helpers.testPlatform should NOT have been added.
                 expect(pkgJson.cordova).toBeUndefined();
-            }).then(fullPlatformList)
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            }).then(fullPlatformList);
     }, TIMEOUT);
 
-    it('Test#009 : should only add the platform to package.json with --save', function (done) {
+    it('Test#009 : should only add the platform to package.json with --save', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         var pkgJson;
         var platformNotToAdd = 'browser';
         expect(pkgJsonPath).toExist();
 
         // Add a platform without --save.
-        cordova.platform('add', platformNotToAdd, {'fetch': true})
+        return cordova.platform('add', platformNotToAdd, {'fetch': true})
             .then(function () {
                 // And now add another platform with --save.
                 return cordova.platform('add', [helpers.testPlatform], {'save': true, 'fetch': true});
@@ -501,14 +478,10 @@ describe('platform end-to-end with --save', function () {
                 // Check that only the platform added with --save was added to package.json.
                 expect(pkgJsonCordova.platforms.indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
                 expect(pkgJsonCordova.platforms.indexOf(platformNotToAdd)).toEqual(-1);
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, TIMEOUT);
 
-    it('Test#010 : two platforms are added and removed correctly with --save --fetch', function (done) {
+    it('Test#010 : two platforms are added and removed correctly with --save --fetch', function () {
         var pkgJsonPath = path.join(process.cwd(), 'package.json');
         expect(pkgJsonPath).toExist();
         var pkgJson;
@@ -527,7 +500,7 @@ describe('platform end-to-end with --save', function () {
         expect(pkgJson.cordova).toBeUndefined();
         expect(configEngArray.length === 0);
         // Check there are no platforms yet.
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add the testing platform with --save and add specific version to android platform.
             return cordova.platform('add', ['android@7.0.0', 'browser@5.0.1'], {'save': true, 'fetch': true});
         }).then(function () {
@@ -575,10 +548,7 @@ describe('platform end-to-end with --save', function () {
                 configEngArray = engNames.slice();
                 // Platforms are removed from config.xml.
                 expect(configEngArray.length === 0);
-            }).then(emptyPlatformList) // platform ls should be empty too.
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            }).then(emptyPlatformList); // platform ls should be empty too.;
     }, TIMEOUT);
 });
 
@@ -619,7 +589,7 @@ describe('During add, if pkg.json has a platform/plugin spec, use that one.', fu
     /** Test#020 will check that pkg.json, config.xml, platforms.json, and cordova platform ls
     *   are updated with the correct (platform and plugin) specs from pkg.json.
     */
-    it('Test#020 : During add, if pkg.json has a spec, use that one.', function (done) {
+    it('Test#020 : During add, if pkg.json has a spec, use that one.', function () {
         var iosPlatform = 'ios';
         var iosVersion;
         var cwd = process.cwd();
@@ -642,7 +612,7 @@ describe('During add, if pkg.json has a platform/plugin spec, use that one.', fu
         expect(engines.length).toEqual(0);
         expect(configPlugins.length).toEqual(0);
 
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add ios with --save and --fetch.
             return cordova.platform('add', [iosPlatform], {'save': true, 'fetch': true});
         }).then(function () {
@@ -678,9 +648,7 @@ describe('During add, if pkg.json has a platform/plugin spec, use that one.', fu
             // Check that pkg.json version and plugin pkg.json version "satisfy" each other.
             pkgJson = cordova_util.requireNoCache(pkgJsonPath);
             expect(semver.satisfies(pluginPkgJsonVersion.version, pkgJson.dependencies['cordova-plugin-splashscreen'])).toEqual(true);
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT * 2);
 });
@@ -721,7 +689,7 @@ describe('During add, if config.xml has a platform/plugin spec and pkg.json does
     /** Test#021 during add, this test will check that pkg.json, config.xml, platforms.json,
     *   and cordova platform ls are updated with the correct platform/plugin spec from config.xml.
     */
-    it('Test#021 : If config.xml has a spec (and none was specified and pkg.json does not have one), use config.', function (done) {
+    it('Test#021 : If config.xml has a spec (and none was specified and pkg.json does not have one), use config.', function () {
         var iosPlatform = 'ios';
         var iosVersion;
         var cwd = process.cwd();
@@ -741,7 +709,7 @@ describe('During add, if config.xml has a platform/plugin spec and pkg.json does
         // Pkg.json does not have platform or spec yet. Config.xml has ios and spec '~4.2.1'.
         // Remove for testing purposes so platform is not pre-installed.
         cordova.platform('rm', [iosPlatform], {'save': true});
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add ios with --save and --fetch.
             return cordova.platform('add', [iosPlatform], {'save': true, 'fetch': true});
         }).then(function () {
@@ -778,9 +746,7 @@ describe('During add, if config.xml has a platform/plugin spec and pkg.json does
             pluginPkgJsonVersion = cordova_util.requireNoCache(pluginPkgJsonDir);
             // Check that version in plugin pkg.json and config version "satisfy" each other.
             expect(semver.satisfies(pluginPkgJsonVersion.version, configPlugin.spec)).toEqual(true);
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -821,7 +787,7 @@ describe('During add, if add specifies a platform spec, use that one regardless
     /** Test#022 : when adding with a specific platform version, always use that one
     *   regardless of what is in package.json or config.xml.
     */
-    it('Test#022 : when adding with a specific platform version, always use that one.', function (done) {
+    it('Test#022 : when adding with a specific platform version, always use that one.', function () {
         var iosPlatform = 'ios';
         var iosVersion;
         var cwd = process.cwd();
@@ -843,7 +809,7 @@ describe('During add, if add specifies a platform spec, use that one regardless
         // Config.xml has ios and spec ~4.2.1.
         expect(engines.length).toEqual(1);
         expect(engines).toEqual([ { name: 'ios', spec: '~4.2.1' } ]);
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add ios with --save and --fetch.
             return cordova.platform('add', ['ios@4.5.4'], {'save': true, 'fetch': true});
         }).then(function () {
@@ -882,9 +848,7 @@ describe('During add, if add specifies a platform spec, use that one regardless
             pkgJson = cordova_util.requireNoCache(pkgJsonPath);
             // Check that pkg.json and plugin pkg.json versions "satisfy".
             expect(semver.satisfies(pluginPkgJsonVersion.version, pkgJson.dependencies['cordova-ios']));
-        }).fail(function (err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
+        });
     // Cordova prepare needs extra wait time to complete.
     }, TIMEOUT);
 });
@@ -914,7 +878,7 @@ describe('local path is added to config.xml without pkg.json', function () {
     });
 
     // Test#026: has NO pkg.json. Checks if local path is added to config.xml and has no errors.
-    it('Test#026 : if you add a platform with local path, config.xml gets updated', function (done) {
+    it('Test#026 : if you add a platform with local path, config.xml gets updated', function () {
         var cwd = process.cwd();
         var configXmlPath = path.join(cwd, 'config.xml');
         var cfg = new ConfigParser(configXmlPath);
@@ -938,13 +902,11 @@ describe('local path is added to config.xml without pkg.json', function () {
                         expect(result).toEqual(true);
                     }
                 });
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 
     // Test#027: has NO pkg.json. Checks if local path is added to config.xml and has no errors.
-    it('Test#027 : if you add a plugin with local path, config.xml gets updated', function (done) {
+    it('Test#027 : if you add a plugin with local path, config.xml gets updated', function () {
         var cwd = process.cwd();
         var pluginPath = path.join(testRunRoot, 'spec', 'cordova/fixtures/plugins/cordova-lib-test-plugin');
         var configXmlPath = path.join(cwd, 'config.xml');
@@ -963,8 +925,6 @@ describe('local path is added to config.xml without pkg.json', function () {
                 // Spec for geolocation plugin is added.
                 var result = includeFunc(configPlugin.spec, pluginPath);
                 expect(result).toEqual(true);
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
     }, TIMEOUT);
 });
diff --git a/integration-tests/platform.spec.js b/integration-tests/platform.spec.js
index 1ac691f..ac35e78 100644
--- a/integration-tests/platform.spec.js
+++ b/integration-tests/platform.spec.js
@@ -99,10 +99,10 @@ describe('platform end-to-end', function () {
     //
     // This test was designed to use a older version of android before API.js
     // It is not valid anymore.
-    xit('Test 001 : should successfully run', function (done) {
+    xit('Test 001 : should successfully run', function () {
 
         // Check there are no platforms yet.
-        emptyPlatformList().then(function () {
+        return emptyPlatformList().then(function () {
             // Add the testing platform.
             return cordova.platform('add', [helpers.testPlatform]);
         }).then(function () {
@@ -123,14 +123,11 @@ describe('platform end-to-end', function () {
             }).then(function () {
                 // It should be gone.
                 expect(path.join(project, 'platforms', helpers.testPlatform)).not.toExist();
-            }).then(emptyPlatformList) // platform ls should be empty too.
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            }).then(emptyPlatformList); // platform ls should be empty too.;
     });
 
-    xit('Test 002 : should install plugins correctly while adding platform', function (done) {
-        cordova.plugin('add', path.join(pluginsDir, 'test'), {'fetch': true})
+    xit('Test 002 : should install plugins correctly while adding platform', function () {
+        return cordova.plugin('add', path.join(pluginsDir, 'test'), {'fetch': true})
             .then(function () {
                 return cordova.platform('add', [helpers.testPlatform], {'fetch': true});
             })
@@ -139,29 +136,22 @@ describe('platform end-to-end', function () {
                 expect(path.join(project, 'platforms', helpers.testPlatform)).toExist();
                 // Check that plugin files exists in www dir
                 expect(path.join(project, 'platforms', helpers.testPlatform, 'assets/www/test.js')).toExist();
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 60000);
 
-    xit('Test 003 : should call prepare after plugins were installed into platform', function (done) {
+    xit('Test 003 : should call prepare after plugins were installed into platform', function () {
         var order = '';
         var fail = jasmine.createSpy(fail); // eslint-disable-line no-use-before-define
         spyOn(plugman, 'install').and.callFake(function () { order += 'I'; });
         // below line won't work since prepare is inline require in addHelper, not global
         var x = addHelper.__set__('prepare', function () { order += 'P'; }); // eslint-disable-line no-unused-vars
         // spyOn(prepare).and.callFake(function() { console.log('prepare'); order += 'P'; });
-        cordova.plugin('add', path.join(pluginsDir, 'test'))
+        return cordova.plugin('add', path.join(pluginsDir, 'test'))
             .then(function () {
                 return platform('add', [helpers.testPlatform]);
             })
-            .fail(fail)
-            .fin(function () {
+            .then(function () {
                 expect(order).toBe('IP'); // Install first, then prepare
-                expect(fail).not.toHaveBeenCalled();
-                done();
             });
     });
 });
@@ -181,9 +171,9 @@ describe('platform add plugin rm end-to-end', function () {
         shell.rm('-rf', tmpDir);
     });
 
-    it('Test 006 : should remove dependency when removing parent plugin', function (done) {
+    it('Test 006 : should remove dependency when removing parent plugin', function () {
 
-        cordova.create('hello')
+        return cordova.create('hello')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'browser@latest', {'fetch': true});
@@ -204,12 +194,7 @@ describe('platform add plugin rm end-to-end', function () {
             .then(function () {
                 expect(path.join(pluginsDir, 'cordova-plugin-media')).not.toExist();
                 expect(path.join(pluginsDir, 'cordova-plugin-file')).not.toExist();
-            })
-            .fail(function (err) {
-                console.error(err);
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 100000);
 });
 
@@ -229,9 +214,9 @@ describe('platform add and remove --fetch', function () {
         shell.rm('-rf', tmpDir);
     });
 
-    it('Test 007 : should add and remove platform from node_modules directory', function (done) {
+    it('Test 007 : should add and remove platform from node_modules directory', function () {
 
-        cordova.create('helloFetch')
+        return cordova.create('helloFetch')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'browser', {'fetch': true, 'save': true});
@@ -256,12 +241,7 @@ describe('platform add and remove --fetch', function () {
             .then(function () {
                 // expect(path.join(nodeModulesDir, 'cordova-android')).not.toExist();
                 // expect(path.join(platformsDir, 'android')).not.toExist();
-            })
-            .fail(function (err) {
-                console.error(err);
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 100000);
 });
 
@@ -280,9 +260,9 @@ describe('plugin add and rm end-to-end --fetch', function () {
         shell.rm('-rf', tmpDir);
     });
 
-    it('Test 008 : should remove dependency when removing parent plugin', function (done) {
+    it('Test 008 : should remove dependency when removing parent plugin', function () {
 
-        cordova.create('hello3')
+        return cordova.create('hello3')
             .then(function () {
                 process.chdir(project);
                 return cordova.platform('add', 'browser', {'fetch': true});
@@ -309,11 +289,7 @@ describe('plugin add and rm end-to-end --fetch', function () {
                 // expect(path.join(project, 'node_modules', 'cordova-plugin-media')).not.toExist();
                 // expect(path.join(project, 'node_modules', 'cordova-plugin-file')).not.toExist();
                 // expect(path.join(project, 'node_modules', 'cordova-plugin-compat')).not.toExist();
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 60000);
 });
 
@@ -333,9 +309,9 @@ describe('non-core platform add and rm end-to-end --fetch', function () {
         shell.rm('-rf', tmpDir);
     });
 
-    it('Test 009 : should add and remove 3rd party platforms', function (done) {
+    it('Test 009 : should add and remove 3rd party platforms', function () {
         var installed;
-        cordova.create('hello')
+        return cordova.create('hello')
             .then(function () {
                 process.chdir(project);
                 // add cordova-android instead of android
@@ -354,9 +330,6 @@ describe('non-core platform add and rm end-to-end --fetch', function () {
                 expect(installed).toBeDefined();
                 expect(installed[1].indexOf('android')).toBeGreaterThan(-1);
                 expect(installed[2].indexOf('cordova-platform-test')).toBeGreaterThan(-1);
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 90000);
 });
diff --git a/integration-tests/plugin.spec.js b/integration-tests/plugin.spec.js
index 0bf602d..8332617 100644
--- a/integration-tests/plugin.spec.js
+++ b/integration-tests/plugin.spec.js
@@ -131,21 +131,18 @@ describe('plugin end-to-end', function () {
         expect(errorHandler.errorCallback).not.toHaveBeenCalled();
     });
 
-    it('Test 001 : should successfully add and remove a plugin with no options', function (done) {
-        addPlugin(path.join(pluginsDir, 'fake1'), pluginId, {'fetch': true}, done)
+    it('Test 001 : should successfully add and remove a plugin with no options', function () {
+        return addPlugin(path.join(pluginsDir, 'fake1'), pluginId, {'fetch': true})
             .then(function () {
                 expect(install.runInstall).toHaveBeenCalled();
                 expect(platforms.getPlatformApi.calls.count()).toEqual(1);
                 return removePlugin(pluginId);
             }).then(function () {
                 expect(platforms.getPlatformApi.calls.count()).toEqual(2);
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 004 : should successfully add a plugin using relative path when running from subdir inside of project', function (done) {
+    it('Test 004 : should successfully add a plugin using relative path when running from subdir inside of project', function () {
         // Copy plugin to subdir inside of the project. This is required since path.relative
         // returns an absolute path when source and dest are on different drives
         var plugindir = path.join(project, 'custom-plugins/some-plugin-inside-subfolder');
@@ -158,20 +155,16 @@ describe('plugin end-to-end', function () {
         shell.cd(subdir);
 
         // Add plugin using relative path
-        addPlugin(path.relative(subdir, plugindir), pluginId, {'fetch': true}, done)
+        return addPlugin(path.relative(subdir, plugindir), pluginId, {'fetch': true})
             .then(function () {
                 return removePlugin(pluginId);
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 005 : should respect preference default values', function (done) {
+    it('Test 005 : should respect preference default values', function () {
         var plugin_util = require('../src/cordova/plugin/util');
         spyOn(plugin_util, 'mergeVariables').and.returnValue({ REQUIRED: 'NO', REQUIRED_ANDROID: 'NO' });
-        addPlugin(path.join(pluginsDir, org_test_defaultvariables), org_test_defaultvariables, { cli_variables: { REQUIRED: 'NO', REQUIRED_ANDROID: 'NO' }, 'fetch': true }, done)
+        return addPlugin(path.join(pluginsDir, org_test_defaultvariables), org_test_defaultvariables, { cli_variables: { REQUIRED: 'NO', REQUIRED_ANDROID: 'NO' }, 'fetch': true })
             .then(function () {
                 var platformJsonPath = path.join(project, 'plugins', helpers.testPlatform + '.json');
                 var installed_plugins = require(platformJsonPath).installed_plugins;
@@ -182,88 +175,64 @@ describe('plugin end-to-end', function () {
                 expect(defaultPluginPreferences.REQUIRED_ANDROID).toBe('NO');
                 expect(defaultPluginPreferences.REQUIRED).toBe('NO');
                 return removePlugin(org_test_defaultvariables);
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 006 : should successfully add a plugin when specifying CLI variables', function (done) {
-        addPlugin(path.join(pluginsDir, org_test_defaultvariables), org_test_defaultvariables, {cli_variables: { REQUIRED: 'yes', REQUIRED_ANDROID: 'yes' }, 'fetch': true}, done)
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+    it('Test 006 : should successfully add a plugin when specifying CLI variables', function () {
+        return addPlugin(path.join(pluginsDir, org_test_defaultvariables), org_test_defaultvariables, {cli_variables: { REQUIRED: 'yes', REQUIRED_ANDROID: 'yes' }, 'fetch': true});
     }, 30000);
 
-    it('Test 007 : should not check npm info when using the searchpath flag', function (done) {
+    it('Test 007 : should not check npm info when using the searchpath flag', function () {
         mockPluginFetch(npmInfoTestPlugin, path.join(pluginsDir, npmInfoTestPlugin));
         spyOn(plugin_util, 'info');
-        return addPlugin(npmInfoTestPlugin, npmInfoTestPlugin, {searchpath: pluginsDir}, done)
+        return addPlugin(npmInfoTestPlugin, npmInfoTestPlugin, {searchpath: pluginsDir})
             .then(function () {
                 expect(plugin_util.info).not.toHaveBeenCalled();
                 var fetchOptions = plugman.fetch.calls.mostRecent().args[2];
                 expect(fetchOptions.searchpath[0]).toExist();
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 008 : should not check npm info when using the noregistry flag', function (done) {
+    it('Test 008 : should not check npm info when using the noregistry flag', function () {
         mockPluginFetch(npmInfoTestPlugin, path.join(pluginsDir, npmInfoTestPlugin));
 
         spyOn(plugin_util, 'info');
-        addPlugin(npmInfoTestPlugin, npmInfoTestPlugin, {noregistry: true}, done)
+        return addPlugin(npmInfoTestPlugin, npmInfoTestPlugin, {noregistry: true})
             .then(function () {
                 expect(plugin_util.info).not.toHaveBeenCalled();
 
                 var fetchOptions = plugman.fetch.calls.mostRecent().args[2];
                 expect(fetchOptions.noregistry).toBeTruthy();
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 009 : should not check npm info when fetching from a Git repository', function (done) {
+    it('Test 009 : should not check npm info when fetching from a Git repository', function () {
         spyOn(plugin_util, 'info');
-        addPlugin(testGitPluginRepository, testGitPluginId, {'fetch': true}, done)
+        return addPlugin(testGitPluginRepository, testGitPluginId, {'fetch': true})
             .then(function () {
                 expect(plugin_util.info).not.toHaveBeenCalled();
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 010 : should select the plugin version based on npm info when fetching from npm', function (done) {
+    it('Test 010 : should select the plugin version based on npm info when fetching from npm', function () {
         mockPluginFetch(npmInfoTestPlugin, path.join(pluginsDir, npmInfoTestPlugin));
 
         spyOn(plugin_util, 'info').and.callThrough();
-        addPlugin(npmInfoTestPlugin, npmInfoTestPlugin, {'fetch': true}, done)
+        return addPlugin(npmInfoTestPlugin, npmInfoTestPlugin, {'fetch': true})
             .then(function () {
                 expect(plugin_util.info).toHaveBeenCalled();
 
                 var fetchTarget = plugman.fetch.calls.mostRecent().args[0];
                 expect(fetchTarget).toEqual(npmInfoTestPlugin + '@' + npmInfoTestPluginVersion);
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 011 : should handle scoped npm packages', function (done) {
+    it('Test 011 : should handle scoped npm packages', function () {
         var scopedPackage = '@testscope/' + npmInfoTestPlugin;
         mockPluginFetch(npmInfoTestPlugin, path.join(pluginsDir, npmInfoTestPlugin));
 
         spyOn(plugin_util, 'info').and.returnValue(Q({}));
-        addPlugin(scopedPackage, npmInfoTestPlugin, {}, done)
+        return addPlugin(scopedPackage, npmInfoTestPlugin, {})
             .then(function () {
                 // Check to make sure that we are at least trying to get the correct package.
                 // This package is not published to npm, so we can't truly do end-to-end tests
@@ -272,28 +241,20 @@ describe('plugin end-to-end', function () {
 
                 var fetchTarget = plugman.fetch.calls.mostRecent().args[0];
                 expect(fetchTarget).toEqual(scopedPackage);
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 
-    it('Test 012 : should handle scoped npm packages with given version tags', function (done) {
+    it('Test 012 : should handle scoped npm packages with given version tags', function () {
         var scopedPackage = '@testscope/' + npmInfoTestPlugin + '@latest';
         mockPluginFetch(npmInfoTestPlugin, path.join(pluginsDir, npmInfoTestPlugin));
 
         spyOn(plugin_util, 'info');
-        addPlugin(scopedPackage, npmInfoTestPlugin, {}, done)
+        return addPlugin(scopedPackage, npmInfoTestPlugin, {})
             .then(function () {
                 expect(plugin_util.info).not.toHaveBeenCalled();
 
                 var fetchTarget = plugman.fetch.calls.mostRecent().args[0];
                 expect(fetchTarget).toEqual(scopedPackage);
-            })
-            .fail(function (err) {
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            });
     }, 30000);
 });
diff --git a/integration-tests/plugin_fetch.spec.js b/integration-tests/plugin_fetch.spec.js
index 232486c..4c4d5cd 100644
--- a/integration-tests/plugin_fetch.spec.js
+++ b/integration-tests/plugin_fetch.spec.js
@@ -45,7 +45,6 @@ var cordovaVersion = '3.4.2';
 var tempDir = helpers.tmpDir('plugin_fetch_spec');
 var project = path.join(tempDir, 'project');
 
-var getVersionErrorCallback;
 var warnings = [];
 
 // Used to extract the constraint, the installed version, and the required
@@ -61,7 +60,7 @@ events.on('warn', function (warning) {
 // Tests a sample engine against the installed platforms/plugins in our test
 // project
 function testEngineWithProject (done, testEngine, testResult) {
-    plugin.getFetchVersion(project,
+    return plugin.getFetchVersion(project,
         {
             'version': '2.3.0',
             'name': 'test-plugin',
@@ -70,9 +69,8 @@ function testEngineWithProject (done, testEngine, testResult) {
         }, cordovaVersion)
         .then(function (toFetch) {
             expect(toFetch).toBe(testResult);
-        })
-        .fail(getVersionErrorCallback)
-        .fin(done);
+            done();
+        });
 }
 
 // Checks the warnings that were printed by the CLI to ensure that the code is
@@ -129,11 +127,9 @@ function getPluginRequirement (requirement) {
 }
 
 // Generates a callback that checks warning messages after the test is complete
-function getWarningCheckCallback (done, requirements) {
+function getWarningCheckCallback (requirements) {
     return function () {
         checkUnmetRequirements(requirements);
-        expect(getVersionErrorCallback).not.toHaveBeenCalled();
-        done();
     };
 }
 var fixtures = path.join(__dirname, '..', 'spec', 'cordova', 'fixtures');
@@ -178,10 +174,9 @@ describe('plugin fetching version selection', function () {
         });
 
         warnings = [];
-        getVersionErrorCallback = jasmine.createSpy('unexpectedPluginFetchErrorCallback');
     });
 
-    it('Test 001 : should handle a mix of upper bounds and single versions', function (done) {
+    it('Test 001 : should handle a mix of upper bounds and single versions', function () {
         var testEngine = {
             '0.0.0': { 'cordova-android': '1.0.0' },
             '0.0.2': { 'cordova-android': '>1.0.0' },
@@ -192,13 +187,13 @@ describe('plugin fetching version selection', function () {
             '2.3.0': { 'cordova-android': '6.1.1' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('6.1.1')
         ]);
-        testEngineWithProject(after, testEngine, '1.3.0');
+        return testEngineWithProject(after, testEngine, '1.3.0');
     }, 6000);
 
-    it('Test 002 : should apply upper bound engine constraints when there are no unspecified constraints above the upper bound', function (done) {
+    it('Test 002 : should apply upper bound engine constraints when there are no unspecified constraints above the upper bound', function () {
         var testEngine = {
             '1.0.0': { 'cordova-android': '>2.0.0' },
             '1.7.0': { 'cordova-android': '>4.0.0' },
@@ -209,185 +204,184 @@ describe('plugin fetching version selection', function () {
             '2.3.0': { 'cordova-android': '6.1.1' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('6.1.1')
         ]);
-        testEngineWithProject(after, testEngine, null);
+        return testEngineWithProject(after, testEngine, null);
     });
 
-    it('Test 003 : should apply upper bound engine constraints when there are unspecified constraints above the upper bound', function (done) {
+    it('Test 003 : should apply upper bound engine constraints when there are unspecified constraints above the upper bound', function () {
         var testEngine = {
             '0.0.0': {},
             '2.0.0': { 'cordova-android': '~5.0.0' },
             '<1.0.0': { 'cordova-android': '>5.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('~5.0.0')
         ]);
-        testEngineWithProject(after, testEngine, '1.7.1');
+        return testEngineWithProject(after, testEngine, '1.7.1');
 
     });
 
-    it('Test 004 : should handle the case where there are no constraints for earliest releases', function (done) {
+    it('Test 004 : should handle the case where there are no constraints for earliest releases', function () {
         var testEngine = {
             '1.0.0': { 'cordova-android': '~5.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('~5.0.0')
         ]);
-        testEngineWithProject(after, testEngine, '0.7.0');
+        return testEngineWithProject(after, testEngine, '0.7.0');
 
     });
 
-    it('Test 005 : should handle the case where the lowest version is unsatisfied', function (done) {
+    it('Test 005 : should handle the case where the lowest version is unsatisfied', function () {
         var testEngine = {
             '0.0.2': { 'cordova-android': '~5.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('~5.0.0')
         ]);
-        testEngineWithProject(after, testEngine, null);
+        return testEngineWithProject(after, testEngine, null);
 
     });
 
-    it('Test 006 : should handle upperbounds if no single version constraints are given', function (done) {
+    it('Test 006 : should handle upperbounds if no single version constraints are given', function () {
         var testEngine = {
             '<1.0.0': { 'cordova-android': '<2.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, []);
+        var after = getWarningCheckCallback([]);
 
-        testEngineWithProject(after, testEngine, '2.3.0');
+        return testEngineWithProject(after, testEngine, '2.3.0');
 
     });
 
-    it('Test 007 : should apply upper bounds greater than highest version', function (done) {
+    it('Test 007 : should apply upper bounds greater than highest version', function () {
         var testEngine = {
             '0.0.0': {},
             '<5.0.0': { 'cordova-android': '<2.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('<2.0.0')
         ]);
 
-        testEngineWithProject(after, testEngine, null);
+        return testEngineWithProject(after, testEngine, null);
 
     });
 
-    it('Test 008 : should treat empty constraints as satisfied', function (done) {
+    it('Test 008 : should treat empty constraints as satisfied', function () {
         var testEngine = {
             '1.0.0': {},
             '1.1.0': { 'cordova-android': '>5.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('>5.0.0')
         ]);
 
-        testEngineWithProject(after, testEngine, '1.0.0');
+        return testEngineWithProject(after, testEngine, '1.0.0');
 
     });
 
-    it('Test 009 : should ignore an empty cordovaDependencies entry', function (done) {
+    it('Test 009 : should ignore an empty cordovaDependencies entry', function () {
         var testEngine = {};
 
-        var after = getWarningCheckCallback(done, []);
+        var after = getWarningCheckCallback([]);
 
-        testEngineWithProject(after, testEngine, null);
+        return testEngineWithProject(after, testEngine, null);
 
     });
 
-    it('Test 010 : should ignore a badly formatted semver range', function (done) {
+    it('Test 010 : should ignore a badly formatted semver range', function () {
         var testEngine = {
             '1.1.3': { 'cordova-android': 'badSemverRange' }
         };
 
-        var after = getWarningCheckCallback(done, []);
+        var after = getWarningCheckCallback([]);
 
-        testEngineWithProject(after, testEngine, '2.3.0');
+        return testEngineWithProject(after, testEngine, '2.3.0');
 
     });
 
-    it('Test 011 : should respect unreleased versions in constraints', function (done) {
+    it('Test 011 : should respect unreleased versions in constraints', function () {
         var testEngine = {
             '1.0.0': { 'cordova-android': '3.1.0' },
             '1.1.2': { 'cordova-android': '6.1.1' },
             '1.3.0': { 'cordova-android': '6.1.1' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('6.1.1')
         ]);
 
-        testEngineWithProject(after, testEngine, '1.1.0');
+        return testEngineWithProject(after, testEngine, '1.1.0');
 
     });
 
-    it('Test 012 : should respect plugin constraints', function (done) {
+    it('Test 012 : should respect plugin constraints', function () {
         var testEngine = {
             '0.0.0': { 'ca.filmaj.AndroidPlugin': '1.2.0' },
             '1.1.3': { 'ca.filmaj.AndroidPlugin': '<5.0.0 || >2.3.0' },
             '2.3.0': { 'ca.filmaj.AndroidPlugin': '6.1.1' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPluginRequirement('6.1.1')
         ]);
 
-        testEngineWithProject(after, testEngine, '2.0.0');
+        return testEngineWithProject(after, testEngine, '2.0.0');
 
     });
 
-    it('Test 013 : should respect cordova constraints', function (done) {
+    it('Test 013 : should respect cordova constraints', function () {
         var testEngine = {
             '0.0.0': { 'cordova': '>1.0.0' },
             '1.1.3': { 'cordova': '<3.0.0 || >4.0.0' },
             '2.3.0': { 'cordova': '6.1.1' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getCordovaRequirement('6.1.1')
         ]);
 
-        testEngineWithProject(after, testEngine, '1.1.0');
+        return testEngineWithProject(after, testEngine, '1.1.0');
 
     });
 
-    it('Test 014 : should not include pre-release versions', function (done) {
+    it('Test 014 : should not include pre-release versions', function () {
         var testEngine = {
             '0.0.0': {},
             '2.0.0': { 'cordova-android': '>5.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('>5.0.0')
         ]);
 
         // Should not return 2.0.0-rc.2
-        testEngineWithProject(after, testEngine, '1.7.1');
+        return testEngineWithProject(after, testEngine, '1.7.1');
 
     });
 
-    it('Test 015 : should not fail if there is no engine in the npm info', function (done) {
-        plugin.getFetchVersion(project, {
+    it('Test 015 : should not fail if there is no engine in the npm info', function () {
+        return plugin.getFetchVersion(project, {
             version: '2.3.0',
             name: 'test-plugin',
             versions: testPluginVersions
         }, cordovaVersion)
             .then(function (toFetch) {
                 expect(toFetch).toBe(null);
-            })
-            .fail(getVersionErrorCallback).fin(done);
+            });
     });
 
-    it('Test 016 : should not fail if there is no cordovaDependencies in the engines', function (done) {
-        var after = getWarningCheckCallback(done, []);
+    it('Test 016 : should not fail if there is no cordovaDependencies in the engines', function () {
+        var after = getWarningCheckCallback([]);
 
-        plugin.getFetchVersion(project, {
+        return plugin.getFetchVersion(project, {
             version: '2.3.0',
             name: 'test-plugin',
             versions: testPluginVersions,
@@ -398,40 +392,40 @@ describe('plugin fetching version selection', function () {
         }, cordovaVersion)
             .then(function (toFetch) {
                 expect(toFetch).toBe(null);
-            })
-            .fail(getVersionErrorCallback).fin(after);
+                after();
+            });
 
     });
 
-    it('Test 017 : should handle extra whitespace', function (done) {
+    it('Test 017 : should handle extra whitespace', function () {
         var testEngine = {
             '  1.0.0    ': {},
             '2.0.0   ': { ' cordova-android': '~5.0.0   ' },
             ' <  1.0.0\t': { ' cordova-android  ': ' > 5.0.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('~5.0.0')
         ]);
 
-        testEngineWithProject(after, testEngine, '1.7.1');
+        return testEngineWithProject(after, testEngine, '1.7.1');
 
     });
 
-    it('Test 018 : should ignore badly typed version requirement entries', function (done) {
+    it('Test 018 : should ignore badly typed version requirement entries', function () {
         var testEngine = {
             '1.1.0': ['cordova', '5.0.0'],
             '1.3.0': undefined,
             '1.7.0': null
         };
 
-        var after = getWarningCheckCallback(done, []);
+        var after = getWarningCheckCallback([]);
 
-        testEngineWithProject(after, testEngine, '2.3.0');
+        return testEngineWithProject(after, testEngine, '2.3.0');
 
     });
 
-    it('Test 019 : should ignore badly typed constraint entries', function (done) {
+    it('Test 019 : should ignore badly typed constraint entries', function () {
         var testEngine = {
             '0.0.2': { 'cordova': 1 },
             '0.7.0': { 'cordova': {} },
@@ -441,13 +435,13 @@ describe('plugin fetching version selection', function () {
             '1.7.1': { 'cordova': null }
         };
 
-        var after = getWarningCheckCallback(done, []);
+        var after = getWarningCheckCallback([]);
 
-        testEngineWithProject(after, testEngine, '2.3.0');
+        return testEngineWithProject(after, testEngine, '2.3.0');
 
     });
 
-    it('Test 020 : should ignore bad semver versions', function (done) {
+    it('Test 020 : should ignore bad semver versions', function () {
         var testEngine = {
             '0.0.0': { 'cordova-android': '5.0.0' },
             'notAVersion': { 'cordova-android': '3.1.0' },
@@ -457,14 +451,14 @@ describe('plugin fetching version selection', function () {
             '2': { 'cordova-android': '3.1.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('5.0.0')
         ]);
 
-        testEngineWithProject(after, testEngine, null);
+        return testEngineWithProject(after, testEngine, null);
     });
 
-    it('Test 021 : should not fail if there are bad semver versions', function (done) {
+    it('Test 021 : should not fail if there are bad semver versions', function () {
         var testEngine = {
             'notAVersion': { 'cordova-android': '3.1.0' },
             '^1.1.2': { 'cordova-android': '3.1.0' },
@@ -475,14 +469,14 @@ describe('plugin fetching version selection', function () {
             '2': { 'cordova-android': '3.1.0' }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('5.1.0')
         ]);
 
-        testEngineWithProject(after, testEngine, '1.7.1');
+        return testEngineWithProject(after, testEngine, '1.7.1');
     });
 
-    it('Test 022 : should properly warn about multiple unmet requirements', function (done) {
+    it('Test 022 : should properly warn about multiple unmet requirements', function () {
         var testEngine = {
             '1.7.0': {
                 'cordova-android': '>5.1.0',
@@ -491,15 +485,15 @@ describe('plugin fetching version selection', function () {
             }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('>5.1.0'),
             getPluginRequirement('3.1.0')
         ]);
 
-        testEngineWithProject(after, testEngine, '1.3.0');
+        return testEngineWithProject(after, testEngine, '1.3.0');
     });
 
-    it('Test 023 : should properly warn about both unmet latest and upper bound requirements', function (done) {
+    it('Test 023 : should properly warn about both unmet latest and upper bound requirements', function () {
         var testEngine = {
             '1.7.0': { 'cordova-android': '>5.1.0' },
             '<5.0.0': {
@@ -508,15 +502,15 @@ describe('plugin fetching version selection', function () {
             }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('>5.1.0 AND >7.1.0'),
             getPluginRequirement('3.1.0')
         ]);
 
-        testEngineWithProject(after, testEngine, null);
+        return testEngineWithProject(after, testEngine, null);
     });
 
-    it('Test 024 : should not warn about versions past latest', function (done) {
+    it('Test 024 : should not warn about versions past latest', function () {
         var testEngine = {
             '1.7.0': { 'cordova-android': '>5.1.0' },
             '7.0.0': {
@@ -525,11 +519,11 @@ describe('plugin fetching version selection', function () {
             }
         };
 
-        var after = getWarningCheckCallback(done, [
+        var after = getWarningCheckCallback([
             getPlatformRequirement('>5.1.0')
         ]);
 
-        testEngineWithProject(after, testEngine, '1.3.0');
+        return testEngineWithProject(after, testEngine, '1.3.0');
     });
 
     it('Test 025 : clean up after plugin fetch spec', function () {
diff --git a/integration-tests/plugman_fetch.spec.js b/integration-tests/plugman_fetch.spec.js
index 985b9a4..e5ea116 100644
--- a/integration-tests/plugman_fetch.spec.js
+++ b/integration-tests/plugman_fetch.spec.js
@@ -37,12 +37,6 @@ var test_plugin_version = '0.6.0';
 var Q = require('q');
 
 describe('fetch', function () {
-
-    function wrapper (p, done, post) {
-        p.then(post, function (err) {
-            expect(err).toBeUndefined('Unexpected exception' + err.stack);
-        }).fin(done);
-    }
     /*
      * Taking out the following test. Fetch has a copyPlugin method that uses existsSync to see if a plugin already exists in the plugins folder. If the plugin exists in the plugins directory for the cordova project, it won't be copied over. This test fails now due it always returning true for existsSync.
     describe('plugin in a dir with spaces', function() {
@@ -53,7 +47,7 @@ describe('fetch', function () {
             spyOn(shell, 'rm');
             spyOn(metadata, 'save_fetch_metadata');
             var cp = spyOn(shell, 'cp');
-            wrapper(fetch(test_plugin_with_space, temp), done, function() {
+            fetch(test_plugin_with_space, temp).then(function() {
                 expect(cp).toHaveBeenCalledWith('-R', path.join(test_plugin_with_space, '*'), path.join(temp, test_plugin_id));
             });
         });
@@ -88,65 +82,64 @@ describe('fetch', function () {
             fetchCalls = 0;
         });
 
-        it('Test 001 : should copy locally-available plugin to plugins directory', function (done) {
-            wrapper(fetch(test_plugin, temp, { fetch: true }), done, function () {
+        it('Test 001 : should copy locally-available plugin to plugins directory', function () {
+            return fetch(test_plugin, temp, { fetch: true }).then(function () {
                 expect(cp).toHaveBeenCalledWith('-R', path.join(test_plugin, '*'), path.join(temp, test_plugin_id));
             });
         });
-        it('Test 002 : should copy locally-available plugin to plugins directory when adding a plugin with searchpath argument', function (done) {
-            wrapper(fetch(test_plugin_id, temp, { searchpath: test_plugin_searchpath }), done, function () {
+        it('Test 002 : should copy locally-available plugin to plugins directory when adding a plugin with searchpath argument', function () {
+            return fetch(test_plugin_id, temp, { searchpath: test_plugin_searchpath }).then(function () {
                 expect(cp).toHaveBeenCalledWith('-R', path.join(test_plugin, '*'), path.join(temp, test_plugin_id));
             });
         });
-        it('Test 003 : should create a symlink if used with `link` param', function (done) {
-            wrapper(fetch(test_plugin, temp, { fetch: true, link: true }), done, function () {
+        it('Test 003 : should create a symlink if used with `link` param', function () {
+            return fetch(test_plugin, temp, { fetch: true, link: true }).then(function () {
                 expect(sym).toHaveBeenCalledWith(test_plugin, path.join(temp, test_plugin_id), 'dir');
             });
         });
 
-        it('Test 004 : should fail when the expected ID doesn\'t match', function (done) {
-            fetch(test_plugin, temp, { expected_id: 'wrongID', fetch: true })
+        it('Test 004 : should fail when the expected ID doesn\'t match', function () {
+            return fetch(test_plugin, temp, { expected_id: 'wrongID', fetch: true })
                 .then(function () {
                     expect('this call').toBe('fail');
                 }, function (err) {
                     expect('' + err).toContain('Expected plugin to have ID "wrongID" but got');
-                }).fin(done);
+                });
         });
 
-        it('Test 005 : should succeed when the expected ID is correct', function (done) {
-            wrapper(fetch(test_plugin, temp, { expected_id: test_plugin_id, fetch: true }), done, function () {
-                expect(1).toBe(1);
+        it('Test 005 : should succeed when the expected ID is correct', function () {
+            return fetch(test_plugin, temp, { expected_id: test_plugin_id, fetch: true }).then(function () {
+                expect().nothing();
             });
         });
-        it('Test 006 : should fail when the expected ID with version specified doesn\'t match', function (done) {
-            fetch(test_plugin, temp, { expected_id: test_plugin_id + '@wrongVersion', fetch: true })
+        it('Test 006 : should fail when the expected ID with version specified doesn\'t match', function () {
+            return fetch(test_plugin, temp, { expected_id: test_plugin_id + '@wrongVersion', fetch: true })
                 .then(function () {
                     expect('this call').toBe('fail');
                 }, function (err) {
                     expect('' + err).toContain('to satisfy version "wrongVersion" but got');
-                }).fin(done);
+                });
         });
-        it('Test 007 : should succeed when the plugin version specified is correct', function (done) {
+        it('Test 007 : should succeed when the plugin version specified is correct', function () {
             var exp_id = test_plugin_id + '@' + test_plugin_version;
-            wrapper(fetch(test_plugin, temp, { expected_id: exp_id, fetch: true }), done, function () {
-                expect(1).toBe(1);
+            return fetch(test_plugin, temp, { expected_id: exp_id, fetch: true }).then(function () {
+                expect().nothing();
             });
         });
-        it('Test 027 : should copy locally-available plugin to plugins directory', function (done) {
-            wrapper(fetch(test_pkgjson_plugin, temp, {fetch: true}), done, function () {
+        it('Test 027 : should copy locally-available plugin to plugins directory', function () {
+            return fetch(test_pkgjson_plugin, temp, {fetch: true}).then(function () {
                 expect(cp).toHaveBeenCalledWith('-R', path.join(test_pkgjson_plugin, '*'), path.join(temp, 'pkgjson-test-plugin'));
                 expect(fetchCalls).toBe(1);
             });
         });
-        it('Test 028 : should fail when locally-available plugin is missing pacakge.json', function (done) {
+        it('Test 028 : should fail when locally-available plugin is missing pacakge.json', function () {
             test_plugin = path.join(plugins_dir, 'org.test.androidonly');
-            fetch(test_plugin, temp, {fetch: true})
+            return fetch(test_plugin, temp, {fetch: true})
                 .then(function () {
-                    expect(false).toBe(true);
-                }).fail(function (err) {
+                    fail();
+                }, function (err) {
                     expect(err).toBeDefined();
                     expect(err.message).toContain('needs a valid package.json');
-                    done();
                 });
         });
     });
@@ -160,19 +153,19 @@ describe('fetch', function () {
         });
 
         if (/^win/.test(process.platform)) {
-            it('Test 020 : should copy all but the /demo/ folder', function (done) {
+            it('Test 020 : should copy all but the /demo/ folder', function () {
                 var cp = spyOn(shell, 'cp');
-                wrapper(fetch(srcDir, appDir, {fetch: true}), done, function () {
+                return fetch(srcDir, appDir, {fetch: true}).then(function () {
                     expect(cp).toHaveBeenCalledWith('-R', path.join(srcDir, 'asset.txt'), path.join(appDir, 'test-recursive'));
                     expect(cp).not.toHaveBeenCalledWith('-R', srcDir, path.join(appDir, 'test-recursive'));
                 });
             });
         } else {
-            it('Test 021 : should skip copy to avoid recursive error', function (done) {
+            it('Test 021 : should skip copy to avoid recursive error', function () {
 
                 var cp = spyOn(shell, 'cp').and.callFake(function () {});
 
-                wrapper(fetch(srcDir, appDir, {fetch: true}), done, function () {
+                return fetch(srcDir, appDir, {fetch: true}).then(function () {
                     expect(cp).not.toHaveBeenCalled();
                 });
             });
diff --git a/integration-tests/plugman_uninstall.spec.js b/integration-tests/plugman_uninstall.spec.js
index babff69..5faa8a7 100644
--- a/integration-tests/plugman_uninstall.spec.js
+++ b/integration-tests/plugman_uninstall.spec.js
@@ -31,7 +31,6 @@ var path = require('path');
 var shell = require('shelljs');
 var Q = require('q');
 var spec = path.join(__dirname, '..', 'spec', 'plugman');
-var done = false;
 var srcProject = path.join(spec, 'projects', 'android');
 var project = path.join(spec, 'projects', 'android_uninstall.test');
 var project2 = path.join(spec, 'projects', 'android_uninstall.test2');
@@ -76,7 +75,7 @@ describe('plugman uninstall start', function () {
         });
     });
 
-    it('Test 001 : plugman uninstall start', function (done) {
+    it('Test 001 : plugman uninstall start', function () {
         shell.rm('-rf', project, project2, project3);
         shell.cp('-R', path.join(srcProject, '*'), project);
         shell.cp('-R', path.join(srcProject, '*'), project2);
@@ -95,9 +94,6 @@ describe('plugman uninstall start', function () {
                 return install('android', project3, plugins['C']);
             }).then(function (result) {
                 expect(result).toEqual(true);
-                done();
-            }).fail(function (err) {
-                expect(err).toBeUndefined();
             });
     }, 60000);
 });
@@ -114,26 +110,21 @@ describe('uninstallPlatform', function () {
         fsWrite = spyOn(fs, 'writeFileSync').and.returnValue(true);
         rm = spyOn(shell, 'rm').and.returnValue(true);
         spyOn(shell, 'cp').and.returnValue(true);
-        done = false;
     });
     describe('success', function () {
 
-        it('Test 002 : should get PlatformApi instance for platform and invoke its\' removePlugin method', function (done) {
+        it('Test 002 : should get PlatformApi instance for platform and invoke its\' removePlugin method', function () {
             var platformApi = { removePlugin: jasmine.createSpy('removePlugin').and.returnValue(Q()) };
             var getPlatformApi = spyOn(platforms, 'getPlatformApi').and.returnValue(platformApi);
 
-            uninstall.uninstallPlatform('android', project, dummy_id)
+            return uninstall.uninstallPlatform('android', project, dummy_id)
                 .then(function () {
                     expect(getPlatformApi).toHaveBeenCalledWith('android', project);
                     expect(platformApi.removePlugin).toHaveBeenCalled();
-                    done();
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
-                    done();
                 });
         }, 6000);
 
-        it('Test 003 : should return propagate value returned by PlatformApi removePlugin method', function (done) {
+        it('Test 003 : should return propagate value returned by PlatformApi removePlugin method', function () {
             var platformApi = { removePlugin: jasmine.createSpy('removePlugin') };
             spyOn(platforms, 'getPlatformApi').and.returnValue(platformApi);
 
@@ -162,11 +153,10 @@ describe('uninstallPlatform', function () {
                 }, Q());
             }
 
-            validateReturnedResultFor([ true, {}, [], 'foo', function () {} ], true)
+            return validateReturnedResultFor([ true, {}, [], 'foo', function () {} ], true)
                 .then(function () {
                     return validateReturnedResultFor([ false, null, undefined, '' ], false);
-                })
-                .fin(done);
+                });
         });
 
         describe('with dependencies', function () {
@@ -174,34 +164,29 @@ describe('uninstallPlatform', function () {
             beforeEach(function () {
                 emit = spyOn(events, 'emit');
             });
-            uninstall.uninstallPlatform('android', project, 'A')
+            return uninstall.uninstallPlatform('android', project, 'A')
                 .then(function (result) {
                     expect(emit).toHaveBeenCalledWith('log', 'Uninstalling 2 dependent plugins.');
-                    done();
                 });
         });
     });
 
     describe('failure ', function () {
-        it('Test 004 : should throw if platform is unrecognized', function (done) {
-            uninstall.uninstallPlatform('atari', project, 'SomePlugin')
+        it('Test 004 : should throw if platform is unrecognized', function () {
+            return uninstall.uninstallPlatform('atari', project, 'SomePlugin')
                 .then(function (result) {
-                    expect(false).toBe(true);
-                    done();
-                }).fail(function err (errMsg) {
+                    fail();
+                }, function err (errMsg) {
                     expect(errMsg.toString()).toContain('atari not supported.');
-                    done();
                 });
         }, 6000);
 
-        it('Test 005 : should throw if plugin is missing', function (done) {
-            uninstall.uninstallPlatform('android', project, 'SomePluginThatDoesntExist')
+        it('Test 005 : should throw if plugin is missing', function () {
+            return uninstall.uninstallPlatform('android', project, 'SomePluginThatDoesntExist')
                 .then(function (result) {
-                    expect(false).toBe(true);
-                    done();
-                }).fail(function err (errMsg) {
+                    fail();
+                }, function err (errMsg) {
                     expect(errMsg.toString()).toContain('Plugin "SomePluginThatDoesntExist" not found. Already uninstalled?');
-                    done();
                 });
         }, 6000);
     });
@@ -220,12 +205,11 @@ describe('uninstallPlugin', function () {
         rm = spyOn(shell, 'rm').and.callFake(function (f, p) { rmstack.push(p); return true; });
         rmstack = [];
         emit = spyOn(events, 'emit');
-        done = false;
     });
     describe('with dependencies', function () {
 
-        it('Test 006 : should delete all dependent plugins', function (done) {
-            uninstall.uninstallPlugin('A', plugins_install_dir)
+        it('Test 006 : should delete all dependent plugins', function () {
+            return uninstall.uninstallPlugin('A', plugins_install_dir)
                 .then(function (result) {
                     var del = common.spy.getDeleted(emit);
                     expect(del).toEqual([
@@ -233,51 +217,45 @@ describe('uninstallPlugin', function () {
                         'Deleted "D"',
                         'Deleted "A"'
                     ]);
-                    done();
                 });
         });
 
-        it('Test 007 : should fail if plugin is a required dependency', function (done) {
-            uninstall.uninstallPlugin('C', plugins_install_dir)
+        it('Test 007 : should fail if plugin is a required dependency', function () {
+            return uninstall.uninstallPlugin('C', plugins_install_dir)
                 .then(function (result) {
-                    expect(false).toBe(true);
-                    done();
-                }).fail(function err (errMsg) {
+                    fail();
+                }, function err (errMsg) {
                     expect(errMsg.toString()).toEqual('"C" is required by (A) and cannot be removed (hint: use -f or --force)');
-                    done();
                 });
         }, 6000);
 
-        it('Test 008 : allow forcefully removing a plugin', function (done) {
-            uninstall.uninstallPlugin('C', plugins_install_dir, {force: true})
+        it('Test 008 : allow forcefully removing a plugin', function () {
+            return uninstall.uninstallPlugin('C', plugins_install_dir, {force: true})
                 .then(function () {
                     var del = common.spy.getDeleted(emit);
                     expect(del).toEqual(['Deleted "C"']);
-                    done();
                 });
         });
 
-        it('Test 009 : never remove top level plugins if they are a dependency', function (done) {
-            uninstall.uninstallPlugin('A', plugins_install_dir2)
+        it('Test 009 : never remove top level plugins if they are a dependency', function () {
+            return uninstall.uninstallPlugin('A', plugins_install_dir2)
                 .then(function () {
                     var del = common.spy.getDeleted(emit);
                     expect(del).toEqual([
                         'Deleted "D"',
                         'Deleted "A"'
                     ]);
-                    done();
                 });
         });
 
-        it('Test 010 : should not remove dependent plugin if it was installed after as top-level', function (done) {
-            uninstall.uninstallPlugin('A', plugins_install_dir3)
+        it('Test 010 : should not remove dependent plugin if it was installed after as top-level', function () {
+            return uninstall.uninstallPlugin('A', plugins_install_dir3)
                 .then(function () {
                     var del = common.spy.getDeleted(emit);
                     expect(del).toEqual([
                         'Deleted "D"',
                         'Deleted "A"'
                     ]);
-                    done();
                 });
         });
     });
@@ -292,36 +270,31 @@ describe('uninstall', function () {
     beforeEach(function () {
         fsWrite = spyOn(fs, 'writeFileSync').and.returnValue(true);
         rm = spyOn(shell, 'rm').and.returnValue(true);
-        done = false;
     });
 
     describe('failure', function () {
-        it('Test 011 : should throw if platform is unrecognized', function (done) {
+        it('Test 011 : should throw if platform is unrecognized', function () {
             return uninstall('atari', project, 'SomePlugin')
                 .then(function (result) {
-                    expect(false).toBe(true);
-                    done();
-                }).fail(function err (errMsg) {
+                    fail();
+                }, function err (errMsg) {
                     expect(errMsg.toString()).toContain('atari not supported.');
-                    done();
                 });
         }, 6000);
 
-        it('Test 012 : should throw if plugin is missing', function (done) {
-            uninstall('android', project, 'SomePluginThatDoesntExist')
+        it('Test 012 : should throw if plugin is missing', function () {
+            return uninstall('android', project, 'SomePluginThatDoesntExist')
                 .then(function (result) {
-                    expect(false).toBe(true);
-                    done();
-                }).fail(function err (errMsg) {
+                    fail();
+                }, function err (errMsg) {
                     expect(errMsg.toString()).toContain('Plugin "SomePluginThatDoesntExist" not found. Already uninstalled?');
-                    done();
                 });
         }, 6000);
     });
 });
 
 describe('end', function () {
-    it('Test 013 : end', function (done) {
+    it('Test 013 : end', function () {
         return uninstall('android', project, plugins['org.test.plugins.dummyplugin'])
             .then(function () {
                 // Fails... A depends on
@@ -334,7 +307,6 @@ describe('end', function () {
             }).fin(function (err) {
                 if (err) { events.emit('error', err); }
                 shell.rm('-rf', project, project2, project3);
-                done();
             });
     });
 });
diff --git a/spec/cordova/build.spec.js b/spec/cordova/build.spec.js
index c7919b2..5de8330 100644
--- a/spec/cordova/build.spec.js
+++ b/spec/cordova/build.spec.js
@@ -41,92 +41,90 @@ describe('build command', function () {
         compile_spy = spyOn(cordova, 'compile').and.returnValue(Q());
     });
     describe('failure', function () {
-        it('Test 001 : should not run inside a project with no platforms', function (done) {
+        it('Test 001 : should not run inside a project with no platforms', function () {
             list_platforms.and.returnValue([]);
-            cordova.build()
+            return cordova.build()
                 .then(function () {
-                    expect('this call').toBe('fail');
+                    fail('Expected promise to be rejected');
                 }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
                     expect(err.message).toEqual(
                         'No platforms added to this project. Please use `cordova platform add <platform>`.'
                     );
-                }).fin(done);
+                });
         });
 
-        it('Test 002 : should not run outside of a Cordova-based project', function (done) {
+        it('Test 002 : should not run outside of a Cordova-based project', function () {
             is_cordova.and.returnValue(false);
 
-            cordova.build()
+            return cordova.build()
                 .then(function () {
-                    expect('this call').toBe('fail');
+                    fail('Expected promise to be rejected');
                 }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
                     expect(err.message).toEqual(
                         'Current working directory is not a Cordova-based project.'
                     );
-                }).fin(done);
+                });
         });
     });
 
     describe('success', function () {
-        it('Test 003 : should run inside a Cordova-based project with at least one added platform and call both prepare and compile', function (done) {
-            cordova.build(['android', 'ios']).then(function () {
+        it('Test 003 : should run inside a Cordova-based project with at least one added platform and call both prepare and compile', function () {
+            return cordova.build(['android', 'ios']).then(function () {
                 var opts = Object({ platforms: [ 'android', 'ios' ], verbose: false, options: Object({ }) });
                 expect(prepare_spy).toHaveBeenCalledWith(opts);
                 expect(compile_spy).toHaveBeenCalledWith(opts);
-                done();
             });
         });
-        it('Test 004 : should pass down options', function (done) {
-            cordova.build({platforms: ['android'], options: {release: true}}).then(function () {
+        it('Test 004 : should pass down options', function () {
+            return cordova.build({platforms: ['android'], options: {release: true}}).then(function () {
                 var opts = {platforms: ['android'], options: {release: true}, verbose: false};
                 expect(prepare_spy).toHaveBeenCalledWith(opts);
                 expect(compile_spy).toHaveBeenCalledWith(opts);
-                done();
             });
         });
 
-        it('Test 005 : should convert options from old format and warn user about this', function (done) {
+        it('Test 005 : should convert options from old format and warn user about this', function () {
             function warnSpy (message) {
                 expect(message).toMatch('The format of cordova.* methods "options" argument was changed');
             }
 
             cordova.on('warn', warnSpy);
-            cordova.build({platforms: ['android'], options: ['--release', '--cdvBuildOpt=opt']}).then(function () {
+            return cordova.build({platforms: ['android'], options: ['--release', '--cdvBuildOpt=opt']}).then(function () {
                 var opts = {platforms: ['android'], options: jasmine.objectContaining({release: true, argv: ['--cdvBuildOpt=opt']}), verbose: false};
                 expect(prepare_spy).toHaveBeenCalledWith(opts);
                 expect(compile_spy).toHaveBeenCalledWith(opts);
                 cordova.off('warn', warnSpy);
-                done();
             });
         });
     });
 
     describe('hooks', function () {
         describe('when platforms are added', function () {
-            it('Test 006 : should fire before hooks through the hooker module', function (done) {
-                cordova.build(['android', 'ios']).then(function () {
+            it('Test 006 : should fire before hooks through the hooker module', function () {
+                return cordova.build(['android', 'ios']).then(function () {
                     expect(fire.calls.argsFor(0)).toEqual(['before_build', {verbose: false, platforms: ['android', 'ios'], options: {}}]);
-                    done();
                 });
             });
-            it('Test 007 : should fire after hooks through the hooker module', function (done) {
-                cordova.build('android').then(function () {
+            it('Test 007 : should fire after hooks through the hooker module', function () {
+                return cordova.build('android').then(function () {
                     expect(fire.calls.argsFor(1)).toEqual([ 'after_build', { platforms: [ 'android' ], verbose: false, options: {} } ]);
-                    done();
                 });
             });
         });
 
         describe('with no platforms added', function () {
-            it('Test 008 : should not fire the hooker', function (done) {
+            it('Test 008 : should not fire the hooker', function () {
                 list_platforms.and.returnValue([]);
-                Q().then(cordova.build).then(function () {
-                    expect('this call').toBe('fail');
+                return Q().then(cordova.build).then(function () {
+                    fail('Expected promise to be rejected');
                 }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
                     expect(err.message).toEqual(
                         'No platforms added to this project. Please use `cordova platform add <platform>`.'
                     );
-                }).fin(done);
+                });
             });
         });
     });
diff --git a/spec/cordova/compile.spec.js b/spec/cordova/compile.spec.js
index e090fb6..2dfefce 100644
--- a/spec/cordova/compile.spec.js
+++ b/spec/cordova/compile.spec.js
@@ -29,7 +29,6 @@ describe('compile command', function () {
     var list_platforms;
     var fire;
     var cd_project_root; // eslint-disable-line no-unused-vars
-    var fail;
     var platformApi;
     var getPlatformApi;
     var project_dir = '/some/path';
@@ -41,110 +40,93 @@ describe('compile command', function () {
         fire = spyOn(HooksRunner.prototype, 'fire').and.returnValue(Q());
         platformApi = { build: jasmine.createSpy('build').and.returnValue(Q()) };
         getPlatformApi = spyOn(platforms, 'getPlatformApi').and.returnValue(platformApi);
-        fail = function (err) { expect(err.stack).not.toBeDefined(); };
     });
     describe('failure', function () {
-        it('Test 001 : should not run inside a Cordova-based project with no added platforms by calling util.listPlatforms', function (done) {
+        it('Test 001 : should not run inside a Cordova-based project with no added platforms by calling util.listPlatforms', function () {
             list_platforms.and.returnValue([]);
-            var success = jasmine.createSpy('success');
-            cordova.compile()
-                .then(success, function (result) {
-                    expect(result instanceof Error).toBe(true);
-                    expect('' + result).toContain('No platforms added to this project. Please use `cordova platform add <platform>`.');
-                })
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    done();
+            return cordova.compile()
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toContain('No platforms added to this project. Please use `cordova platform add <platform>`.');
                 });
         });
-        it('Test 002 : should not run outside of a Cordova-based project', function (done) {
+        it('Test 002 : should not run outside of a Cordova-based project', function () {
             is_cordova.and.returnValue(false);
-            var success = jasmine.createSpy('success');
-            cordova.compile()
-                .then(success, function (result) {
-                    expect(result instanceof Error).toBe(true);
-                })
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    done();
+            return cordova.compile()
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
                 });
         });
     });
 
     describe('success', function () {
-        it('Test 003 : should run inside a Cordova-based project with at least one added platform and shell out to build', function (done) {
-            cordova.compile(['android', 'ios'])
+        it('Test 003 : should run inside a Cordova-based project with at least one added platform and shell out to build', function () {
+            return cordova.compile(['android', 'ios'])
                 .then(function () {
                     expect(getPlatformApi).toHaveBeenCalledWith('android');
                     expect(getPlatformApi).toHaveBeenCalledWith('ios');
                     expect(platformApi.build).toHaveBeenCalled();
-                })
-                .fail(fail)
-                .fin(done);
+                });
         });
 
-        it('Test 004 : should pass down optional parameters', function (done) {
-            cordova.compile({platforms: ['blackberry10'], options: {release: true}})
+        it('Test 004 : should pass down optional parameters', function () {
+            return cordova.compile({platforms: ['blackberry10'], options: {release: true}})
                 .then(function () {
                     expect(getPlatformApi).toHaveBeenCalledWith('blackberry10');
                     expect(platformApi.build).toHaveBeenCalledWith({release: true});
-                })
-                .fail(fail)
-                .fin(done);
+                });
         });
 
-        it('Test 005 : should convert options from old format and warn user about this', function (done) {
+        it('Test 005 : should convert options from old format and warn user about this', function () {
             function warnSpy (message) {
                 expect(message).toMatch('The format of cordova.* methods "options" argument was changed');
             }
 
             cordova.on('warn', warnSpy);
-            cordova.compile({platforms: ['blackberry10'], options: ['--release']})
+            return cordova.compile({platforms: ['blackberry10'], options: ['--release']})
                 .then(function () {
                     expect(getPlatformApi).toHaveBeenCalledWith('blackberry10');
                     expect(platformApi.build).toHaveBeenCalledWith({release: true, argv: []});
                 })
-                .fail(fail)
                 .fin(function () {
                     cordova.off('warn', warnSpy);
-                    done();
                 });
         });
     });
 
     describe('hooks', function () {
         describe('when platforms are added', function () {
-            it('Test 006 : should fire before hooks through the hooker module', function (done) {
-                cordova.compile(['android', 'ios'])
+            it('Test 006 : should fire before hooks through the hooker module', function () {
+                return cordova.compile(['android', 'ios'])
                     .then(function () {
                         expect(fire.calls.argsFor(0)).toEqual(['before_compile', {verbose: false, platforms: ['android', 'ios'], options: {}}]);
-                        done();
-                    })
-                    .fail(fail)
-                    .fin(done);
+                    });
             });
-            it('Test 007 : should fire after hooks through the hooker module', function (done) {
-                cordova.compile('android')
+            it('Test 007 : should fire after hooks through the hooker module', function () {
+                return cordova.compile('android')
                     .then(function () {
                         expect(fire.calls.argsFor(1)).toEqual(['after_compile', {verbose: false, platforms: ['android'], options: {}}]);
-                        done();
-                    })
-                    .fail(fail)
-                    .fin(done);
+                    });
             });
         });
 
         describe('with no platforms added', function () {
-            it('Test 008 : should not fire the hooker', function (done) {
+            it('Test 008 : should not fire the hooker', function () {
                 list_platforms.and.returnValue([]);
-                Q().then(cordova.compile).then(function () {
-                    expect('this call').toBe('fail');
-                }, function (err) {
-                    expect(fire).not.toHaveBeenCalled();
-                    expect(err.message).toContain(
-                        'No platforms added to this project. Please use `cordova platform add <platform>`.'
-                    );
-                }).fin(done);
+                return Q().then(cordova.compile)
+                    .then(function () {
+                        fail('Expected promise to be rejected');
+                    }, function (err) {
+                        expect(err).toEqual(jasmine.any(Error));
+                        expect(fire).not.toHaveBeenCalled();
+                        expect(err.message).toContain(
+                            'No platforms added to this project. Please use `cordova platform add <platform>`.'
+                        );
+                    });
             });
         });
     });
diff --git a/spec/cordova/create.spec.js b/spec/cordova/create.spec.js
index 0a088e1..d4a5e23 100644
--- a/spec/cordova/create.spec.js
+++ b/spec/cordova/create.spec.js
@@ -39,20 +39,22 @@ var configBasic = {
 };
 
 describe('cordova create checks for valid-identifier', function () {
-    it('Test 001 : should reject reserved words from start of id', function (done) {
-        cordova.create('projectPath', 'int.bob', 'appName', {}, events)
-            .fail(function (err) {
+    it('Test 001 : should reject reserved words from start of id', function () {
+        return cordova.create('projectPath', 'int.bob', 'appName', {}, events)
+            .then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
                 expect(err.message).toBe('App id contains a reserved word, or is not a valid identifier.');
-            })
-            .fin(done);
+            });
     });
 
-    it('Test 002 : should reject reserved words from end of id', function (done) {
-        cordova.create('projectPath', 'bob.class', 'appName', {}, events)
-            .fail(function (err) {
+    it('Test 002 : should reject reserved words from end of id', function () {
+        return cordova.create('projectPath', 'bob.class', 'appName', {}, events)
+            .then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
                 expect(err.message).toBe('App id contains a reserved word, or is not a valid identifier.');
-            })
-            .fin(done);
+            });
     });
 });
 
@@ -92,19 +94,13 @@ describe('create basic test (see more in cordova-create)', function () {
     var results; // eslint-disable-line no-unused-vars
     events.on('results', function (res) { results = res; });
 
-    it('Test 003 : should successfully run', function (done) {
-        // Call cordova create with no args, should return help.
-        Q()
+    it('Test 003 : should successfully run', function () {
+        return Q()
             .then(function () {
                 // Create a real project
                 return cordova.create(project, appId, appName, configBasic, events);
             })
-            .then(checkProject)
-            .fail(function (err) {
-                console.log(err && err.stack);
-                expect(err).toBeUndefined();
-            })
-            .fin(done);
+            .then(checkProject);
     }, 60000);
 
 });
diff --git a/spec/cordova/emulate.spec.js b/spec/cordova/emulate.spec.js
index f698a2e..f1e9582 100644
--- a/spec/cordova/emulate.spec.js
+++ b/spec/cordova/emulate.spec.js
@@ -48,73 +48,61 @@ describe('emulate command', function () {
         getPlatformApi = spyOn(platforms, 'getPlatformApi').and.returnValue(platformApi);
     });
     describe('failure', function () {
-        it('Test 001 : should not run inside a Cordova-based project with no added platforms by calling util.listPlatforms', function (done) {
+        it('Test 001 : should not run inside a Cordova-based project with no added platforms by calling util.listPlatforms', function () {
             list_platforms.and.returnValue([]);
-            var success = jasmine.createSpy('success');
-            cordova.compile()
-                .then(success, function (result) {
-                    expect(result instanceof Error).toBe(true);
-                    expect('' + result).toContain('No platforms added to this project. Please use `cordova platform add <platform>`.');
-                })
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    done();
+            return cordova.compile()
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toContain('No platforms added to this project. Please use `cordova platform add <platform>`.');
                 });
         });
-        it('Test 002 : should not run outside of a Cordova-based project', function (done) {
+        it('Test 002 : should not run outside of a Cordova-based project', function () {
             is_cordova.and.returnValue(false);
-            var success = jasmine.createSpy('success');
-            cordova.compile()
-                .then(success, function (result) {
-                    expect(result instanceof Error).toBe(true);
-                })
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    done();
+            return cordova.compile()
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
                 });
         });
     });
 
     describe('success', function () {
-        it('Test 003 : should run inside a Cordova-based project with at least one added platform and call prepare and shell out to the emulate script', function (done) {
-            cordova.emulate(['android', 'ios'])
+        it('Test 003 : should run inside a Cordova-based project with at least one added platform and call prepare and shell out to the emulate script', function () {
+            return cordova.emulate(['android', 'ios'])
                 .then(function (err) { // eslint-disable-line handle-callback-err
                     expect(prepare_spy).toHaveBeenCalledWith(jasmine.objectContaining({platforms: ['android', 'ios']}));
                     expect(getPlatformApi).toHaveBeenCalledWith('android');
                     expect(getPlatformApi).toHaveBeenCalledWith('ios');
                     expect(platformApi.build).toHaveBeenCalled();
                     expect(platformApi.run).toHaveBeenCalled();
-                })
-                .fail(fail)
-                .fin(done);
+                });
         });
-        it('Test 004 : should pass down options', function (done) {
-            cordova.emulate({platforms: ['ios'], options: { optionTastic: true }})
+        it('Test 004 : should pass down options', function () {
+            return cordova.emulate({platforms: ['ios'], options: { optionTastic: true }})
                 .then(function (err) { // eslint-disable-line handle-callback-err
                     expect(prepare_spy).toHaveBeenCalledWith(jasmine.objectContaining({platforms: ['ios']}));
                     expect(getPlatformApi).toHaveBeenCalledWith('ios');
                     expect(platformApi.build).toHaveBeenCalledWith({ device: false, emulator: true, optionTastic: true });
                     expect(platformApi.run).toHaveBeenCalledWith({ device: false, emulator: true, optionTastic: true, nobuild: true });
-                })
-                .fail(fail)
-                .fin(done);
+                });
         });
-        it('Test 005 : should convert options from old format and warn user about this', function (done) {
+        it('Test 005 : should convert options from old format and warn user about this', function () {
             function warnSpy (message) {
                 expect(message).toMatch('The format of cordova.* methods "options" argument was changed');
             }
 
             cordova.on('warn', warnSpy);
-            cordova.emulate({platforms: ['ios'], options: ['--optionTastic']})
+            return cordova.emulate({platforms: ['ios'], options: ['--optionTastic']})
                 .then(function () {
                     expect(prepare_spy).toHaveBeenCalledWith(jasmine.objectContaining({platforms: ['ios']}));
                     expect(getPlatformApi).toHaveBeenCalledWith('ios');
                     expect(platformApi.run).toHaveBeenCalledWith(jasmine.objectContaining({emulator: true, argv: ['--optionTastic']}));
                 })
-                .fail(fail)
                 .fin(function () {
                     cordova.off('warn', warnSpy);
-                    done();
                 });
         });
         describe('run parameters should not be altered by intermediate build command', function () {
@@ -129,74 +117,63 @@ describe('emulate command', function () {
             afterEach(function () {
                 platformApi.build = originalBuildSpy;
             });
-            it('Test 006 : should leave parameters unchanged', function (done) {
-                cordova.run({platforms: ['blackberry10'], options: {password: '1q1q'}})
+            it('Test 006 : should leave parameters unchanged', function () {
+                return cordova.run({platforms: ['blackberry10'], options: {password: '1q1q'}})
                     .then(function () {
                         expect(prepare_spy).toHaveBeenCalledWith({ platforms: [ 'blackberry10' ], options: { password: '1q1q', 'couldBeModified': 'insideBuild' }, verbose: false });
                         expect(platformApi.build).toHaveBeenCalledWith({password: '1q1q', 'couldBeModified': 'insideBuild'});
                         expect(platformApi.run).toHaveBeenCalledWith({password: '1q1q', nobuild: true});
-                    }, function (err) {
-                        expect(err).toBeUndefined();
-                    }).fin(done);
+                    });
             });
         });
 
-        it('Test 007 : should call platform\'s build method', function (done) {
-            cordova.emulate({platforms: ['blackberry10']})
+        it('Test 007 : should call platform\'s build method', function () {
+            return cordova.emulate({platforms: ['blackberry10']})
                 .then(function () {
                     expect(prepare_spy).toHaveBeenCalled();
                     expect(platformApi.build).toHaveBeenCalledWith({device: false, emulator: true});
                     expect(platformApi.run).toHaveBeenCalledWith(jasmine.objectContaining({nobuild: true}));
-                }, function (err) {
-                    expect(err).toBeUndefined();
-                })
-                .fin(done);
+                });
         });
 
-        it('Test 008 : should not call build if --nobuild option is passed', function (done) {
-            cordova.emulate({platforms: ['blackberry10'], options: { nobuild: true }})
+        it('Test 008 : should not call build if --nobuild option is passed', function () {
+            return cordova.emulate({platforms: ['blackberry10'], options: { nobuild: true }})
                 .then(function () {
                     expect(prepare_spy).toHaveBeenCalled();
                     expect(platformApi.build).not.toHaveBeenCalled();
                     expect(platformApi.run).toHaveBeenCalledWith(jasmine.objectContaining({nobuild: true}));
-                }, function (err) {
-                    expect(err).toBeUndefined();
-                })
-                .fin(done);
+                });
         });
     });
 
     describe('hooks', function () {
         describe('when platforms are added', function () {
-            it('Test 009 : should fire before hooks through the hooker module', function (done) {
-                cordova.emulate(['android', 'ios'])
+            it('Test 009 : should fire before hooks through the hooker module', function () {
+                return cordova.emulate(['android', 'ios'])
                     .then(function () {
                         expect(fire).toHaveBeenCalledWith('before_emulate',
                             jasmine.objectContaining({verbose: false, platforms: ['android', 'ios'], options: jasmine.any(Object)}));
-                    })
-                    .fail(fail)
-                    .fin(done);
+                    });
             });
-            it('Test 010 : should fire after hooks through the hooker module', function (done) {
-                cordova.emulate('android')
+            it('Test 010 : should fire after hooks through the hooker module', function () {
+                return cordova.emulate('android')
                     .then(function () {
                         expect(fire).toHaveBeenCalledWith('after_emulate',
                             jasmine.objectContaining({verbose: false, platforms: ['android'], options: jasmine.any(Object)}));
-                    })
-                    .fail(fail)
-                    .fin(done);
+                    });
             });
         });
 
         describe('with no platforms added', function () {
-            it('Test 011 : should not fire the hooker', function (done) {
+            it('Test 011 : should not fire the hooker', function () {
                 list_platforms.and.returnValue([]);
-                Q().then(cordova.emulate).then(function () {
-                    expect('this call').toBe('fail');
+                return Q().then(cordova.emulate).then(function () {
+                    fail('Expected promise to be rejected');
                 }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toContain('No platforms added to this project. Please use `cordova platform add <platform>`.');
                     expect(fire).not.toHaveBeenCalled();
-                    expect('' + err).toContain('No platforms added to this project. Please use `cordova platform add <platform>`.');
-                }).fin(done);
+                });
             });
         });
     });
diff --git a/spec/cordova/platform/addHelper.spec.js b/spec/cordova/platform/addHelper.spec.js
index ce76078..2fc88cc 100644
--- a/spec/cordova/platform/addHelper.spec.js
+++ b/spec/cordova/platform/addHelper.spec.js
@@ -95,39 +95,39 @@ describe('cordova/platform/addHelper', function () {
         prepare_revert_mock();
     });
     describe('error/warning conditions', function () {
-        it('should require specifying at least one platform', function (done) {
-            platform_addHelper('add', hooks_mock).then(function () {
+        it('should require specifying at least one platform', function () {
+            return platform_addHelper('add', hooks_mock).then(function () {
                 fail('addHelper success handler unexpectedly invoked');
-            }).fail(function (e) {
+            }, function (e) {
                 expect(e.message).toContain('No platform specified.');
-            }).done(done);
+            });
         });
 
-        it('should log if host OS does not support the specified platform', function (done) {
+        it('should log if host OS does not support the specified platform', function () {
             cordova_util.hostSupports.and.returnValue(false);
-            platform_addHelper('add', hooks_mock, projectRoot, ['atari']).then(function () {
+            return platform_addHelper('add', hooks_mock, projectRoot, ['atari']).then(function () {
                 fail('addHelper success handler unexpectedly invoked');
-            }).fail(function (e) {
+            }, function (e) {
                 expect(cordova_util.hostSupports).toHaveBeenCalled();
                 expect(events.emit).toHaveBeenCalledWith('warning', jasmine.stringMatching(/WARNING: Applications/));
-            }).done(done);
+            });
         });
 
-        it('should throw if platform was already added before adding', function (done) {
+        it('should throw if platform was already added before adding', function () {
             fs.existsSync.and.returnValue('/some/path/platforms/ios');
-            platform_addHelper('add', hooks_mock, projectRoot, ['ios']).then(function () {
+            return platform_addHelper('add', hooks_mock, projectRoot, ['ios']).then(function () {
                 fail('addHelper success handler unexpectedly invoked');
-            }).fail(function (e) {
+            }, function (e) {
                 expect(e.message).toContain('already added.');
-            }).done(done);
+            });
         });
 
-        it('should throw if platform was not added before updating', function (done) {
-            platform_addHelper('update', hooks_mock, projectRoot, ['atari']).then(function () {
+        it('should throw if platform was not added before updating', function () {
+            return platform_addHelper('update', hooks_mock, projectRoot, ['atari']).then(function () {
                 fail('addHelper success handler unexpectedly invoked');
-            }).fail(function (e) {
+            }, function (e) {
                 expect(e.message).toContain('Platform "atari" is not yet added. See `cordova platform list`.');
-            }).done(done);
+            });
         });
     });
     describe('happy path (success conditions)', function () {
@@ -137,95 +137,71 @@ describe('cordova/platform/addHelper', function () {
         });
 
         describe('platform spec inference', function () {
-            it('should retrieve platform details from directories-specified-as-platforms using getPlatformDetailsFromDir', function (done) {
+            it('should retrieve platform details from directories-specified-as-platforms using getPlatformDetailsFromDir', function () {
                 cordova_util.isDirectory.and.returnValue(true);
                 var directory_to_platform = '/path/to/cordova-atari';
-                platform_addHelper('add', hooks_mock, projectRoot, [directory_to_platform], {restoring: true}).then(function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, [directory_to_platform], {restoring: true}).then(function () {
                     expect(platform_module.getPlatformDetailsFromDir).toHaveBeenCalledWith(directory_to_platform, null);
                     expect(platform_addHelper.downloadPlatform).not.toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
 
-            it('should retrieve platform details from URLs-specified-as-platforms using downloadPlatform', function (done) {
+            it('should retrieve platform details from URLs-specified-as-platforms using downloadPlatform', function () {
                 cordova_util.isUrl.and.returnValue(true);
                 var url_to_platform = 'http://github.com/apache/cordova-atari';
-                platform_addHelper('add', hooks_mock, projectRoot, [url_to_platform], {restoring: true}).then(function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, [url_to_platform], {restoring: true}).then(function () {
                     expect(platform_addHelper.downloadPlatform).toHaveBeenCalledWith(projectRoot, null, url_to_platform, jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
 
-            it('should use spec from config.xml if package.json does not contain dependency for platform', function (done) {
+            it('should use spec from config.xml if package.json does not contain dependency for platform', function () {
                 package_json_mock.dependencies = {};
                 cordova_util.requireNoCache.and.returnValue(package_json_mock);
                 fs.existsSync.and.callFake(function (filePath) {
                     return path.basename(filePath) === 'package.json';
                 });
 
-                platform_addHelper('add', hooks_mock, projectRoot, ['windows'], {restoring: true}).then(function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, ['windows'], {restoring: true}).then(function () {
                     expect(platform_addHelper.getVersionFromConfigFile).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
 
-            it('should attempt to retrieve from config.xml if exists and package.json does not', function (done) {
-                platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {restoring: true}).then(function () {
+            it('should attempt to retrieve from config.xml if exists and package.json does not', function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {restoring: true}).then(function () {
                     expect(platform_addHelper.getVersionFromConfigFile).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
 
-            it('should fall back to using pinned version if both package.json and config.xml do not specify it', function (done) {
-                platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {restoring: true}).then(function () {
+            it('should fall back to using pinned version if both package.json and config.xml do not specify it', function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {restoring: true}).then(function () {
                     expect(events.emit).toHaveBeenCalledWith('verbose', 'Grabbing pinned version.');
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
 
-            it('should invoke fetch if provided as an option and spec is a directory', function (done) {
+            it('should invoke fetch if provided as an option and spec is a directory', function () {
                 cordova_util.isDirectory.and.returnValue(projectRoot);
                 cordova_util.fixRelativePath.and.returnValue(projectRoot);
                 spyOn(path, 'resolve').and.callThrough();
-                platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, fetch: true, restoring: true}).then(function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, fetch: true, restoring: true}).then(function () {
                     expect(fetch_mock).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
         });
 
         describe('platform api invocation', function () {
 
-            it('should invoke the createPlatform platform API method when adding a platform, providing destination location, parsed config file and platform detail options as arguments', function (done) {
-                platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, fetch: true, restoring: true}).then(function (result) {
+            it('should invoke the createPlatform platform API method when adding a platform, providing destination location, parsed config file and platform detail options as arguments', function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, fetch: true, restoring: true}).then(function (result) {
                     expect(platform_api_mock.createPlatform).toHaveBeenCalled();
-                }).fail(function (err) {
-                    fail('unexpected failure handler invoked!');
-                    console.error(err);
-                }).done(done);
+                });
             });
 
-            it('should invoke the update platform API method when updating a platform, providing destination location and plaform detail options as arguments', function (done) {
+            it('should invoke the update platform API method when updating a platform, providing destination location and plaform detail options as arguments', function () {
                 cordova_util.isDirectory.and.returnValue(true);
                 fs.existsSync.and.returnValue(true);
-                platform_addHelper('update', hooks_mock, projectRoot, ['ios'], {restoring: true}).then(function (result) {
+                return platform_addHelper('update', hooks_mock, projectRoot, ['ios'], {restoring: true}).then(function (result) {
                     expect(platform_api_mock.updatePlatform).toHaveBeenCalled();
-                }).fail(function (err) {
-                    fail('unexpected failure handler invoked!');
-                    console.error(err);
-                }).done(done);
+                });
             });
         });
 
@@ -233,38 +209,29 @@ describe('cordova/platform/addHelper', function () {
 
             describe('when the restoring option is not provided', function () {
                 // test is commented out b/c preparePlatforms can't be spied on as it is dynamically required due to circular references.
-                xit('should invoke preparePlatforms twice (?!?), once before installPluginsForNewPlatforms and once after... ?!', function (done) {
-                    platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {save: true, fetch: true}).then(function (result) {
+                xit('should invoke preparePlatforms twice (?!?), once before installPluginsForNewPlatforms and once after... ?!', function () {
+                    return platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {save: true, fetch: true}).then(function (result) {
                         expect(prepare.preparePlatforms).toHaveBeenCalledWith([ 'atari' ], '/some/path', Object({ searchpath: undefined }));
-                    }).fail(function (err) {
-                        fail('unexpected failure handler invoked!');
-                        console.error(err);
-                    }).done(done);
+                    });
                 });
             });
 
-            it('should invoke the installPluginsForNewPlatforms method in the platform-add case', function (done) {
-                platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {save: true, fetch: true, restoring: true}).then(function (result) {
+            it('should invoke the installPluginsForNewPlatforms method in the platform-add case', function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {save: true, fetch: true, restoring: true}).then(function (result) {
                     expect(platform_addHelper.installPluginsForNewPlatform).toHaveBeenCalled();
-                }).fail(function (err) {
-                    fail('unexpected failure handler invoked!');
-                    console.error(err);
-                }).done(done);
+                });
             });
 
-            it('should write out the version of platform just added/updated to config.xml if the save option is provided', function (done) {
-                platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, restoring: true}).then(function (result) {
+            it('should write out the version of platform just added/updated to config.xml if the save option is provided', function () {
+                return platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, restoring: true}).then(function (result) {
                     expect(cfg_parser_mock.prototype.removeEngine).toHaveBeenCalled();
                     expect(cfg_parser_mock.prototype.addEngine).toHaveBeenCalled();
                     expect(cfg_parser_mock.prototype.write).toHaveBeenCalled();
-                }).fail(function (err) {
-                    fail('unexpected failure handler invoked!');
-                    console.error(err);
-                }).done(done);
+                });
             });
 
             describe('if the project contains a package.json', function () {
-                it('should write out the platform just added/updated to the cordova.platforms property of package.json', function (done) {
+                it('should write out the platform just added/updated to the cordova.platforms property of package.json', function () {
                     fs.readFileSync.and.returnValue('file');
                     fs.existsSync.and.callFake(function (filePath) {
                         if (path.basename(filePath) === 'package.json') {
@@ -275,15 +242,12 @@ describe('cordova/platform/addHelper', function () {
                     });
                     package_json_mock.cordova = {'platforms': ['ios']};
                     cordova_util.requireNoCache.and.returnValue(package_json_mock);
-                    platform_addHelper('add', hooks_mock, projectRoot, ['android'], {save: true, restoring: true}).then(function (result) {
+                    return platform_addHelper('add', hooks_mock, projectRoot, ['android'], {save: true, restoring: true}).then(function (result) {
                         expect(fs.writeFileSync).toHaveBeenCalled();
-                    }).fail(function (err) {
-                        fail('unexpected failure handler invoked!');
-                        console.error(err);
-                    }).done(done);
+                    });
                 });
 
-                it('should use pkgJson version devDependencies, if dependencies are undefined', function (done) {
+                it('should use pkgJson version devDependencies, if dependencies are undefined', function () {
                     package_json_mock.dependencies = undefined;
                     package_json_mock.cordova = {'platforms': ['ios']};
                     package_json_mock.devDependencies['ios'] = {};
@@ -292,33 +256,24 @@ describe('cordova/platform/addHelper', function () {
                         return path.basename(filePath) === 'package.json';
                     });
                     fs.readFileSync.and.returnValue('{}');
-                    platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, restoring: true}).then(function () {
+                    return platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, restoring: true}).then(function () {
                         expect(platform_addHelper.getVersionFromConfigFile).not.toHaveBeenCalled();
                         expect(fs.writeFileSync).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        fail('fail handler unexpectedly invoked');
-                        console.error(e);
-                    }).done(done);
+                    });
                 });
 
-                it('should only write the package.json file if it was modified', function (done) {
+                it('should only write the package.json file if it was modified', function () {
                     package_json_mock.cordova = {'platforms': ['ios']};
                     cordova_util.requireNoCache.and.returnValue(package_json_mock);
-                    platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, restoring: true}).then(function (result) {
+                    return platform_addHelper('add', hooks_mock, projectRoot, ['ios'], {save: true, restoring: true}).then(function (result) {
                         expect(fs.writeFileSync).not.toHaveBeenCalled();
-                    }).fail(function (err) {
-                        fail('unexpected failure handler invoked!');
-                        console.error(err);
-                    }).done(done);
+                    });
                 });
 
-                it('should file the after_platform_* hook', function (done) {
-                    platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {save: true, restoring: true}).then(function (result) {
+                it('should file the after_platform_* hook', function () {
+                    return platform_addHelper('add', hooks_mock, projectRoot, ['atari'], {save: true, restoring: true}).then(function (result) {
                         expect(hooks_mock.fire).toHaveBeenCalledWith('before_platform_add', Object({ save: true, restoring: true, searchpath: undefined }));
-                    }).fail(function (err) {
-                        fail('unexpected failure handler invoked!');
-                        console.error(err);
-                    }).done(done);
+                    });
                 });
             });
         });
@@ -329,31 +284,27 @@ describe('cordova/platform/addHelper', function () {
             platform_addHelper.downloadPlatform.and.callThrough();
         });
         describe('errors', function () {
-            it('should reject the promise should fetch fail', function (done) {
+            it('should reject the promise should fetch fail', function () {
                 fetch_mock.and.returnValue(Q.reject('fetch has failed, rejecting promise'));
-                platform_addHelper.downloadPlatform(projectRoot, 'android', '67', {fetch: true}).then(function () {
+                return platform_addHelper.downloadPlatform(projectRoot, 'android', '67', {fetch: true}).then(function () {
                     fail('success handler unexpectedly invoked');
-                }).fail(function (e) {
+                }, function (e) {
                     expect(e.message).toContain('fetch has failed, rejecting promise');
-                }).done(done);
+                });
             });
         });
         describe('happy path', function () {
-            it('should invoke cordova-fetch if fetch was provided as an option', function (done) {
+            it('should invoke cordova-fetch if fetch was provided as an option', function () {
                 fetch_mock.and.returnValue(true);
-                platform_addHelper.downloadPlatform(projectRoot, 'android', '6.0.0', {fetch: true}).then(function () {
+                return platform_addHelper.downloadPlatform(projectRoot, 'android', '6.0.0', {fetch: true}).then(function () {
                     expect(fetch_mock).toHaveBeenCalledWith('cordova-android@6.0.0', projectRoot, Object({ fetch: true }));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                }).done(done);
+                });
             });
-            it('should pass along a libDir argument to getPlatformDetailsFromDir on a successful platform download', function (done) {
+            it('should pass along a libDir argument to getPlatformDetailsFromDir on a successful platform download', function () {
                 cordova_util.isUrl.and.returnValue(true);
-                platform_addHelper.downloadPlatform(projectRoot, 'android', 'https://github.com/apache/cordova-android', {save: true}).then(function () {
+                return platform_addHelper.downloadPlatform(projectRoot, 'android', 'https://github.com/apache/cordova-android', {save: true}).then(function () {
                     expect(require('../../../src/cordova/platform/index').getPlatformDetailsFromDir).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                }).done(done);
+                });
             }, 60000);
         });
     });
@@ -364,34 +315,28 @@ describe('cordova/platform/addHelper', function () {
             platform_addHelper.installPluginsForNewPlatform.and.callThrough();
         });
 
-        it('should immediately return if there are no plugins to install into the platform', function (done) {
-            platform_addHelper.installPluginsForNewPlatform('android', projectRoot).then(function () {
+        it('should immediately return if there are no plugins to install into the platform', function () {
+            return platform_addHelper.installPluginsForNewPlatform('android', projectRoot).then(function () {
                 expect(plugman.install).not.toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-            }).done(done);
+            });
         });
 
-        it('should invoke plugman.install, giving correct platform, plugin and other arguments', function (done) {
+        it('should invoke plugman.install, giving correct platform, plugin and other arguments', function () {
             spyOn(cordova_util, 'findPlugins').and.returnValue(['cordova-plugin-whitelist']);
             fetch_metadata.get_fetch_metadata.and.returnValue({ });
-            platform_addHelper.installPluginsForNewPlatform('browser', projectRoot, {save: true, fetch: true}).then(function () {
+            return platform_addHelper.installPluginsForNewPlatform('browser', projectRoot, {save: true, fetch: true}).then(function () {
                 expect(plugman.install).toHaveBeenCalled();
                 expect(events.emit).toHaveBeenCalledWith('verbose', 'Installing plugin "cordova-plugin-whitelist" following successful platform add of browser');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-            }).done(done);
+            });
         });
 
-        it('should include any plugin variables as options when invoking plugman install', function (done) {
+        it('should include any plugin variables as options when invoking plugman install', function () {
             spyOn(cordova_util, 'findPlugins').and.returnValue(['cordova-plugin-camera']);
             fetch_metadata.get_fetch_metadata.and.returnValue({ source: {}, variables: {} });
-            platform_addHelper.installPluginsForNewPlatform('browser', projectRoot, {save: true, fetch: true}).then(function () {
+            return platform_addHelper.installPluginsForNewPlatform('browser', projectRoot, {save: true, fetch: true}).then(function () {
                 expect(plugman.install).toHaveBeenCalled();
                 expect(events.emit).toHaveBeenCalledWith('verbose', 'Found variables for "cordova-plugin-camera". Processing as cli_variables.');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-            }).done(done);
+            });
         });
     });
 });
diff --git a/spec/cordova/platform/check.spec.js b/spec/cordova/platform/check.spec.js
index bb4456d..51e844f 100644
--- a/spec/cordova/platform/check.spec.js
+++ b/spec/cordova/platform/check.spec.js
@@ -34,50 +34,38 @@ describe('cordova/platform/check', function () {
         spyOn(cordova_util, 'listPlatforms');
     });
 
-    it('If no results, platforms cannot be updated', function (done) {
+    it('If no results, platforms cannot be updated', function () {
         cordova_util.listPlatforms.and.callThrough();
-        platform_check(hooks_mock, projectRoot).then(function () {
+        return platform_check(hooks_mock, projectRoot).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/No platforms can be updated/));
             expect(superspawn.spawn).toHaveBeenCalledWith('npm', ['--loglevel=silent', '--json', 'outdated', 'cordova-lib'], jasmine.any(Object));
             expect(shell.rm).toHaveBeenCalledWith('-rf', jasmine.any(String));
-        }).fail(function (err) {
-            fail('unexpected failure handler invoked!');
-            console.error(err);
-        }).done(done);
+        });
     });
 
-    it('Should warn if install failed', function (done) {
+    it('Should warn if install failed', function () {
         cordova_util.listPlatforms.and.returnValue(['ios']);
-        platform_check(hooks_mock, projectRoot).then(function () {
+        return platform_check(hooks_mock, projectRoot).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/current did not install/));
-        }).fail(function (err) {
-            fail('unexpected failure handler invoked!');
-            console.error(err);
-        }).done(done);
+        });
     });
 
-    it('Should warn if version-empty', function (done) {
+    it('Should warn if version-empty', function () {
         cordova_util.listPlatforms.and.returnValue(['ios']);
         spyOn(require('../../../src/cordova/platform/index'), 'add').and.returnValue(Q());
         superspawn.spawn.and.returnValue(Q());
-        platform_check(hooks_mock, projectRoot).then(function () {
+        return platform_check(hooks_mock, projectRoot).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/current version script failed to return a version/));
-        }).fail(function (err) {
-            fail('unexpected failure handler invoked!');
-            console.error(err);
-        }).done(done);
+        });
     });
 
-    it('Should warn if version-failed', function (done) {
+    it('Should warn if version-failed', function () {
         cordova_util.listPlatforms.and.returnValue(['ios']);
         spyOn(require('../../../src/cordova/platform/index'), 'add').and.returnValue(Q());
         spyOn(superspawn, 'maybeSpawn').and.returnValue(Q('version-failed'));
         spyOn(Q.defer(), 'resolve').and.returnValue('version-failed');
-        platform_check(hooks_mock, projectRoot).then(function () {
+        return platform_check(hooks_mock, projectRoot).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/current version script failed, and/));
-        }).fail(function (err) {
-            fail('unexpected failure handler invoked!');
-            console.error(err);
-        }).done(done);
+        });
     });
 });
diff --git a/spec/cordova/platform/getPlatformDetailsFromDir.spec.js b/spec/cordova/platform/getPlatformDetailsFromDir.spec.js
index c551f08..cad731c 100644
--- a/spec/cordova/platform/getPlatformDetailsFromDir.spec.js
+++ b/spec/cordova/platform/getPlatformDetailsFromDir.spec.js
@@ -17,12 +17,10 @@
 
 var path = require('path');
 var fs = require('fs');
-var Q = require('q');
 var rewire = require('rewire');
 var cordova_util = require('../../../src/cordova/util');
 var platform_getPlatformDetails = rewire('../../../src/cordova/platform/getPlatformDetailsFromDir');
 var events = require('cordova-common').events;
-var fail;
 
 describe('cordova/platform/getPlatformDetailsFromDir', function () {
     var package_json_mock;
@@ -31,26 +29,31 @@ describe('cordova/platform/getPlatformDetailsFromDir', function () {
     package_json_mock.version = '1.0.0';
 
     beforeEach(function () {
-        spyOn(Q, 'reject');
         spyOn(fs, 'existsSync');
         spyOn(cordova_util, 'requireNoCache');
         spyOn(events, 'emit');
     });
 
-    it('should throw if no config.xml or pkgJson', function (done) {
-        platform_getPlatformDetails('dir', ['ios']);
-        expect(Q.reject).toHaveBeenCalledWith(jasmine.stringMatching(/does not seem to contain a valid package.json or a valid Cordova platform/));
-        done();
+    it('should throw if no config.xml or pkgJson', function () {
+        return platform_getPlatformDetails('dir', ['ios'])
+            .then(function () {
+                fail('Expected promise to be rejected');
+            }, function (reason) {
+                expect(reason).toMatch(/does not seem to contain a valid package.json or a valid Cordova platform/);
+            });
     });
 
-    it('should throw if no platform is provided', function (done) {
+    it('should throw if no platform is provided', function () {
         cordova_util.requireNoCache.and.returnValue({});
-        platform_getPlatformDetails('dir');
-        expect(Q.reject).toHaveBeenCalledWith(jasmine.stringMatching(/does not seem to contain a Cordova platform:/));
-        done();
+        return platform_getPlatformDetails('dir')
+            .then(function () {
+                fail('Expected promise to be rejected');
+            }, function (reason) {
+                expect(reason).toMatch(/does not seem to contain a Cordova platform:/);
+            });
     });
 
-    it('should return a promise with platform and version', function (done) {
+    it('should return a promise with platform and version', function () {
         fs.existsSync.and.callFake(function (filePath) {
             if (path.basename(filePath) === 'package.json') {
                 return true;
@@ -59,20 +62,15 @@ describe('cordova/platform/getPlatformDetailsFromDir', function () {
             }
         });
         cordova_util.requireNoCache.and.returnValue(package_json_mock);
-        platform_getPlatformDetails('dir', ['cordova-android'])
+        return platform_getPlatformDetails('dir', ['cordova-android'])
             .then(function (result) {
                 expect(result.platform).toBe('io.cordova.hellocordova');
                 expect(result.version).toBe('1.0.0');
-                expect(Q.reject).not.toHaveBeenCalled();
-            }).fail(function (err) {
-                fail('unexpected failure handler invoked!');
-                console.error(err);
-            }).done(done);
+            });
     });
 
-    it('should remove the cordova- prefix from the platform name for known platforms', function (done) {
+    it('should remove the cordova- prefix from the platform name for known platforms', function () {
         expect(platform_getPlatformDetails.platformFromName('cordova-ios')).toBe('ios');
         expect(events.emit).toHaveBeenCalledWith('verbose', jasmine.stringMatching(/Removing "cordova-" prefix/));
-        done();
     });
 });
diff --git a/spec/cordova/platform/index.spec.js b/spec/cordova/platform/index.spec.js
index f15340a..8d15d22 100644
--- a/spec/cordova/platform/index.spec.js
+++ b/spec/cordova/platform/index.spec.js
@@ -37,21 +37,23 @@ describe('cordova/platform', function () {
     describe('main module function', function () {
         describe('error/warning conditions', function () {
             // TODO: what about other commands? update? save?
-            it('should require at least one platform for add and remove commands', function (done) {
+            it('should require at least one platform for add and remove commands', function () {
                 // targets = empty array
-                platform('add', []).then(function () {
-                    fail('should not succeed without targets');
-                }, function (err) {
-                    expect(err).toMatch(/You need to qualify.* with one or more platforms/gi);
-                }).then(function () {
-                    // targets = null
-                    return platform('remove', null);
-                })
+                return platform('add', [])
                     .then(function () {
                         fail('should not succeed without targets');
                     }, function (err) {
                         expect(err).toMatch(/You need to qualify.* with one or more platforms/gi);
-                    }).done(done);
+                    })
+                    .then(function () {
+                        // targets = null
+                        return platform('remove', null);
+                    })
+                    .then(function () {
+                        fail('should not succeed without targets');
+                    }, function (err) {
+                        expect(err).toMatch(/You need to qualify.* with one or more platforms/gi);
+                    });
             });
         });
         describe('handling of targets parameter', function () {
@@ -59,112 +61,79 @@ describe('cordova/platform', function () {
             beforeEach(function () {
                 spyOn(platform, cmd).and.returnValue(true);
             });
-            it('should be able to handle an array of platform targets', function (done) {
+            it('should be able to handle an array of platform targets', function () {
                 var targets = ['nokia brick', 'HAM radio', 'nintendo wii'];
-                platform(cmd, targets)
+                return platform(cmd, targets)
                     .then(function () {
                         expect(platform[cmd]).toHaveBeenCalledWith(jasmine.any(Object), projectRoot, targets, jasmine.any(Object));
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
-                    }).done(done);
+                    });
             });
-            it('should be able to handle a single platform target string', function (done) {
+            it('should be able to handle a single platform target string', function () {
                 var target = 'motorola razr';
-                platform(cmd, target)
+                return platform(cmd, target)
                     .then(function () {
                         expect(platform[cmd]).toHaveBeenCalledWith(jasmine.any(Object), projectRoot, [target], jasmine.any(Object));
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
-                    }).done(done);
+                    });
             });
         });
         describe('happy path (success conditions)', function () {
-            it('should direct `add` commands to the `add` method/module', function (done) {
+            it('should direct `add` commands to the `add` method/module', function () {
                 spyOn(platform, 'add').and.returnValue(true);
-                platform('add', ['android'])
+                return platform('add', ['android'])
                     .then(function () {
                         expect(platform.add).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
-                    }).done(done);
+                    });
             });
-            it('should direct `remove` + `rm` commands to the `remove` method/module', function (done) {
+            it('should direct `remove` + `rm` commands to the `remove` method/module', function () {
                 spyOn(platform, 'remove').and.returnValue(true);
-                platform('remove', ['android'])
+                return platform('remove', ['android'])
                     .then(function () {
                         expect(platform.remove).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
                     }).then(function () {
                         platform.remove.calls.reset(); // reset spy counter
                         return platform('rm', ['android']);
                     }).then(function () {
                         expect(platform.remove).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
-                    }).done(done);
+                    });
             });
-            it('should direct `update` + `up` commands to the `update` method/module', function (done) {
+            it('should direct `update` + `up` commands to the `update` method/module', function () {
                 spyOn(platform, 'update').and.returnValue(true);
-                platform('update', ['android'])
+                return platform('update', ['android'])
                     .then(function () {
                         expect(platform.update).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
                     }).then(function () {
                         platform.update.calls.reset(); // reset spy counter
                         return platform('up', ['android']);
                     }).then(function () {
                         expect(platform.update).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
-                    }).done(done);
+                    });
             });
-            it('should direct `check` commands to the `check` method/module', function (done) {
+            it('should direct `check` commands to the `check` method/module', function () {
                 spyOn(platform, 'check').and.returnValue(true);
-                platform('check', ['android'])
+                return platform('check', ['android'])
                     .then(function () {
                         expect(platform.check).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
-                    }).done(done);
+                    });
             });
-            it('should direct `list`, all other commands and no command at all to the `list` method/module', function (done) {
+            it('should direct `list`, all other commands and no command at all to the `list` method/module', function () {
                 spyOn(platform, 'list').and.returnValue(true);
                 // test the `list` command directly
-                platform('list')
+                return platform('list')
                     .then(function () {
                         expect(platform.list).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
                     }).then(function () {
                         platform.list.calls.reset(); // reset spy counter
                         // test the list catch-all
                         return platform('please give me the list command');
                     }).then(function () {
                         expect(platform.list).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
                     }).then(function () {
                         platform.list.calls.reset(); // reset spy counter
                         // test the lack of providing an argument.
                         return platform();
                     }).then(function () {
                         expect(platform.list).toHaveBeenCalled();
-                    }).fail(function (e) {
-                        expect(e).toBeUndefined();
-                        fail('did not expect fail handler to be invoked');
-                    }).done(done);
+                    });
             });
         });
     });
diff --git a/spec/cordova/platform/list.spec.js b/spec/cordova/platform/list.spec.js
index c704fa4..4e561e5 100644
--- a/spec/cordova/platform/list.spec.js
+++ b/spec/cordova/platform/list.spec.js
@@ -19,7 +19,6 @@ var events = require('cordova-common').events;
 var Q = require('q');
 var platform_list = require('../../../src/cordova/platform/list');
 var cordova_util = require('../../../src/cordova/util');
-var fail;
 
 describe('cordova/platform/list', function () {
     var hooks_mock;
@@ -38,29 +37,22 @@ describe('cordova/platform/list', function () {
         expect(hooks_mock.fire).toHaveBeenCalledWith('before_platform_ls', Object({ save: true }));
     });
 
-    it('should fire the after_platform_ls hook', function (done) {
-        platform_list(hooks_mock, projectRoot, {save: true})
+    it('should fire the after_platform_ls hook', function () {
+        return platform_list(hooks_mock, projectRoot, {save: true})
             .then(function (result) {
                 expect(hooks_mock.fire).toHaveBeenCalledWith('after_platform_ls', Object({ save: true }));
-            }).fail(function (err) {
-                fail('unexpected failure handler invoked!');
-                console.error(err);
-            }).done(done);
+            });
     });
 
-    it('should print results of available platforms', function (done) {
-        platform_list(hooks_mock, projectRoot, {save: true})
+    it('should print results of available platforms', function () {
+        return platform_list(hooks_mock, projectRoot, {save: true})
             .then(function (result) {
                 expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/Installed platforms:/));
-            }).fail(function (err) {
-                fail('unexpected failure handler invoked!');
-                console.error(err);
-            }).done(done);
+            });
     });
 
-    it('should return platform list', function (done) {
+    it('should return platform list', function () {
         var platformList = ['android', 'ios'];
         expect(platform_list.addDeprecatedInformationToPlatforms(platformList).toString()).toBe('android,ios');
-        done();
     });
 });
diff --git a/spec/cordova/platform/platform.spec.js b/spec/cordova/platform/platform.spec.js
index 4456537..9245773 100644
--- a/spec/cordova/platform/platform.spec.js
+++ b/spec/cordova/platform/platform.spec.js
@@ -27,6 +27,8 @@ describe('cordova.platform', function () {
         var hooksRunnerMock;
         var projectRoot = os.tmpdir();
 
+        const NO_PLATFORMS_MSG = 'No platform specified. Please specify a platform to add. See `cordova platform list`.';
+
         beforeEach(function () {
             opts = {};
             hooksRunnerMock = {
@@ -36,26 +38,33 @@ describe('cordova.platform', function () {
             };
         });
 
-        it('Test 004 : throws if the target list is empty', function (done) {
+        it('Test 004 : throws if the target list is empty', function () {
             var targets = [];
-            platform.add(hooksRunnerMock, projectRoot, targets, opts).fail(function (error) {
-                expect(error.message).toBe('No platform specified. Please specify a platform to add. See `cordova platform list`.');
-                done();
+            return platform.add(hooksRunnerMock, projectRoot, targets, opts).then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toEqual(jasmine.any(Error));
+                expect(err.message).toBe(NO_PLATFORMS_MSG);
             });
         });
 
-        it('Test 005 : throws if the target list is undefined or null', function (done) {
-            // case 1 : target list undefined
+        it('Test 005 : throws if the target list is undefined', function () {
             var targets; // = undefined;
-            platform.add(hooksRunnerMock, projectRoot, targets, opts).fail(function (error) {
-                expect(error.message).toBe('No platform specified. Please specify a platform to add. See `cordova platform list`.');
+            return platform.add(hooksRunnerMock, projectRoot, targets, opts).then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toEqual(jasmine.any(Error));
+                expect(err.message).toBe(NO_PLATFORMS_MSG);
             });
+        });
 
-            // case 2 : target list null
-            targets = null;
-            platform.add(hooksRunnerMock, projectRoot, targets, opts).fail(function (error) {
-                expect(error.message).toBe('No platform specified. Please specify a platform to add. See `cordova platform list`.');
-                done();
+        it('Test 006 : throws if the target list is null', function () {
+            const targets = null;
+            return platform.add(hooksRunnerMock, projectRoot, targets, opts).then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toEqual(jasmine.any(Error));
+                expect(err.message).toBe(NO_PLATFORMS_MSG);
             });
         });
     });
diff --git a/spec/cordova/platform/remove.spec.js b/spec/cordova/platform/remove.spec.js
index 9f42fe8..d555085 100644
--- a/spec/cordova/platform/remove.spec.js
+++ b/spec/cordova/platform/remove.spec.js
@@ -54,12 +54,12 @@ describe('cordova/platform/remove', function () {
         hooksRunnerRevert();
     });
     describe('error/warning conditions', function () {
-        it('should require specifying at least one platform', function (done) {
-            platform_remove('remove', hooks_mock).then(function () {
+        it('should require specifying at least one platform', function () {
+            return platform_remove('remove', hooks_mock).then(function () {
                 fail('remove success handler unexpectedly invoked');
-            }).fail(function (e) {
+            }, function (e) {
                 expect(e.message).toContain('No platform(s) specified.');
-            }).done(done);
+            });
         });
     });
     describe('happy path (success conditions)', function () {
@@ -68,30 +68,24 @@ describe('cordova/platform/remove', function () {
             expect(hooks_mock.fire).toHaveBeenCalledWith('before_platform_rm', jasmine.any(Object));
         });
 
-        it('should remove <platform>.json file from plugins directory', function (done) {
-            platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
+        it('should remove <platform>.json file from plugins directory', function () {
+            return platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
                 .then(function () {
                     expect(cordova_util.removePlatformPluginsJson).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
         });
 
-        it('should remove from config.xml and platforms.json', function (done) {
-            platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
+        it('should remove from config.xml and platforms.json', function () {
+            return platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
                 .then(function () {
                     expect(cordova_util.removePlatformPluginsJson).toHaveBeenCalled();
                     expect(cfg_parser_mock.prototype.write).toHaveBeenCalled();
                     expect(events.emit).toHaveBeenCalledWith('log', jasmine.stringMatching(/Removing platform atari from config.xml file/));
                     expect(events.emit).toHaveBeenCalledWith('verbose', jasmine.stringMatching(/Removing platform atari from platforms.json file/));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
         });
 
-        it('should remove from package.json', function (done) {
+        it('should remove from package.json', function () {
             package_json_mock.cordova = {'platforms': ['atari']};
             cordova_util.requireNoCache.and.returnValue(package_json_mock);
             spyOn(fs, 'readFileSync').and.returnValue('file');
@@ -102,36 +96,27 @@ describe('cordova/platform/remove', function () {
                     return false;
                 }
             });
-            platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
+            return platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
                 .then(function () {
                     expect(fs.writeFileSync).toHaveBeenCalled();
                     expect(events.emit).toHaveBeenCalledWith('log', jasmine.stringMatching(/Removing atari from cordova.platforms array in package.json/));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
         });
 
-        it('fetch should be called', function (done) {
+        it('fetch should be called', function () {
             spyOn(promiseutil, 'Q_chainmap').and.returnValue(true);
-            platform_remove(hooks_mock, projectRoot, ['atari'], {fetch: true})
+            return platform_remove(hooks_mock, projectRoot, ['atari'], {fetch: true})
                 .then(function () {
                     expect(promiseutil.Q_chainmap).toHaveBeenCalled();
                     expect(hooks_mock.fire).toHaveBeenCalledWith('after_platform_rm', Object({ fetch: true }));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
         });
 
-        it('should file the after_platform_* hook', function (done) {
-            platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
+        it('should file the after_platform_* hook', function () {
+            return platform_remove(hooks_mock, projectRoot, ['atari'], {save: true})
                 .then(function (result) {
                     expect(hooks_mock.fire).toHaveBeenCalledWith('after_platform_rm', Object({ save: true }));
-                }).fail(function (err) {
-                    fail('unexpected failure handler invoked!');
-                    console.error(err);
-                }).done(done);
+                });
         });
     });
 });
diff --git a/spec/cordova/plugin/add.spec.js b/spec/cordova/plugin/add.spec.js
index eb07adc..818a55d 100644
--- a/spec/cordova/plugin/add.spec.js
+++ b/spec/cordova/plugin/add.spec.js
@@ -97,66 +97,56 @@ describe('cordova/plugin/add', function () {
             spyOn(config, 'read').and.returnValue({});
         });
         describe('error/warning conditions', function () {
-            it('should error out if at least one plugin is not specified', function (done) {
-                add(projectRoot, hook_mock, {plugins: []}).then(function () {
-                    fail('success handler unexpectedly invoked');
-                }).fail(function (e) {
-                    expect(e.message).toContain('No plugin specified');
-                }).done(done);
-            });
-            it('should error out if any mandatory plugin variables are not provided', function (done) {
+            it('should error out if at least one plugin is not specified', function () {
+                return add(projectRoot, hook_mock, {plugins: []}).then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toContain('No plugin specified');
+                });
+            });
+            it('should error out if any mandatory plugin variables are not provided', function () {
                 plugin_info.getPreferences.and.returnValue({'some': undefined});
 
-                add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
-                    fail('success handler unexpectedly invoked');
-                }).fail(function (e) {
-                    expect(e.message).toContain('Variable(s) missing (use: --variable');
-                }).done(done);
+                return add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toContain('Variable(s) missing (use: --variable');
+                });
             });
         });
         describe('happy path', function () {
-            it('should fire the before_plugin_add hook', function (done) {
-                add(projectRoot, hook_mock, {plugins: ['https://github.com/apache/cordova-plugin-device'], save: true}).then(function () {
+            it('should fire the before_plugin_add hook', function () {
+                return add(projectRoot, hook_mock, {plugins: ['https://github.com/apache/cordova-plugin-device'], save: true}).then(function () {
                     expect(hook_mock.fire).toHaveBeenCalledWith('before_plugin_add', jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.log(e);
-                }).done(done);
+                });
             });
-            it('should determine where to fetch a plugin from using determinePluginTarget and invoke plugman.fetch with the resolved target', function (done) {
-                add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
+            it('should determine where to fetch a plugin from using determinePluginTarget and invoke plugman.fetch with the resolved target', function () {
+                return add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
                     expect(add.determinePluginTarget).toHaveBeenCalledWith(projectRoot, jasmine.any(Object), 'cordova-plugin-device', jasmine.any(Object));
                     expect(plugman.fetch).toHaveBeenCalledWith('cordova-plugin-device', path.join(projectRoot, 'plugins'), jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.log(e);
-                }).done(done);
+                });
             });
-            it('should retrieve any variables for the plugin from config.xml and add them as cli variables only when the variables were not already provided via options', function (done) {
+            it('should retrieve any variables for the plugin from config.xml and add them as cli variables only when the variables were not already provided via options', function () {
                 var cfg_plugin_variables = {'some': 'variable'};
                 Cfg_parser_mock.prototype.getPlugin.and.callFake(function (plugin_id) {
                     return {'variables': cfg_plugin_variables};
                 });
-                add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
+                return add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
                     // confirm cli_variables are undefind
                     expect(add.determinePluginTarget).toHaveBeenCalledWith(jasmine.anything(), jasmine.anything(), jasmine.anything(), jasmine.objectContaining({'variables': undefined}));
                     expect(plugman.install).toHaveBeenCalled();
                     // check that the plugin variables from config.xml got added to cli_variables
                     expect(plugman.install).toHaveBeenCalledWith(jasmine.anything(), jasmine.anything(), jasmine.anything(), jasmine.anything(), jasmine.objectContaining({'cli_variables': cfg_plugin_variables}));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.log(e);
-                }).done(done);
+                });
             });
-            it('should invoke plugman.install for each platform added to the project', function (done) {
-                add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
+            it('should invoke plugman.install for each platform added to the project', function () {
+                return add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
                     expect(plugman.install).toHaveBeenCalledWith('android', jasmine.any(String), jasmine.any(String), jasmine.any(String), jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.log(e);
-                }).done(done);
+                });
             });
-            it('should save plugin variable information to package.json file (if exists)', function (done) {
+            it('should save plugin variable information to package.json file (if exists)', function () {
                 var cli_plugin_variables = {'some': 'variable'};
 
                 fs.existsSync.and.callFake(function (file_path) {
@@ -168,21 +158,18 @@ describe('cordova/plugin/add', function () {
                 });
 
                 spyOn(fs, 'readFileSync').and.returnValue('file');
-                add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device'], cli_variables: cli_plugin_variables, save: 'true'}).then(function () {
+                return add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device'], cli_variables: cli_plugin_variables, save: 'true'}).then(function () {
                     expect(fs.writeFileSync).toHaveBeenCalledWith(jasmine.any(String), JSON.stringify({'cordova': {'plugins': {'cordova-plugin-device': cli_plugin_variables}}, 'dependencies': {}, 'devDependencies': {}}, null, 2), 'utf8');
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.log(e);
-                }).done(done);
+                });
             });
-            it('should overwrite plugin information in config.xml after a successful installation', function (done) {
+            it('should overwrite plugin information in config.xml after a successful installation', function () {
                 var cfg_plugin_variables = {'some': 'variable'};
                 var cli_plugin_variables = {'some': 'new_variable'};
                 Cfg_parser_mock.prototype.getPlugin.and.callFake(function (plugin_id) {
                     return {'variables': cfg_plugin_variables};
                 });
 
-                add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device'], cli_variables: cli_plugin_variables, save: 'true'}).then(function () {
+                return add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device'], cli_variables: cli_plugin_variables, save: 'true'}).then(function () {
                     // confirm cli_variables got passed through
                     expect(add.determinePluginTarget).toHaveBeenCalledWith(jasmine.anything(), jasmine.anything(), jasmine.anything(), jasmine.objectContaining({'variables': cli_plugin_variables}));
                     // check that the plugin variables from config.xml got added to cli_variables
@@ -190,22 +177,16 @@ describe('cordova/plugin/add', function () {
                     expect(Cfg_parser_mock.prototype.removePlugin).toHaveBeenCalledWith('cordova-plugin-device');
                     expect(Cfg_parser_mock.prototype.addPlugin).toHaveBeenCalledWith(jasmine.any(Object), cli_plugin_variables);
                     expect(Cfg_parser_mock.prototype.write).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.log(e);
-                }).done(done);
+                });
             });
             // can't test the following due to inline require of preparePlatforms
             xit('should invoke preparePlatforms if plugman.install returned a falsey value', function () {
                 plugman.install.and.returnValue(false);
             });
-            it('should fire after_plugin_add hook', function (done) {
-                add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
+            it('should fire after_plugin_add hook', function () {
+                return add(projectRoot, hook_mock, {plugins: ['cordova-plugin-device']}).then(function () {
                     expect(hook_mock.fire).toHaveBeenCalledWith('after_plugin_add', jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.log(e);
-                }).done(done);
+                });
             });
         });
     });
@@ -217,32 +198,23 @@ describe('cordova/plugin/add', function () {
         });
         afterEach(function () {
         });
-        it('should return the target directly if the target is pluginSpec-parseable', function (done) {
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device@1.0.0', {}).then(function (target) {
+        it('should return the target directly if the target is pluginSpec-parseable', function () {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device@1.0.0', {}).then(function (target) {
                 expect(target).toEqual('cordova-plugin-device@1.0.0');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should return the target directly if the target is a URL', function (done) {
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'https://github.com/apache/cordova-plugin-device.git', {}).then(function (target) {
+        it('should return the target directly if the target is a URL', function () {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'https://github.com/apache/cordova-plugin-device.git', {}).then(function (target) {
                 expect(target).toEqual('https://github.com/apache/cordova-plugin-device.git');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should return the target directly if the target is a directory', function (done) {
+        it('should return the target directly if the target is a directory', function () {
             cordova_util.isDirectory.and.returnValue(true);
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, '../some/dir/cordova-plugin-device', {}).then(function (target) {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, '../some/dir/cordova-plugin-device', {}).then(function (target) {
                 expect(target).toEqual('../some/dir/cordova-plugin-device');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should retrieve plugin version from package.json (if exists)', function (done) {
+        it('should retrieve plugin version from package.json (if exists)', function () {
             fs.existsSync.and.callFake(function (file_path) {
                 if (path.basename(file_path) === 'package.json') {
                     return true;
@@ -253,14 +225,11 @@ describe('cordova/plugin/add', function () {
 
             package_json_mock.dependencies['cordova-plugin-device'] = '^1.0.0';
 
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
                 expect(target).toEqual('cordova-plugin-device@^1.0.0');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should retrieve plugin version from package.json devDependencies (if exists)', function (done) {
+        it('should retrieve plugin version from package.json devDependencies (if exists)', function () {
             fs.existsSync.and.callFake(function (file_path) {
                 if (path.basename(file_path) === 'package.json') {
                     return true;
@@ -271,24 +240,18 @@ describe('cordova/plugin/add', function () {
 
             package_json_mock.devDependencies['cordova-plugin-device'] = '^1.0.0';
 
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
                 expect(target).toEqual('cordova-plugin-device@^1.0.0');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should retrieve plugin version from config.xml as a last resort', function (done) {
+        it('should retrieve plugin version from config.xml as a last resort', function () {
             add.getVersionFromConfigFile.and.returnValue('~1.0.0');
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
                 expect(add.getVersionFromConfigFile).toHaveBeenCalled();
                 expect(target).toEqual('cordova-plugin-device@~1.0.0');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should return plugin version retrieved from package.json or config.xml if it is a URL', function (done) {
+        it('should return plugin version retrieved from package.json or config.xml if it is a URL', function () {
             fs.existsSync.and.callFake(function (file_path) {
                 if (path.basename(file_path) === 'package.json') {
                     return true;
@@ -299,14 +262,11 @@ describe('cordova/plugin/add', function () {
 
             package_json_mock.dependencies['cordova-plugin-device'] = 'https://github.com/apache/cordova-plugin-device.git';
 
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
                 expect(target).toEqual('https://github.com/apache/cordova-plugin-device.git');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should return plugin version retrieved from package.json or config.xml if it is a directory', function (done) {
+        it('should return plugin version retrieved from package.json or config.xml if it is a directory', function () {
             fs.existsSync.and.callFake(function (file_path) {
                 if (path.basename(file_path) === 'package.json') {
                     return true;
@@ -322,14 +282,11 @@ describe('cordova/plugin/add', function () {
             });
             package_json_mock.dependencies['cordova-plugin-device'] = '../some/dir/cordova-plugin-device';
 
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {}).then(function (target) {
                 expect(target).toEqual('../some/dir/cordova-plugin-device');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
-        it('should return plugin version retrieved from package.json or config.xml if it has a scope', function (done) {
+        it('should return plugin version retrieved from package.json or config.xml if it has a scope', function () {
             fs.existsSync.and.callFake(function (file_path) {
                 if (path.basename(file_path) === 'package.json') {
                     return true;
@@ -340,94 +297,73 @@ describe('cordova/plugin/add', function () {
 
             package_json_mock.dependencies['@cordova/cordova-plugin-device'] = '^1.0.0';
 
-            add.determinePluginTarget(projectRoot, Cfg_parser_mock, '@cordova/cordova-plugin-device', {}).then(function (target) {
+            return add.determinePluginTarget(projectRoot, Cfg_parser_mock, '@cordova/cordova-plugin-device', {}).then(function (target) {
                 expect(target).toEqual('@cordova/cordova-plugin-device@^1.0.0');
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.log(e);
-            }).done(done);
+            });
         });
         describe('with no version inferred from config files or provided plugin target', function () {
             describe('when searchpath or noregistry flag is provided', function () {
-                it('should end up just returning the target passed in case of searchpath', function (done) {
-                    add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {'searchpath': 'some/path'})
+                it('should end up just returning the target passed in case of searchpath', function () {
+                    return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {'searchpath': 'some/path'})
                         .then(function (target) {
                             expect(target).toEqual('cordova-plugin-device');
                             expect(events.emit).toHaveBeenCalledWith('verbose', 'Not checking npm info for cordova-plugin-device because searchpath or noregistry flag was given');
-                        }).fail(function (e) {
-                            fail('fail handler unexpectedly invoked');
-                            console.log(e);
-                        }).done(done);
+                        });
                 });
-                it('should end up just returning the target passed in case of noregistry', function (done) {
-                    add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {'noregistry': true})
+                it('should end up just returning the target passed in case of noregistry', function () {
+                    return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {'noregistry': true})
                         .then(function (target) {
                             expect(target).toEqual('cordova-plugin-device');
                             expect(events.emit).toHaveBeenCalledWith('verbose', 'Not checking npm info for cordova-plugin-device because searchpath or noregistry flag was given');
-                        }).fail(function (e) {
-                            fail('fail handler unexpectedly invoked');
-                            console.log(e);
-                        }).done(done);
+                        });
                 });
             });
             describe('when registry/npm is to be used (neither searchpath nor noregistry flag is provided)', function () {
-                it('should retrieve plugin info via registry.info', function (done) {
-                    add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {})
+                it('should retrieve plugin info via registry.info', function () {
+                    return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {})
                         .then(function (target) {
                             expect(plugin_util.info).toHaveBeenCalledWith(['cordova-plugin-device']);
                             expect(events.emit).toHaveBeenCalledWith('verbose', 'Attempting to use npm info for cordova-plugin-device to choose a compatible release');
                             expect(target).toEqual('cordova-plugin-device');
-                        }).fail(function (e) {
-                            fail('fail handler unexpectedly invoked');
-                            console.log(e);
-                        }).done(done);
+                        });
                 });
-                it('should feed registry.info plugin information into getFetchVersion', function (done) {
+                it('should feed registry.info plugin information into getFetchVersion', function () {
                     plugin_util.info.and.returnValue(Q({'plugin': 'info'}));
-                    add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {})
+                    return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {})
                         .then(function (target) {
                             expect(plugin_util.info).toHaveBeenCalled();
                             expect(add.getFetchVersion).toHaveBeenCalledWith(jasmine.anything(), {'plugin': 'info'}, jasmine.anything());
                             expect(target).toEqual('cordova-plugin-device');
                             expect(events.emit).toHaveBeenCalledWith('verbose', 'Attempting to use npm info for cordova-plugin-device to choose a compatible release');
-                        }).fail(function (e) {
-                            fail('fail handler unexpectedly invoked');
-                            console.log(e);
-                        }).done(done);
+                        });
                 });
-                it('should return the target as plugin-id@fetched-version', function (done) {
+                it('should return the target as plugin-id@fetched-version', function () {
                     add.getFetchVersion.and.returnValue(Q('1.0.0'));
-                    add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {})
+                    return add.determinePluginTarget(projectRoot, Cfg_parser_mock, 'cordova-plugin-device', {})
                         .then(function (target) {
                             expect(plugin_util.info).toHaveBeenCalled();
                             expect(add.getFetchVersion).toHaveBeenCalled();
                             expect(target).toEqual('cordova-plugin-device@1.0.0');
                             expect(events.emit).toHaveBeenCalledWith('verbose', 'Attempting to use npm info for cordova-plugin-device to choose a compatible release');
-                        }).fail(function (e) {
-                            fail('fail handler unexpectedly invoked');
-                            console.log(e);
-                        }).done(done);
+                        });
                 });
             });
         });
     });
     describe('parseSource helper method', function () {
-        it('should return target when url is passed', function (done) {
+        it('should return target when url is passed', function () {
             expect(add.parseSource('https://github.com/apache/cordova-plugin-device', {})).toEqual('https://github.com/apache/cordova-plugin-device');
-            done();
         });
-        it('should return target when local path is passed', function (done) {
+        it('should return target when local path is passed', function () {
             fs.existsSync.and.returnValue(true);
             expect(add.parseSource('../cordova-plugin-device', {})).toEqual('../cordova-plugin-device');
-            done();
         });
-        it('should return null when target is not url or local path', function (done) {
+        it('should return null when target is not url or local path', function () {
             expect(add.parseSource('cordova-plugin-device', {})).toEqual(null);
-            done();
         });
     });
     describe('getVersionFromConfigFile helper method', function () {
-        it('should return spec', function (done) {
+        it('should return spec', function () {
             var fakePlugin = {};
             fakePlugin.name = '';
             fakePlugin.spec = '1.0.0';
@@ -436,7 +372,6 @@ describe('cordova/plugin/add', function () {
             Cfg_parser_mock.prototype.getPlugin.and.returnValue(fakePlugin);
             var new_cfg = new Cfg_parser_mock();
             expect(add.getVersionFromConfigFile('cordova-plugin-device', new_cfg)).toEqual('1.0.0');
-            done();
         });
     });
 
@@ -453,29 +388,23 @@ describe('cordova/plugin/add', function () {
                 spyOn(cordova_util, 'getInstalledPlatformsWithVersions').and.returnValue(Q({}));
                 spyOn(add, 'determinePluginVersionToFetch');
             });
-            it('should resolve with null if plugin info does not contain engines and engines.cordovaDependencies properties', function (done) {
-                add.getFetchVersion(projectRoot, pluginInfo, '7.0.0')
+            it('should resolve with null if plugin info does not contain engines and engines.cordovaDependencies properties', function () {
+                return add.getFetchVersion(projectRoot, pluginInfo, '7.0.0')
                     .then(function (value) {
                         expect(value).toBe(null);
-                    }).fail(function (e) {
-                        fail('fail handler unexpectedly invoked');
-                        console.log(e);
-                    }).done(done);
+                    });
             });
-            it('should retrieve installed plugins and installed platforms version and feed that information into determinePluginVersionToFetch', function (done) {
+            it('should retrieve installed plugins and installed platforms version and feed that information into determinePluginVersionToFetch', function () {
                 plugin_util.getInstalledPlugins.and.returnValue([{'id': 'cordova-plugin-camera', 'version': '2.0.0'}]);
                 cordova_util.getInstalledPlatformsWithVersions.and.returnValue(Q({'android': '6.0.0'}));
                 pluginInfo.engines = {};
                 pluginInfo.engines.cordovaDependencies = {'^1.0.0': {'cordova': '>7.0.0'}};
-                add.getFetchVersion(projectRoot, pluginInfo, '7.0.0')
+                return add.getFetchVersion(projectRoot, pluginInfo, '7.0.0')
                     .then(function () {
                         expect(plugin_util.getInstalledPlugins).toHaveBeenCalledWith(projectRoot);
                         expect(cordova_util.getInstalledPlatformsWithVersions).toHaveBeenCalledWith(projectRoot);
                         expect(add.determinePluginVersionToFetch).toHaveBeenCalledWith(pluginInfo, {'cordova-plugin-camera': '2.0.0'}, {'android': '6.0.0'}, '7.0.0');
-                    }).fail(function (e) {
-                        fail('fail handler unexpectedly invoked');
-                        console.log(e);
-                    }).done(done);
+                    });
             });
         });
         // TODO More work to be done here to replace plugin_fetch.spec.js
@@ -489,75 +418,63 @@ describe('cordova/plugin/add', function () {
                 spyOn(add, 'findVersion').and.returnValue(null);
                 spyOn(add, 'listUnmetRequirements');
             });
-            it('should return null if no valid semver versions exist and no upperbound constraints were placed', function (done) {
+            it('should return null if no valid semver versions exist and no upperbound constraints were placed', function () {
                 pluginInfo.engines = {};
                 pluginInfo.engines.cordovaDependencies = {'^1.0.0': {'cordova': '<7.0.0'}};
                 expect(add.determinePluginVersionToFetch(pluginInfo, {}, {}, '7.0.0')).toBe(null);
                 expect(events.emit).toHaveBeenCalledWith('verbose', jasmine.stringMatching(/Ignoring invalid version/));
-                done();
             });
-            it('should return null and fetching latest version of plugin', function (done) {
+            it('should return null and fetching latest version of plugin', function () {
                 add.getFailedRequirements.and.returnValue(['2.0.0']);
                 pluginInfo.engines = {};
                 pluginInfo.engines.cordovaDependencies = {'1.0.0': {'cordova': '<7.0.0'}, '<3.0.0': {'cordova': '>=7.0.0'}};
                 expect(add.determinePluginVersionToFetch(pluginInfo, {}, {}, '7.0.0')).toBe(null);
                 expect(events.emit).toHaveBeenCalledWith('warn', jasmine.stringMatching(/Current project does not satisfy/));
-                done();
             });
-            it('should return highest version of plugin available based on constraints', function (done) {
+            it('should return highest version of plugin available based on constraints', function () {
                 pluginInfo.engines = {};
                 pluginInfo.engines.cordovaDependencies = {'1.0.0': {'cordova': '<7.0.0'}, '<3.0.0': {'cordova': '>=7.0.0'}};
                 expect(add.determinePluginVersionToFetch(pluginInfo, {}, {}, '7.0.0')).toEqual('2.0.0');
-                done();
             });
         });
         describe('getFailedRequirements helper method', function () {
-            it('should remove prerelease version', function (done) {
+            it('should remove prerelease version', function () {
                 var semver = require('semver');
                 spyOn(semver, 'prerelease').and.returnValue('7.0.1');
                 spyOn(semver, 'inc').and.callThrough();
                 expect(add.getFailedRequirements({'cordova': '>=7.0.0'}, {}, {}, '7.0.0').length).toBe(0);
                 expect(semver.inc).toHaveBeenCalledWith('7.0.0', 'patch');
-                done();
             });
-            it('should return an empty array if no failed requirements', function (done) {
+            it('should return an empty array if no failed requirements', function () {
                 expect(add.getFailedRequirements({'cordova': '>=7.0.0'}, {}, {}, '7.0.0').length).toBe(0);
-                done();
             });
-            it('should return an empty array if invalid dependency constraint', function (done) {
+            it('should return an empty array if invalid dependency constraint', function () {
                 expect(add.getFailedRequirements({1: 'wrong'}, {}, {}, '7.0.0').length).toBe(0);
                 expect(events.emit).toHaveBeenCalledWith('verbose', jasmine.stringMatching(/Ignoring invalid plugin dependency constraint/));
-                done();
             });
-            it('should return an array with failed plugin requirements ', function (done) {
+            it('should return an array with failed plugin requirements ', function () {
                 expect(add.getFailedRequirements({'cordova-plugin-camera': '>1.0.0'}, {'cordova-plugin-camera': '1.0.0'}, {}, '7.0.0')).toEqual([{ dependency: 'cordova-plugin-camera', installed: '1.0.0', required: '>1.0.0' }]);
-                done();
             });
-            it('should return an array with failed cordova requirements ', function (done) {
+            it('should return an array with failed cordova requirements ', function () {
                 expect(add.getFailedRequirements({'cordova': '>=7.0.0'}, {}, {}, '6.5.0')).toEqual([{ dependency: 'cordova', installed: '6.5.0', required: '>=7.0.0' }]);
-                done();
             });
-            it('should return an array with failed platform requirements ', function (done) {
+            it('should return an array with failed platform requirements ', function () {
                 expect(add.getFailedRequirements({'cordova-android': '>=6.0.0'}, {}, {'android': '5.5.0'}, '7.0.0')).toEqual([{ dependency: 'cordova-android', installed: '5.5.0', required: '>=6.0.0' }]);
-                done();
             });
         });
         describe('listUnmetRequirements helper method', function () {
-            it('should emit warnings for failed requirements', function (done) {
+            it('should emit warnings for failed requirements', function () {
                 add.listUnmetRequirements('cordova-plugin-device', [{ dependency: 'cordova', installed: '6.5.0', required: '>=7.0.0' }]);
                 expect(events.emit).toHaveBeenCalledWith('warn', 'Unmet project requirements for latest version of cordova-plugin-device:');
                 expect(events.emit).toHaveBeenCalledWith('warn', '    cordova (6.5.0 in project, >=7.0.0 required)');
-                done();
             });
         });
         describe('findVersion helper method', function () {
-            it('should return null if version is not in array', function (done) {
+            it('should return null if version is not in array', function () {
                 expect(add.findVersion(['0.0.1', '1.0.0', '2.0.0'], '0.0.0')).toEqual(null);
-                done();
             });
-            it('should return the version if it is in the array', function (done) {
+            it('should return the version if it is in the array', function () {
                 expect(add.findVersion(['0.0.1', '1.0.0', '2.0.0'], '1.0.0')).toEqual('1.0.0');
-                done();
             });
         });
     });
diff --git a/spec/cordova/plugin/index.spec.js b/spec/cordova/plugin/index.spec.js
index b2be5b0..a32b556 100644
--- a/spec/cordova/plugin/index.spec.js
+++ b/spec/cordova/plugin/index.spec.js
@@ -36,12 +36,13 @@ describe('cordova/plugin', function () {
 
     describe('error conditions', function () {
         // TODO: what about search cmd?
-        it('should require at least one target for add and rm commands', function (done) {
-            plugin('add', null).then(function () {
-                fail('success handler unexpectedly invoked');
-            }).fail(function (e) {
-                expect(e.message).toContain('one or more plugins');
-            }).done(done);
+        it('should require at least one target for add and rm commands', function () {
+            return plugin('add', null).then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toEqual(jasmine.any(Error));
+                expect(err.message).toContain('one or more plugins');
+            });
         });
     });
 
@@ -51,107 +52,80 @@ describe('cordova/plugin', function () {
             spyOn(plugin, cmd).and.returnValue(true);
         });
 
-        it('should be able to handle an array of platform targets', function (done) {
+        it('should be able to handle an array of platform targets', function () {
             var targets = ['plugin1', 'plugin2', 'plugin3'];
-            plugin(cmd, targets)
+            return plugin(cmd, targets)
                 .then(function () {
                     expect(plugin[cmd]).toHaveBeenCalledWith(projectRoot, jasmine.any(Object), Object({ options: [ ], plugins: [ 'plugin1', 'plugin2', 'plugin3' ] }));
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
 
-        it('should be able to handle a single string as a target', function (done) {
+        it('should be able to handle a single string as a target', function () {
             var targets = 'plugin1';
-            plugin(cmd, targets)
+            return plugin(cmd, targets)
                 .then(function () {
                     expect(plugin[cmd]).toHaveBeenCalledWith(projectRoot, jasmine.any(Object), Object({ options: [ ], plugins: [ 'plugin1' ] }));
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
 
-        it('should transform targets that start with a dash into options', function (done) {
+        it('should transform targets that start with a dash into options', function () {
             var targets = '-plugin1';
-            plugin(cmd, targets)
+            return plugin(cmd, targets)
                 .then(function () {
                     expect(plugin[cmd]).toHaveBeenCalledWith(projectRoot, jasmine.any(Object), Object({ options: [ '-plugin1' ], plugins: [ ] }));
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
 
-        it('should also include targets into a plugins property on options', function (done) {
+        it('should also include targets into a plugins property on options', function () {
             var options = {save: true};
             var targets = 'plugin1';
-            plugin(cmd, targets, options)
+            return plugin(cmd, targets, options)
                 .then(function () {
                     expect(plugin[cmd]).toHaveBeenCalledWith(projectRoot, jasmine.any(Object), Object({ save: true, options: [ ], plugins: [ 'plugin1' ] }));
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
     });
 
     describe('happy path', function () {
 
-        it('should direct "add" command to the "add" submodule', function (done) {
+        it('should direct "add" command to the "add" submodule', function () {
             spyOn(plugin, 'add').and.returnValue(true);
-            plugin('add', ['cordova-plugin-splashscreen'])
+            return plugin('add', ['cordova-plugin-splashscreen'])
                 .then(function () {
                     expect(plugin.add).toHaveBeenCalled();
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
 
-        it('should direct "rm" and "remove" commands to the "remove" submodule', function (done) {
+        it('should direct "rm" and "remove" commands to the "remove" submodule', function () {
             spyOn(plugin, 'remove').and.returnValue(true);
-            plugin('remove', ['cordova-plugin-splashscreen'])
+            return plugin('remove', ['cordova-plugin-splashscreen'])
                 .then(function () {
                     expect(plugin.remove).toHaveBeenCalled();
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
 
-        it('should direct "search" command to the "search" submodule', function (done) {
+        it('should direct "search" command to the "search" submodule', function () {
             spyOn(plugin, 'search').and.returnValue(true);
-            plugin('search')
+            return plugin('search')
                 .then(function () {
                     expect(plugin.search).toHaveBeenCalled();
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
 
-        it('should direct "save" command to the "save" submodule', function (done) {
+        it('should direct "save" command to the "save" submodule', function () {
             spyOn(plugin, 'save').and.returnValue(true);
-            plugin('save')
+            return plugin('save')
                 .then(function () {
                     expect(plugin.save).toHaveBeenCalled();
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
 
-        it('should direct "list", all other commands and no command at all to the "list" submodule', function (done) {
+        it('should direct "list", all other commands and no command at all to the "list" submodule', function () {
             spyOn(plugin, 'list').and.returnValue(true);
-            plugin('list')
+            return plugin('list')
                 .then(function () {
                     expect(plugin.list).toHaveBeenCalled();
-                }).fail(function (e) {
-                    expect(e).toBeUndefined();
-                    fail('did not expect fail handler to be invoked');
-                }).done(done);
+                });
         });
     });
 });
diff --git a/spec/cordova/plugin/list.spec.js b/spec/cordova/plugin/list.spec.js
index 490dc61..eec3ab6 100644
--- a/spec/cordova/plugin/list.spec.js
+++ b/spec/cordova/plugin/list.spec.js
@@ -36,69 +36,48 @@ describe('cordova/plugin/list', function () {
         spyOn(plugin_util, 'getInstalledPlugins').and.returnValue(Q.resolve(fake_plugins_list));
         spyOn(events, 'emit');
     });
-    it('should fire the before_plugin_ls hook', function (done) {
+    it('should fire the before_plugin_ls hook', function () {
         var opts = {important: 'options'};
-        list(projectRoot, hook_mock, opts).then(function () {
+        return list(projectRoot, hook_mock, opts).then(function () {
             expect(hook_mock.fire).toHaveBeenCalledWith('before_plugin_ls', opts);
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
-    it('should emit a "no plugins added" result if there are no installed plugins', function (done) {
+    it('should emit a "no plugins added" result if there are no installed plugins', function () {
         plugin_util.getInstalledPlugins.and.returnValue([]);
-        list(projectRoot, hook_mock).then(function () {
+        return list(projectRoot, hook_mock).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/No plugins added/));
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
-    it('should warn if plugin list contains dependencies that are missing', function (done) {
+    it('should warn if plugin list contains dependencies that are missing', function () {
         var fake_plugins_list = [{id: 'VRPlugin', deps: '1'}];
         plugin_util.getInstalledPlugins.and.returnValue(Q.resolve(fake_plugins_list));
-        list(projectRoot, hook_mock).then(function () {
+        return list(projectRoot, hook_mock).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/WARNING, missing dependency/));
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
-    xit('should warn if plugin list contains a plugin dependency that does not have a version satisfied', function (done) {
+    xit('should warn if plugin list contains a plugin dependency that does not have a version satisfied', function () {
         spyOn(semver, 'satisfies').and.returnValue(false);
         var fake_plugins_list = [{id: 'VRPlugin', version: '1', deps: '1'}];
         plugin_util.getInstalledPlugins.and.returnValue(Q.resolve(fake_plugins_list));
-        list(projectRoot, hook_mock).then(function () {
+        return list(projectRoot, hook_mock).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching(/WARNING, broken dependency/));
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
-    it('should emit a result containing a description of plugins installed', function (done) {
-        list(projectRoot, hook_mock).then(function () {
+    it('should emit a result containing a description of plugins installed', function () {
+        return list(projectRoot, hook_mock).then(function () {
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching('VRPlugin 1.0.0'));
             expect(events.emit).toHaveBeenCalledWith('results', jasmine.stringMatching('MastodonSocialPlugin 2.0.0'));
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
-    it('should fire the after_plugin_ls hook', function (done) {
+    it('should fire the after_plugin_ls hook', function () {
         var opts = {important: 'options'};
-        list(projectRoot, hook_mock, opts).then(function () {
+        return list(projectRoot, hook_mock, opts).then(function () {
             expect(hook_mock.fire).toHaveBeenCalledWith('after_plugin_ls', opts);
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
-    it('should resolve the promise by returning an array of plugin ids installed', function (done) {
-        list(projectRoot, hook_mock).then(function (results) {
+    it('should resolve the promise by returning an array of plugin ids installed', function () {
+        return list(projectRoot, hook_mock).then(function (results) {
             expect(results).toEqual([ 'VRPlugin', 'MastodonSocialPlugin' ]);
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
 });
diff --git a/spec/cordova/plugin/remove.spec.js b/spec/cordova/plugin/remove.spec.js
index ec59b11..bb41ec1 100644
--- a/spec/cordova/plugin/remove.spec.js
+++ b/spec/cordova/plugin/remove.spec.js
@@ -72,71 +72,61 @@ describe('cordova/plugin/remove', function () {
     });
 
     describe('error/warning conditions', function () {
-        it('should require that a plugin be provided', function (done) {
-            remove(projectRoot, null).then(function () {
-                fail('success handler unexpectedly invoked');
-            }).fail(function (e) {
-                expect(e.message).toContain('No plugin specified');
-            }).done(done);
+        it('should require that a plugin be provided', function () {
+            return remove(projectRoot, null).then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toEqual(jasmine.any(Error));
+                expect(err.message).toContain('No plugin specified');
+            });
         });
 
-        it('should require that a provided plugin be installed in the current project', function (done) {
+        it('should require that a provided plugin be installed in the current project', function () {
             var opts = { plugins: [ undefined ] };
-            remove(projectRoot, 'plugin', hook_mock, opts).then(function () {
-                fail('success handler unexpectedly invoked');
-            }).fail(function (e) {
-                expect(e.message).toContain('is not present in the project');
-            }).done(done);
+            return remove(projectRoot, 'plugin', hook_mock, opts).then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toEqual(jasmine.any(Error));
+                expect(err.message).toContain('is not present in the project');
+            });
         });
     });
     describe('happy path', function () {
-        it('should fire the before_plugin_rm hook', function (done) {
+        it('should fire the before_plugin_rm hook', function () {
             var opts = { important: 'options', plugins: [] };
-            remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+            return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                 expect(hook_mock.fire).toHaveBeenCalledWith('before_plugin_rm', opts);
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
 
-        it('should call plugman.uninstall.uninstallPlatform for each platform installed in the project and for each provided plugin', function (done) {
+        it('should call plugman.uninstall.uninstallPlatform for each platform installed in the project and for each provided plugin', function () {
             spyOn(plugin_util, 'mergeVariables');
             remove.validatePluginId.and.returnValue('cordova-plugin-splashscreen');
             var opts = {important: 'options', plugins: ['cordova-plugin-splashscreen']};
-            remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+            return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                 expect(plugman.uninstall.uninstallPlatform).toHaveBeenCalled();
                 expect(events.emit).toHaveBeenCalledWith('verbose', jasmine.stringMatching('plugman.uninstall on plugin "cordova-plugin-splashscreen" for platform "ios"'));
                 expect(events.emit).toHaveBeenCalledWith('verbose', jasmine.stringMatching('plugman.uninstall on plugin "cordova-plugin-splashscreen" for platform "android"'));
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
 
-        it('should trigger a prepare if plugman.uninstall.uninstallPlatform returned something falsy', function (done) {
+        it('should trigger a prepare if plugman.uninstall.uninstallPlatform returned something falsy', function () {
             spyOn(plugin_util, 'mergeVariables');
             remove.validatePluginId.and.returnValue('cordova-plugin-splashscreen');
             plugman.uninstall.uninstallPlatform.and.returnValue(Q(false));
             var opts = {important: 'options', plugins: ['cordova-plugin-splashscreen']};
-            remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+            return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                 expect(plugman.uninstall.uninstallPlatform).toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
 
-        it('should call plugman.uninstall.uninstallPlugin once plugin has been uninstalled for each platform', function (done) {
+        it('should call plugman.uninstall.uninstallPlugin once plugin has been uninstalled for each platform', function () {
             spyOn(plugin_util, 'mergeVariables');
             remove.validatePluginId.and.returnValue('cordova-plugin-splashscreen');
             var opts = {important: 'options', plugins: ['cordova-plugin-splashscreen']};
-            remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+            return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                 expect(plugman.uninstall.uninstallPlugin).toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
 
         describe('when save option is provided or autosave config is on', function () {
@@ -149,60 +139,48 @@ describe('cordova/plugin/remove', function () {
                 spyOn(metadata, 'remove_fetch_metadata').and.returnValue(true);
             });
 
-            it('should remove provided plugins from config.xml', function (done) {
+            it('should remove provided plugins from config.xml', function () {
                 spyOn(cordova_util, 'requireNoCache').and.returnValue(true);
                 fs.existsSync.and.returnValue(true);
                 remove.validatePluginId.and.returnValue('cordova-plugin-splashscreen');
                 var opts = {important: 'options', plugins: ['cordova-plugin-splashscreen']};
-                remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+                return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                     expect(cfg_parser_mock.prototype.removePlugin).toHaveBeenCalled();
                     expect(cfg_parser_mock.prototype.write).toHaveBeenCalled();
                     expect(events.emit).toHaveBeenCalledWith('log', jasmine.stringMatching('Removing plugin cordova-plugin-splashscreen from config.xml file'));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
 
-            it('should remove provided plugins from package.json (if exists)', function (done) {
+            it('should remove provided plugins from package.json (if exists)', function () {
                 spyOn(fs, 'readFileSync').and.returnValue('file');
                 spyOn(cordova_util, 'requireNoCache').and.returnValue(package_json_mock);
                 remove.validatePluginId.and.returnValue('cordova-plugin-splashscreen');
                 fs.existsSync.and.returnValue(true);
                 var opts = {important: 'options', plugins: ['cordova-plugin-splashscreen']};
-                remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+                return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                     expect(fs.writeFileSync).toHaveBeenCalled();
                     expect(events.emit).toHaveBeenCalledWith('log', jasmine.stringMatching('Removing cordova-plugin-splashscreen from package.json'));
-                }).fail(function (e) {
-                    fail('fail handler unexpectedly invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
         });
 
-        it('should remove fetch metadata from fetch.json', function (done) {
+        it('should remove fetch metadata from fetch.json', function () {
             plugin_info_provider_mock.prototype.getPreferences.and.returnValue(true);
             spyOn(plugin_util, 'mergeVariables');
             spyOn(metadata, 'remove_fetch_metadata').and.callThrough();
             remove.validatePluginId.and.returnValue('cordova-plugin-splashscreen');
             var opts = {important: 'options', plugins: ['cordova-plugin-splashscreen']};
-            remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+            return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                 expect(metadata.remove_fetch_metadata).toHaveBeenCalled();
                 expect(events.emit).toHaveBeenCalledWith('verbose', jasmine.stringMatching('Removing plugin cordova-plugin-splashscreen from fetch.json'));
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
 
-        it('should fire the after_plugin_rm hook', function (done) {
+        it('should fire the after_plugin_rm hook', function () {
             var opts = {important: 'options', plugins: []};
-            remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
+            return remove(projectRoot, 'cordova-plugin-splashscreen', hook_mock, opts).then(function () {
                 expect(hook_mock.fire).toHaveBeenCalledWith('after_plugin_rm', opts);
-            }).fail(function (e) {
-                fail('fail handler unexpectedly invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
     });
 });
diff --git a/spec/cordova/plugin/save.spec.js b/spec/cordova/plugin/save.spec.js
index d51cf11..77d0870 100644
--- a/spec/cordova/plugin/save.spec.js
+++ b/spec/cordova/plugin/save.spec.js
@@ -50,29 +50,26 @@ describe('cordova/plugin/save', function () {
         plugin_info_provider_revert_mock();
     });
     describe('error conditions', function () {
-        it('should explode if there was an issue parsing or reading from fetch.json file', function (done) {
+        it('should explode if there was an issue parsing or reading from fetch.json file', function () {
             fs.readFileSync.and.callFake(function () {
                 throw new Error('massive explosions during file reading!');
             });
-            save(projectRoot).then(function () {
-                fail('unexpected success handler invoked');
-            }).fail(function (e) {
-                expect(e).toContain('massive explosions');
-            }).done(done);
+            return save(projectRoot).then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toContain('massive explosions');
+            });
         });
     });
     describe('happy path', function () {
-        it('check that existing plugins are getting removed', function (done) {
-            save(projectRoot).then(function () {
+        it('check that existing plugins are getting removed', function () {
+            return save(projectRoot).then(function () {
                 expect(cfg_parser_mock.prototype.removePlugin).toHaveBeenCalledWith('VRPlugin');
                 expect(cfg_parser_mock.prototype.removePlugin).toHaveBeenCalledWith('MastodonSocialPlugin');
-            }).fail(function (e) {
-                expect(e).toBeUndefined();
-                fail('did not expect fail handler to be invoked');
-            }).done(done);
+            });
         });
 
-        it('plugins are being removed first and then only top level plugins are being restored', function (done) {
+        it('plugins are being removed first and then only top level plugins are being restored', function () {
             var fake_fetch_json =
                 {'VRPlugin': {'source': {
                     'type': 'registry',
@@ -87,19 +84,16 @@ describe('cordova/plugin/save', function () {
                 'is_top_level': false }};
 
             fs.readFileSync.and.returnValue(JSON.stringify(fake_fetch_json));
-            save(projectRoot).then(function () {
+            return save(projectRoot).then(function () {
                 expect(cfg_parser_mock.prototype.removePlugin).toHaveBeenCalledWith('VRPlugin');
                 expect(cfg_parser_mock.prototype.removePlugin).toHaveBeenCalledWith('MastodonSocialPlugin');
                 expect(cfg_parser_mock.prototype.addPlugin).toHaveBeenCalledWith(Object({ name: 'VRPlugin' }), [ ]);
                 expect(cfg_parser_mock.prototype.addPlugin).not.toHaveBeenCalledWith(Object({ name: 'MastodonSocialPlugin' }), [ ]);
                 expect(cfg_parser_mock.prototype.write).toHaveBeenCalled();
-            }).fail(function (e) {
-                expect(e).toBeUndefined();
-                fail('did not expect fail handler to be invoked');
-            }).done(done);
+            });
         });
 
-        it('should write individual plugin specs to config.xml', function (done) {
+        it('should write individual plugin specs to config.xml', function () {
             var fake_fetch_json =
                 {'VRPlugin': {'source': {
                     'type': 'registry',
@@ -108,16 +102,13 @@ describe('cordova/plugin/save', function () {
                 'is_top_level': true }};
             fs.readFileSync.and.returnValue(JSON.stringify(fake_fetch_json));
             spyOn(save, 'getSpec').and.returnValue('1.0.0');
-            save(projectRoot).then(function () {
+            return save(projectRoot).then(function () {
                 expect(cfg_parser_mock.prototype.addPlugin).toHaveBeenCalledWith(Object({ name: 'VRPlugin', spec: '1.0.0' }), jasmine.any(Object));
                 expect(cfg_parser_mock.prototype.write).toHaveBeenCalled();
-            }).fail(function (e) {
-                expect(e).toBeUndefined();
-                fail('did not expect fail handler to be invoked');
-            }).done(done);
+            });
         });
 
-        it('should write individual plugin variables to config.xml', function (done) {
+        it('should write individual plugin variables to config.xml', function () {
             var fake_fetch_json =
                 {'VRPlugin': {'source': {
                     'type': 'registry',
@@ -128,13 +119,10 @@ describe('cordova/plugin/save', function () {
                     'var 1': ' '
                 }}};
             fs.readFileSync.and.returnValue(JSON.stringify(fake_fetch_json));
-            save(projectRoot).then(function () {
+            return save(projectRoot).then(function () {
                 expect(cfg_parser_mock.prototype.addPlugin).toHaveBeenCalledWith(jasmine.any(Object), [ Object({ name: 'var 1', value: ' ' }) ]);
                 expect(cfg_parser_mock.prototype.write).toHaveBeenCalled();
-            }).fail(function (e) {
-                expect(e).toBeUndefined();
-                fail('did not expect fail handler to be invoked');
-            }).done(done);
+            });
         });
     });
     describe('getSpec helper method', function () {
diff --git a/spec/cordova/plugin/search.spec.js b/spec/cordova/plugin/search.spec.js
index 02eaaa1..6202a08 100644
--- a/spec/cordova/plugin/search.spec.js
+++ b/spec/cordova/plugin/search.spec.js
@@ -35,43 +35,31 @@ describe('cordova/plugin/search', function () {
     afterEach(function () {
         opener_revert_mock();
     });
-    it('should fire the before_plugin_search hook', function (done) {
+    it('should fire the before_plugin_search hook', function () {
         var opts = {important: 'options', plugins: []};
-        search(hook_mock, opts).then(function () {
+        return search(hook_mock, opts).then(function () {
             expect(hook_mock.fire).toHaveBeenCalledWith('before_plugin_search', opts);
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
 
-    it('should open a link to cordova.apache.org/plugins if no plugins are provided as parameter', function (done) {
+    it('should open a link to cordova.apache.org/plugins if no plugins are provided as parameter', function () {
         var opts = {important: 'options', plugins: []};
-        search(hook_mock, opts).then(function () {
+        return search(hook_mock, opts).then(function () {
             expect(opener_mock).toHaveBeenCalled();
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
 
-    it('should open a link to cordova.apache.org/plugins, providing the plugins passed in as a query-string parameter', function (done) {
+    it('should open a link to cordova.apache.org/plugins, providing the plugins passed in as a query-string parameter', function () {
         var opts = {important: 'options', plugins: ['cordova-plugin-camera', 'cordova-plugin-splashscreen']};
-        search(hook_mock, opts).then(function () {
+        return search(hook_mock, opts).then(function () {
             expect(opener_mock).toHaveBeenCalled();
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
 
-    it('should fire the after_plugin_search hook', function (done) {
+    it('should fire the after_plugin_search hook', function () {
         var opts = {important: 'options', plugins: []};
-        search(hook_mock, opts).then(function () {
+        return search(hook_mock, opts).then(function () {
             expect(hook_mock.fire).toHaveBeenCalledWith('after_plugin_search', opts);
-        }).fail(function (e) {
-            fail('fail handler unexpectedly invoked');
-            console.error(e);
-        }).done(done);
+        });
     });
 });
diff --git a/spec/cordova/prepare.spec.js b/spec/cordova/prepare.spec.js
index d89742c..1d4ff43 100644
--- a/spec/cordova/prepare.spec.js
+++ b/spec/cordova/prepare.spec.js
@@ -72,85 +72,69 @@ describe('cordova/prepare', function () {
             spyOn(prepare, 'preparePlatforms').and.returnValue(Q);
         });
         describe('failure', function () {
-            it('should invoke util.preProcessOptions as preflight task checker, which, if fails, should trigger promise rejection and only fire the before_prepare hook', function (done) {
+            it('should invoke util.preProcessOptions as preflight task checker, which, if fails, should trigger promise rejection and only fire the before_prepare hook', function () {
                 util.preProcessOptions.and.callFake(function () {
                     throw new Error('preProcessOption error');
                 });
-                prepare({}).then(function () {
-                    fail('unexpected success handler invoked');
-                }).fail(function (e) {
-                    expect(e.message).toBe('preProcessOption error');
+                return prepare({}).then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toBe('preProcessOption error');
                     expect(HooksRunner.prototype.fire).toHaveBeenCalledWith('before_prepare', jasmine.any(Object));
-                }).done(done);
+                });
             });
-            it('should invoke util.cdProjectRoot as a preflight task checker, which, if fails, should trigger a promise rejection and fire no hooks', function (done) {
+            it('should invoke util.cdProjectRoot as a preflight task checker, which, if fails, should trigger a promise rejection and fire no hooks', function () {
                 util.cdProjectRoot.and.callFake(function () {
                     throw new Error('cdProjectRoot error');
                 });
 
-                prepare({}).then(function () {
-                    fail('unexpected success handler invoked');
-                }).fail(function (e) {
-                    expect(e.message).toBe('cdProjectRoot error');
+                return prepare({}).then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toBe('cdProjectRoot error');
                     expect(HooksRunner.prototype.fire).not.toHaveBeenCalled();
-                }).done(done);
+                });
             });
         });
 
         describe('success', function () {
-            it('should fire the before_prepare hook and provide platform and path information as arguments', function (done) {
-                prepare({}).then(function () {
+            it('should fire the before_prepare hook and provide platform and path information as arguments', function () {
+                return prepare({}).then(function () {
                     expect(HooksRunner.prototype.fire).toHaveBeenCalledWith('before_prepare', jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('unexpected failure handler invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
-            it('should invoke restore module\'s installPlatformsFromConfigXML method', function (done) {
-                prepare({}).then(function () {
+            it('should invoke restore module\'s installPlatformsFromConfigXML method', function () {
+                return prepare({}).then(function () {
                     expect(restore.installPlatformsFromConfigXML).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('unexpected failure handler invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
-            it('should retrieve PlatformApi instances for each platform provided', function (done) {
-                prepare({'platforms': ['android', 'ios']}).then(function () {
+            it('should retrieve PlatformApi instances for each platform provided', function () {
+                return prepare({'platforms': ['android', 'ios']}).then(function () {
                     expect(platforms.getPlatformApi).toHaveBeenCalledTimes(4);
                     // expect(platforms.getPlatformApi).toHaveBeenCalledWith(['android', path.join('some','path','platforms','android')], ['ios', path.join('some','path','platforms','ios')], ['android'], ['ios']);
                     expect(platforms.getPlatformApi).toHaveBeenCalledWith('android', path.join('/', 'some', 'path', 'platforms', 'android'));
                     expect(platforms.getPlatformApi).toHaveBeenCalledWith('ios', path.join('/', 'some', 'path', 'platforms', 'ios'));
                     expect(platforms.getPlatformApi).toHaveBeenCalledWith('android');
                     expect(platforms.getPlatformApi).toHaveBeenCalledWith('ios');
-                }).fail(function (e) {
-                    fail('unexpected failure handler invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
-            it('should invoke restore module\'s installPluginsFromConfigXML method', function (done) {
-                prepare({platforms: []}).then(function () {
+            it('should invoke restore module\'s installPluginsFromConfigXML method', function () {
+                return prepare({platforms: []}).then(function () {
                     expect(restore.installPluginsFromConfigXML).toHaveBeenCalled();
-                }).fail(function (e) {
-                    fail('unexpected failure handler invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
-            it('should invoke preparePlatforms method, providing the appropriate platforms', function (done) {
-                prepare({platforms: ['android']}).then(function () {
+            it('should invoke preparePlatforms method, providing the appropriate platforms', function () {
+                return prepare({platforms: ['android']}).then(function () {
                     expect(prepare.preparePlatforms).toHaveBeenCalledWith(['android'], '/some/path', jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('unexpected failure handler invoked');
-                    console.error(e);
-                }).done(done);
+                });
 
             });
-            it('should fire the after_prepare hook and provide platform and path information as arguments', function (done) {
-                prepare({platforms: ['android']}).then(function () {
+            it('should fire the after_prepare hook and provide platform and path information as arguments', function () {
+                return prepare({platforms: ['android']}).then(function () {
                     expect(HooksRunner.prototype.fire).toHaveBeenCalledWith('after_prepare', jasmine.any(Object));
-                }).fail(function (e) {
-                    fail('unexpected failure handler invoked');
-                    console.error(e);
-                }).done(done);
+                });
             });
         });
     });
@@ -178,49 +162,37 @@ describe('cordova/prepare', function () {
             cfg_parser_revert_mock();
             platform_munger_revert_mock();
         });
-        it('should call restoreMissingPluginsForPlatform', function (done) {
-            prepare.preparePlatforms(['android'], project_dir, {}).then(function () {
+        it('should call restoreMissingPluginsForPlatform', function () {
+            return prepare.preparePlatforms(['android'], project_dir, {}).then(function () {
                 expect(prepare.restoreMissingPluginsForPlatform).toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('unexpected failure handler invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
-        it('should retrieve the platform API via getPlatformApi per platform provided, and invoke the prepare method from that API', function (done) {
-            prepare.preparePlatforms(['android'], project_dir, {}).then(function () {
+        it('should retrieve the platform API via getPlatformApi per platform provided, and invoke the prepare method from that API', function () {
+            return prepare.preparePlatforms(['android'], project_dir, {}).then(function () {
                 expect(platforms.getPlatformApi).toHaveBeenCalledWith('android');
                 expect(platform_api_prepare_mock).toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('unexpected failure handler invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
-        it('should fire a pre_package hook for the windows', function (done) {
-            prepare.preparePlatforms(['windows'], project_dir, {}).then(function () {
+        it('should fire a pre_package hook for the windows', function () {
+            return prepare.preparePlatforms(['windows'], project_dir, {}).then(function () {
                 expect(HooksRunner.prototype.fire).toHaveBeenCalledWith('pre_package', jasmine.any(Object));
-            }).fail(function (e) {
-                fail('unexpected failure handler invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
         // TODO: xit'ed the one below as dynamic requires make it difficult to spy on
         // Can we refactor the relevant code to make it testable?
         xit('should invoke browserify if the browserify option is provided');
-        it('should handle config changes by invoking add_config_changes and save_all', function (done) {
-            prepare.preparePlatforms(['android'], project_dir, {}).then(function () {
+        it('should handle config changes by invoking add_config_changes and save_all', function () {
+            return prepare.preparePlatforms(['android'], project_dir, {}).then(function () {
                 expect(platform_munger_mock.prototype.add_config_changes).toHaveBeenCalled();
                 expect(platform_munger_save_mock).toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('unexpected failure handler invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
     });
 
     describe('restoreMissingPluginsForPlatform helper method', function () {
         var is_plugin_installed_mock;
         var is_plugin_provider_get_mock;
-        it('should resolve quickly and not invoke getPlatformAPI in the easy case of there being no difference between old and new platform.json', function (done) {
+        it('should resolve quickly and not invoke getPlatformAPI in the easy case of there being no difference between old and new platform.json', function () {
             is_plugin_installed_mock = jasmine.createSpy('is plugin installed mock');
             // mock platform json value below
             PlatformJson.load.and.callFake(function (platformJsonPath, plat) {
@@ -233,14 +205,11 @@ describe('cordova/prepare', function () {
                 };
             });
 
-            prepare.restoreMissingPluginsForPlatform('android', project_dir, {}).then(function () {
+            return prepare.restoreMissingPluginsForPlatform('android', project_dir, {}).then(function () {
                 expect(platforms.getPlatformApi).not.toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('unexpected failure handler invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
-        it('should leverage platform API to remove and add any missing plugins identified', function (done) {
+        it('should leverage platform API to remove and add any missing plugins identified', function () {
             is_plugin_installed_mock = jasmine.createSpy('is plugin installed mock');
             is_plugin_provider_get_mock = jasmine.createSpy('is plugin provider get mock');
             // mock platform json value below
@@ -263,15 +232,12 @@ describe('cordova/prepare', function () {
             spyOn(PluginInfoProvider.prototype, 'get').and.callFake(function () {
                 return is_plugin_provider_get_mock;
             });
-            prepare.restoreMissingPluginsForPlatform('android', project_dir, {}).then(function () {
+            return prepare.restoreMissingPluginsForPlatform('android', project_dir, {}).then(function () {
                 expect(platforms.getPlatformApi).toHaveBeenCalled();
                 expect(platform_api_add_mock).toHaveBeenCalled();
                 expect(platform_api_remove_mock).toHaveBeenCalled();
                 expect(PluginInfoProvider.prototype.get).toHaveBeenCalled();
-            }).fail(function (e) {
-                fail('unexpected failure handler invoked');
-                console.error(e);
-            }).done(done);
+            });
         });
     });
 });
diff --git a/spec/cordova/project-metadata-apis.spec.js b/spec/cordova/project-metadata-apis.spec.js
index 45b7d75..84d8091 100644
--- a/spec/cordova/project-metadata-apis.spec.js
+++ b/spec/cordova/project-metadata-apis.spec.js
@@ -23,11 +23,11 @@ var path = require('path');
 describe('retrieval of project metadata', function () {
     var projectRoot = path.resolve(__dirname, 'Projects/ProjectMetadata');
 
-    it('Test 001 : retrieve platforms saved in config.xml', function (done) {
+    it('Test 001 : retrieve platforms saved in config.xml', function () {
         var androidVersion = '3.7.1';
         var browserSrc = 'https://github.com/apache/cordova-browser.git';
 
-        cordova.projectMetadata.getPlatforms(projectRoot)
+        return cordova.projectMetadata.getPlatforms(projectRoot)
             .then(function (platforms) {
                 expect(platforms.length).toBe(2);
 
@@ -42,10 +42,10 @@ describe('retrieval of project metadata', function () {
                 expect(browserPlatform).not.toBeNull();
                 expect(browserPlatform.version).toBeUndefined();
                 expect(browserPlatform.src).toBe(browserSrc);
-            }).finally(done);
+            });
     });
 
-    it('Test 002 : retrieve plugins saved in config.xml', function (done) {
+    it('Test 002 : retrieve plugins saved in config.xml', function () {
         var deviceId = 'org.apache.cordova.device';
         var deviceVersion = '0.3.0';
 
@@ -57,7 +57,7 @@ describe('retrieval of project metadata', function () {
         var fileId = 'org.apache.cordova.file';
         var fileSource = 'https://github.com/apache/cordova-plugin-file.git';
 
-        cordova.projectMetadata.getPlugins(projectRoot)
+        return cordova.projectMetadata.getPlugins(projectRoot)
             .then(function (plugins) {
                 expect(plugins.length).toBe(3);
 
@@ -94,7 +94,7 @@ describe('retrieval of project metadata', function () {
                 expect(fileVariables).not.toBeNull();
                 expect(Array.isArray(fileVariables)).toBeTruthy();
                 expect(fileVariables.length).toBe(0);
-            }).finally(done);
+            });
     });
 });
 
diff --git a/spec/cordova/run.spec.js b/spec/cordova/run.spec.js
index a19540e..3b52b1a 100644
--- a/spec/cordova/run.spec.js
+++ b/spec/cordova/run.spec.js
@@ -42,95 +42,85 @@ describe('run command', function () {
         getPlatformApi = spyOn(platforms, 'getPlatformApi').and.returnValue(platformApi);
     });
     describe('failure', function () {
-        it('Test 001 : should not run inside a Cordova-based project with no added platforms by calling util.listPlatforms', function (done) {
+        it('Test 001 : should not run inside a Cordova-based project with no added platforms by calling util.listPlatforms', function () {
             list_platforms.and.returnValue([]);
-            Q().then(cordova.run).then(function () {
-                expect('this call').toBe('fail');
-            }, function (err) {
-                expect(err.message).toEqual('No platforms added to this project. Please use `cordova platform add <platform>`.');
-            }).fin(done);
+            return Q().then(cordova.run)
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toEqual('No platforms added to this project. Please use `cordova platform add <platform>`.');
+                });
         });
-        it('Test 002 : should not run outside of a Cordova-based project', function (done) {
+        it('Test 002 : should not run outside of a Cordova-based project', function () {
             var msg = 'Dummy message about not being in a cordova dir.';
             cd_project_root.and.throwError(new Error(msg));
             is_cordova.and.returnValue(false);
-            Q().then(cordova.run).then(function () {
-                expect('this call').toBe('fail');
-            }, function (err) {
-                expect(err.message).toEqual(msg);
-            }).fin(done);
+            return Q().then(cordova.run)
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
+                    expect(err.message).toEqual(msg);
+                });
         });
     });
 
     describe('success', function () {
-        it('Test 003 : should call prepare before actually run platform ', function (done) {
-            cordova.run(['android', 'ios']).then(function () {
+        it('Test 003 : should call prepare before actually run platform ', function () {
+            return cordova.run(['android', 'ios']).then(function () {
                 expect(prepare_spy.calls.argsFor(0)).toEqual([ { platforms: [ 'android', 'ios' ], verbose: false, options: {} } ]);
-            }, function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
         });
-        it('Test 004 : should get PlatformApi instance for each platform and call its\' run method', function (done) {
-            cordova.run(['android', 'ios']).then(function () {
+        it('Test 004 : should get PlatformApi instance for each platform and call its\' run method', function () {
+            return cordova.run(['android', 'ios']).then(function () {
                 expect(getPlatformApi).toHaveBeenCalledWith('android');
                 expect(getPlatformApi).toHaveBeenCalledWith('ios');
                 expect(platformApi.build).toHaveBeenCalled();
                 expect(platformApi.run).toHaveBeenCalled();
-            }, function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
         });
-        it('Test 005 : should pass down parameters', function (done) {
-            cordova.run({platforms: ['blackberry10'], options: {password: '1q1q'}}).then(function () {
+        it('Test 005 : should pass down parameters', function () {
+            return cordova.run({platforms: ['blackberry10'], options: {password: '1q1q'}}).then(function () {
                 expect(prepare_spy).toHaveBeenCalledWith({ platforms: [ 'blackberry10' ], options: { password: '1q1q' }, verbose: false });
                 expect(platformApi.build).toHaveBeenCalledWith({password: '1q1q'});
                 expect(platformApi.run).toHaveBeenCalledWith({password: '1q1q', nobuild: true});
-            }, function (err) {
-                expect(err).toBeUndefined();
-            }).fin(done);
+            });
         });
-        it('Test 006 : should convert parameters from old format and warn user about this', function (done) {
+        it('Test 006 : should convert parameters from old format and warn user about this', function () {
             function warnSpy (message) {
                 expect(message).toMatch('The format of cordova.* methods "options" argument was changed');
             }
 
             cordova.on('warn', warnSpy);
-            cordova.run({platforms: ['blackberry10'], options: ['--password=1q1q']}).then(function () {
-                expect(prepare_spy).toHaveBeenCalledWith({ platforms: [ 'blackberry10' ],
-                    options: jasmine.objectContaining({argv: ['--password=1q1q']}),
-                    verbose: false });
-                expect(platformApi.run).toHaveBeenCalledWith(jasmine.objectContaining({argv: ['--password=1q1q']}));
-            }, function (err) {
-                expect(err).toBeUndefined();
-            })
+            return cordova.run({platforms: ['blackberry10'], options: ['--password=1q1q']})
+                .then(function () {
+                    expect(prepare_spy).toHaveBeenCalledWith({ platforms: [ 'blackberry10' ],
+                        options: jasmine.objectContaining({argv: ['--password=1q1q']}),
+                        verbose: false });
+                    expect(platformApi.run).toHaveBeenCalledWith(jasmine.objectContaining({argv: ['--password=1q1q']}));
+                })
                 .fin(function () {
                     cordova.off('warn', warnSpy);
-                    done();
                 });
         });
 
-        it('Test 007 : should call platform\'s build method', function (done) {
-            cordova.run({platforms: ['blackberry10']})
+        it('Test 007 : should call platform\'s build method', function () {
+            return cordova.run({platforms: ['blackberry10']})
                 .then(function () {
                     expect(prepare_spy).toHaveBeenCalled();
                     expect(platformApi.build).toHaveBeenCalledWith({});
                     expect(platformApi.run).toHaveBeenCalledWith(jasmine.objectContaining({nobuild: true}));
-                }, function (err) {
-                    expect(err).toBeUndefined();
-                })
-                .fin(done);
+                });
         });
 
-        it('Test 008 : should not call build if --nobuild option is passed', function (done) {
-            cordova.run({platforms: ['blackberry10'], options: { nobuild: true }})
+        it('Test 008 : should not call build if --nobuild option is passed', function () {
+            return cordova.run({platforms: ['blackberry10'], options: { nobuild: true }})
                 .then(function () {
                     expect(prepare_spy).toHaveBeenCalled();
                     expect(platformApi.build).not.toHaveBeenCalled();
                     expect(platformApi.run).toHaveBeenCalledWith(jasmine.objectContaining({nobuild: true}));
-                }, function (err) {
-                    expect(err).toBeUndefined();
-                })
-                .fin(done);
+                });
         });
 
         describe('run parameters should not be altered by intermediate build command', function () {
@@ -145,45 +135,41 @@ describe('run command', function () {
             afterEach(function () {
                 platformApi.build = originalBuildSpy;
             });
-            it('Test 009 : should leave parameters unchanged', function (done) {
-                cordova.run({platforms: ['blackberry10'], options: {password: '1q1q'}}).then(function () {
+            it('Test 009 : should leave parameters unchanged', function () {
+                return cordova.run({platforms: ['blackberry10'], options: {password: '1q1q'}}).then(function () {
                     expect(prepare_spy).toHaveBeenCalledWith({ platforms: [ 'blackberry10' ], options: { password: '1q1q', 'couldBeModified': 'insideBuild' }, verbose: false });
                     expect(platformApi.build).toHaveBeenCalledWith({password: '1q1q', 'couldBeModified': 'insideBuild'});
                     expect(platformApi.run).toHaveBeenCalledWith({password: '1q1q', nobuild: true});
-                }, function (err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
+                });
             });
         });
     });
 
     describe('hooks', function () {
         describe('when platforms are added', function () {
-            it('Test 010 : should fire before hooks through the hooker module', function (done) {
-                cordova.run(['android', 'ios']).then(function () {
+            it('Test 010 : should fire before hooks through the hooker module', function () {
+                return cordova.run(['android', 'ios']).then(function () {
                     expect(fire.calls.argsFor(0)).toEqual([ 'before_run', { platforms: [ 'android', 'ios' ], verbose: false, options: {} } ]);
-                }, function (err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
+                });
             });
-            it('Test 011 : should fire after hooks through the hooker module', function (done) {
-                cordova.run('android').then(function () {
+            it('Test 011 : should fire after hooks through the hooker module', function () {
+                return cordova.run('android').then(function () {
                     expect(fire.calls.argsFor(2)).toEqual([ 'after_run', { platforms: [ 'android' ], verbose: false, options: {} } ]);
-                }, function (err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
+                });
             });
         });
 
         describe('with no platforms added', function () {
-            it('Test 012 : should not fire the hooker', function (done) {
+            it('Test 012 : should not fire the hooker', function () {
                 list_platforms.and.returnValue([]);
-                Q().then(cordova.run).then(function () {
-                    expect('this call').toBe('fail');
-                }, function (err) {
-                    expect(fire).not.toHaveBeenCalled();
-                    expect(err.message).toEqual('No platforms added to this project. Please use `cordova platform add <platform>`.');
-                }).fin(done);
+                return Q().then(cordova.run)
+                    .then(function () {
+                        fail('Expected promise to be rejected');
+                    }, function (err) {
+                        expect(err).toEqual(jasmine.any(Error));
+                        expect(fire).not.toHaveBeenCalled();
+                        expect(err.message).toEqual('No platforms added to this project. Please use `cordova platform add <platform>`.');
+                    });
             });
         });
     });
diff --git a/spec/cordova/util.spec.js b/spec/cordova/util.spec.js
index 8be8a08..032a123 100644
--- a/spec/cordova/util.spec.js
+++ b/spec/cordova/util.spec.js
@@ -137,7 +137,7 @@ describe('util module', function () {
         afterEach(function () {
             shell.rm('-rf', temp);
         });
-        it('Test 010 : should get the supported platforms in the cordova project dir along with their reported versions', function (done) {
+        it('Test 010 : should get the supported platforms in the cordova project dir along with their reported versions', function () {
             var platforms = path.join(temp, 'platforms');
             var android = path.join(platforms, 'android');
 
@@ -145,10 +145,10 @@ describe('util module', function () {
 
             shell.cp('-R',
                 path.join(__dirname, 'fixtures', 'platforms', helpers.testPlatform), platforms);
-            util.getInstalledPlatformsWithVersions(temp)
+            return util.getInstalledPlatformsWithVersions(temp)
                 .then(function (platformMap) {
                     expect(platformMap['android']).toBe('3.1.0');
-                }).fin(done);
+                });
         });
     });
     describe('findPlugins method', function () {
diff --git a/spec/plugman/add_platform.spec.js b/spec/plugman/add_platform.spec.js
index 9631d2c..0a81731 100644
--- a/spec/plugman/add_platform.spec.js
+++ b/spec/plugman/add_platform.spec.js
@@ -41,14 +41,12 @@ describe('platform add', function () {
         existsSync = spyOn(fs, 'existsSync').and.returnValue(false);
         done = false;
     });
-    it('Test 002 : should error on non existing plugin.xml', function (done) {
-        platform.add().then(function (result) {
-            expect(false).toBe(true);
-            done();
-        },
-        function err (errMsg) {
-            expect(errMsg.toString()).toContain('can\'t find a plugin.xml.  Are you in the plugin?');
-            done();
+    it('Test 002 : should error on non existing plugin.xml', function () {
+        return platform.add().then(function () {
+            fail('Expected promise to be rejected');
+        }, function (err) {
+            expect(err).toEqual(jasmine.any(Error));
+            expect(err.message).toContain('can\'t find a plugin.xml.  Are you in the plugin?');
         });
     }, 6000);
 });
@@ -63,14 +61,12 @@ describe('platform remove', function () {
         existsSync = spyOn(fs, 'existsSync').and.returnValue(false);
         done = false;
     });
-    it('Test 003 : should error on non existing plugin.xml', function (done) {
-        platform.remove().then(function (result) {
-            expect(false).toBe(true);
-            done();
-        },
-        function err (errMsg) {
-            expect(errMsg.toString()).toContain('can\'t find a plugin.xml.  Are you in the plugin?');
-            done();
+    it('Test 003 : should error on non existing plugin.xml', function () {
+        return platform.remove().then(function () {
+            fail('Expected promise to be rejected');
+        }, function (err) {
+            expect(err).toEqual(jasmine.any(Error));
+            expect(err.message).toContain('can\'t find a plugin.xml.  Are you in the plugin?');
         });
     }, 6000);
 });
diff --git a/spec/plugman/create.spec.js b/spec/plugman/create.spec.js
index e538851..860bc9b 100644
--- a/spec/plugman/create.spec.js
+++ b/spec/plugman/create.spec.js
@@ -45,14 +45,10 @@ describe('create plugin', function () {
         done = false;
     });
 
-    it('Test 002 : should be successful', function (done) {
-        create('name', 'org.plugin.id', '0.0.0', '.', [])
+    it('Test 002 : should be successful', function () {
+        return create('name', 'org.plugin.id', '0.0.0', '.', [])
             .then(function (result) {
                 expect(writeFileSync.calls.count()).toEqual(2);
-                done();
-            }).fail(function err (errMsg) {
-                expect(errMsg).toBeUndefined();
-                done();
             });
     }, 6000);
 });
@@ -68,14 +64,13 @@ describe('create plugin in existing plugin', function () {
         done = false; // eslint-disable-line  no-unused-vars
     });
 
-    it('Test 003 : should fail due to an existing plugin.xml', function (done) {
-        create()
-            .then(function (result) {
-                expect(false).toBe(true);
-                done();
-            }).fail(function err (errMsg) {
-                expect(errMsg.toString()).toContain('plugin.xml already exists. Are you already in a plugin?');
-                done();
+    it('Test 003 : should fail due to an existing plugin.xml', function () {
+        return create()
+            .then(function () {
+                fail('Expected promise to be rejected');
+            }, function (err) {
+                expect(err).toEqual(jasmine.any(Error));
+                expect(err.message).toContain('plugin.xml already exists. Are you already in a plugin?');
             });
     }, 6000);
 });
diff --git a/spec/plugman/install.spec.js b/spec/plugman/install.spec.js
index 3341ea3..79d81a3 100644
--- a/spec/plugman/install.spec.js
+++ b/spec/plugman/install.spec.js
@@ -35,7 +35,6 @@ var child_process = require('child_process');
 var semver = require('semver');
 var Q = require('q');
 var spec = __dirname;
-var done = false; // eslint-disable-line no-unused-vars
 var srcProject = path.join(spec, 'projects', 'android');
 var temp_dir = path.join(fs.realpathSync(os.tmpdir()), 'plugman-test');
 var project = path.join(temp_dir, 'android_install');
@@ -126,7 +125,7 @@ describe('plugman install start', function () {
         });
     });
 
-    it('Test 001 : plugman install start', function (done) {
+    it('Test 001 : plugman install start', function () {
         shell.rm('-rf', project);
         shell.cp('-R', path.join(srcProject, '*'), project);
 
@@ -166,10 +165,6 @@ describe('plugman install start', function () {
                     if (emit.calls.argsFor(i)[0] === 'results') { results['emit_results'].push(emit.calls.argsFor(i)[1]); }
                 });
                 events.emit('verbose', '***** DONE START *****');
-                done();
-            }).fail(function (error) {
-                expect(error).toBeUndefined();
-                done();
             });
     }, TIMEOUT);
 });
@@ -201,7 +196,6 @@ describe('install', function () {
         cp = spyOn(shell, 'cp').and.returnValue(true);
         rm = spyOn(shell, 'rm').and.returnValue(true);
         add_to_queue = spyOn(PlatformJson.prototype, 'addInstalledPluginToPrepareQueue');
-        done = false;
     });
 
     describe('success', function () {
@@ -217,16 +211,12 @@ describe('install', function () {
             // VariableBrowser
             expect(results['emit_results'][2]).toBe('Remember that your api key is batman!');
         }, TIMEOUT);
-        it('Test 005 : should call fetch if provided plugin cannot be resolved locally', function (done) {
+        it('Test 005 : should call fetch if provided plugin cannot be resolved locally', function () {
             fetchSpy.and.returnValue(Q(plugins['org.test.plugins.dummyplugin']));
             spyOn(fs, 'existsSync').and.callFake(fake['existsSync']['noPlugins']);
-            install('android', project, 'CLEANYOURSHORTS')
-                .fail(function (err) {
-                    expect(err).toBeUndefined();
-                })
-                .fin(function () {
+            return install('android', project, 'CLEANYOURSHORTS')
+                .then(function () {
                     expect(fetchSpy).toHaveBeenCalled();
-                    done();
                 });
         });
 
@@ -238,39 +228,32 @@ describe('install', function () {
                 spyOn(PlatformJson.prototype, 'isPluginInstalled').and.returnValue(false);
             });
 
-            it('Test 007 : should check version if plugin has engine tag', function (done) {
+            it('Test 007 : should check version if plugin has engine tag', function () {
                 exec.and.callFake(function (cmd, cb) { cb(null, '2.5.0\n'); });
-                install('android', project, plugins['com.cordova.engine'])
-                    .fail(fail)
-                    .fin(function () {
+                return install('android', project, plugins['com.cordova.engine'])
+                    .then(function () {
                         expect(satisfies).toHaveBeenCalledWith('2.5.0', '>=1.0.0', true);
-                        done();
                     });
             }, TIMEOUT);
-            it('Test 008 : should check version and munge it a little if it has "rc" in it so it plays nice with semver (introduce a dash in it)', function (done) {
+            it('Test 008 : should check version and munge it a little if it has "rc" in it so it plays nice with semver (introduce a dash in it)', function () {
                 exec.and.callFake(function (cmd, cb) { cb(null, '3.0.0rc1\n'); });
-                install('android', project, plugins['com.cordova.engine'])
-                    .fail(fail)
-                    .fin(function () {
+                return install('android', project, plugins['com.cordova.engine'])
+                    .then(function () {
                         expect(satisfies).toHaveBeenCalledWith('3.0.0-rc1', '>=1.0.0', true);
-                        done();
                     });
             }, TIMEOUT);
-            it('Test 009 : should check specific platform version over cordova version if specified', function (done) {
+            it('Test 009 : should check specific platform version over cordova version if specified', function () {
                 exec.and.callFake(function (cmd, cb) { cb(null, '3.1.0\n'); });
-                install('android', project, plugins['com.cordova.engine-android'])
-                    .fail(fail)
-                    .fin(function () {
+                return install('android', project, plugins['com.cordova.engine-android'])
+                    .then(function () {
                         expect(satisfies).toHaveBeenCalledWith('3.1.0', '>=3.1.0', true);
-                        done();
                     });
             }, TIMEOUT);
-            it('Test 010 : should check platform sdk version if specified', function (done) {
+            it('Test 010 : should check platform sdk version if specified', function () {
                 var cordovaVersion = require('../../package.json').version.replace(/-dev|-nightly.*$/, '');
                 exec.and.callFake(function (cmd, cb) { cb(null, '18\n'); });
-                install('android', project, plugins['com.cordova.engine-android'])
-                    .fail(fail)
-                    .fin(function () {
+                return install('android', project, plugins['com.cordova.engine-android'])
+                    .then(function () {
                         expect(satisfies.calls.count()).toBe(3);
                         // <engine name="cordova" VERSION=">=3.0.0"/>
                         expect(satisfies.calls.argsFor(0)).toEqual([ cordovaVersion, '>=3.0.0', true ]);
@@ -278,13 +261,11 @@ describe('install', function () {
                         expect(satisfies.calls.argsFor(1)).toEqual([ '18.0.0', '>=3.1.0', true ]);
                         // <engine name="android-sdk" VERSION=">=18"/>
                         expect(satisfies.calls.argsFor(2)).toEqual([ '18.0.0', '>=18', true ]);
-                        done();
                     });
             }, TIMEOUT);
-            it('Test 011 : should check engine versions', function (done) {
-                install('android', project, plugins['com.cordova.engine'])
-                    .fail(fail)
-                    .fin(function () {
+            it('Test 011 : should check engine versions', function () {
+                return install('android', project, plugins['com.cordova.engine'])
+                    .then(function () {
                         var plugmanVersion = require('../../package.json').version.replace(/-dev|-nightly.*$/, '');
                         var cordovaVersion = require('../../package.json').version.replace(/-dev|-nightly.*$/, '');
                         expect(satisfies.calls.count()).toBe(4);
@@ -296,27 +277,22 @@ describe('install', function () {
                         expect(satisfies.calls.argsFor(2)).toEqual([ null, '>=1.0.0', true ]);
                         // <engine name="mega-boring-plugin" version=">=3.0.0" scriptSrc="megaBoringVersion" platform="ios|android" />
                         expect(satisfies.calls.argsFor(3)).toEqual([ null, '>=3.0.0', true ]);
-                        done();
                     });
             }, TIMEOUT);
-            it('Test 012 : should not check custom engine version that is not supported for platform', function (done) {
-                install('blackberry10', project, plugins['com.cordova.engine'])
-                    .then(fail)
-                    .fail(function () {
+            it('Test 012 : should not check custom engine version that is not supported for platform', function () {
+                return install('blackberry10', project, plugins['com.cordova.engine'])
+                    .then(fail, function () {
                         expect(satisfies).not.toHaveBeenCalledWith('', '>=3.0.0', true);
-                    })
-                    .fin(done);
+                    });
             }, TIMEOUT);
         });
 
-        it('Test 014 : should not check custom engine version that is not supported for platform', function (done) {
+        it('Test 014 : should not check custom engine version that is not supported for platform', function () {
             var spy = spyOn(semver, 'satisfies').and.returnValue(true);
-            install('blackberry10', project, plugins['com.cordova.engine'])
+            return install('blackberry10', project, plugins['com.cordova.engine'])
                 .then(function () {
                     expect(spy).not.toHaveBeenCalledWith('', '>=3.0.0');
-                }).fail(function (err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
+                });
         }, TIMEOUT);
 
         describe('with dependencies', function () {
@@ -336,7 +312,7 @@ describe('install', function () {
                 spyOn(knownPlatforms, 'getPlatformApi').and.returnValue(PlatformApiMock);
             });
 
-            it('Test 015 : should install specific version of dependency', function (done) {
+            it('Test 015 : should install specific version of dependency', function () {
                 // Plugin I depends on C@1.0.0
                 emit.calls.reset();
                 return install('android', project, plugins['I'])
@@ -347,11 +323,10 @@ describe('install', function () {
                             'Install start for "C" on android.',
                             'Install start for "I" on android.'
                         ]);
-                        done();
                     }, TIMEOUT);
             }, TIMEOUT);
 
-            it('Test 016 : should install any dependent plugins if missing', function (done) {
+            it('Test 016 : should install any dependent plugins if missing', function () {
                 emit.calls.reset();
                 return install('android', project, plugins['A'])
                     .then(function () {
@@ -361,11 +336,10 @@ describe('install', function () {
                             'Install start for "D" on android.',
                             'Install start for "A" on android.'
                         ]);
-                        done();
                     });
             }, TIMEOUT);
 
-            it('Test 017 : should install any dependent plugins from registry when url is not defined', function (done) {
+            it('Test 017 : should install any dependent plugins from registry when url is not defined', function () {
                 emit.calls.reset();
                 return install('android', project, plugins['A'])
                     .then(function () {
@@ -375,11 +349,10 @@ describe('install', function () {
                             'Install start for "D" on android.',
                             'Install start for "A" on android.'
                         ]);
-                        done();
                     });
             }, TIMEOUT);
 
-            it('Test 018 : should process all dependent plugins with alternate routes to the same plugin', function (done) {
+            it('Test 018 : should process all dependent plugins with alternate routes to the same plugin', function () {
                 // Plugin F depends on A, C, D and E
                 emit.calls.reset();
                 return install('android', project, plugins['F'])
@@ -392,20 +365,19 @@ describe('install', function () {
                             'Install start for "D" on android.',
                             'Install start for "F" on android.'
                         ]);
-                        done();
                     });
             }, TIMEOUT);
 
-            it('Test 019 : should throw if there is a cyclic dependency', function (done) {
+            it('Test 019 : should throw if there is a cyclic dependency', function () {
                 return install('android', project, plugins['G'])
                     .then(function () {
                         common.spy.getInstall(emit);
                     }).fail(function err (errMsg) {
                         expect(errMsg.toString()).toContain('Cyclic dependency from G to H');
-                    }).fin(done);
+                    });
             }, TIMEOUT);
 
-            it('Test 020 : install subdir relative to top level plugin if no fetch meta', function (done) {
+            it('Test 020 : install subdir relative to top level plugin if no fetch meta', function () {
                 return install('android', project, plugins['B'])
                     .then(function () {
                         var install = common.spy.getInstall(emit);
@@ -414,11 +386,10 @@ describe('install', function () {
                             'Install start for "E" on android.',
                             'Install start for "B" on android.'
                         ]);
-                        done();
                     });
             }, TIMEOUT);
 
-            it('Test 021 : install uses meta data (if available) of top level plugin source', function (done) {
+            it('Test 021 : install uses meta data (if available) of top level plugin source', function () {
                 // Fake metadata so plugin 'B' appears from 'meta/B'
                 var meta = require('../../src/plugman/util/metadata');
                 spyOn(meta, 'get_fetch_metadata').and.callFake(function () {
@@ -440,84 +411,60 @@ describe('install', function () {
                         expect(copy.length).toBe(3);
                         expect(copy[0].indexOf(path.normalize('meta/D')) > 0).toBe(true);
                         expect(copy[1].indexOf(path.normalize('meta/subdir/E')) > 0).toBe(true);
-                        done();
                     });
             }, TIMEOUT);
         });
     });
 
     describe('failure', function () {
-        it('Test 023 : should throw if variables are missing', function (done) {
-            var success = jasmine.createSpy('success');
+        it('Test 023 : should throw if variables are missing', function () {
             spyOn(PlatformJson.prototype, 'isPluginInstalled').and.returnValue(false);
-            install('android', project, plugins['com.adobe.vars'])
-                .then(success)
-                .fail(function (err) {
+            return install('android', project, plugins['com.adobe.vars'])
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
                     expect(err.toString()).toContain('Variable(s) missing: API_KEY');
-                })
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    done();
                 });
         }, TIMEOUT);
 
-        it('Test 025 :should not fail when trying to install plugin less than minimum version. Skip instead  ', function (done) {
+        it('Test 025 :should not fail when trying to install plugin less than minimum version. Skip instead  ', function () {
             spyOn(semver, 'satisfies').and.returnValue(false);
             exec.and.callFake(function (cmd, cb) {
                 cb(null, '0.0.1\n');
             });
-            install('android', project, plugins['com.cordova.engine'])
+            return install('android', project, plugins['com.cordova.engine'])
                 .then(function (result) {
                     expect(result).toBe(true);
-                    done();
-                })
-                .fail(function (error) {
-                    expect(error).toBeUndefined();
                 });
         }, TIMEOUT);
 
-        it('Test 026 : should throw if the engine scriptSrc escapes out of the plugin dir.', function (done) {
-            var success = jasmine.createSpy('success');
-            var fail = jasmine.createSpy('fail').and.callFake(function (err) {
-                // <engine name="path-escaping-plugin" version=">=1.0.0" scriptSrc="../../../malicious/script" platform="*" />
-                expect(err).toBeDefined();
-                expect(err.message.indexOf('Security violation:')).toBe(0);
-            });
-
+        it('Test 026 : should throw if the engine scriptSrc escapes out of the plugin dir.', function () {
             spyOn(PlatformJson.prototype, 'isPluginInstalled').and.returnValue(false);
-            install('android', project, plugins['org.test.invalid.engine.script'])
-                .then(success)
-                .fail(fail)
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    expect(fail).toHaveBeenCalled();
-                    done();
+            return install('android', project, plugins['org.test.invalid.engine.script'])
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    // <engine name="path-escaping-plugin" version=">=1.0.0" scriptSrc="../../../malicious/script" platform="*" />
+                    expect(err).toBeDefined();
+                    expect(err.message.indexOf('Security violation:')).toBe(0);
                 });
         }, TIMEOUT);
-        it('Test 027 : should throw if a non-default cordova engine platform attribute is not defined.', function (done) {
-            var success = jasmine.createSpy('success');
-            var fail = jasmine.createSpy('fail');
+        it('Test 027 : should throw if a non-default cordova engine platform attribute is not defined.', function () {
             spyOn(PlatformJson.prototype, 'isPluginInstalled').and.returnValue(false);
-            install('android', project, plugins['org.test.invalid.engine.no.platform'])
-                .then(success)
-                .fail(fail)
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    expect(fail).toHaveBeenCalled();
-                    done();
+            return install('android', project, plugins['org.test.invalid.engine.no.platform'])
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
                 });
         }, TIMEOUT);
-        it('Test 028 : should throw if a non-default cordova engine scriptSrc attribute is not defined.', function (done) {
-            var success = jasmine.createSpy('success');
-            var fail = jasmine.createSpy('fail');
+        it('Test 028 : should throw if a non-default cordova engine scriptSrc attribute is not defined.', function () {
             spyOn(PlatformJson.prototype, 'isPluginInstalled').and.returnValue(false);
-            install('android', project, plugins['org.test.invalid.engine.no.scriptSrc'])
-                .then(success)
-                .fail(fail)
-                .fin(function () {
-                    expect(success).not.toHaveBeenCalled();
-                    expect(fail).toHaveBeenCalled();
-                    done();
+            return install('android', project, plugins['org.test.invalid.engine.no.scriptSrc'])
+                .then(function () {
+                    fail('Expected promise to be rejected');
+                }, function (err) {
+                    expect(err).toEqual(jasmine.any(Error));
                 });
         }, TIMEOUT);
     });


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