You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by an...@apache.org on 2015/09/02 13:31:42 UTC

[4/5] cordova-lib git commit: CB-9597 Initial Implementation of PlatformApiPoly

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/install-browserify.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/install-browserify.spec.js b/cordova-lib/spec-plugman/install-browserify.spec.js
deleted file mode 100644
index 6d94eee..0000000
--- a/cordova-lib/spec-plugman/install-browserify.spec.js
+++ /dev/null
@@ -1,519 +0,0 @@
-// /**
-//     Licensed to the Apache Software Foundation (ASF) under one
-//     or more contributor license agreements.  See the NOTICE file
-//     distributed with this work for additional information
-//     regarding copyright ownership.  The ASF licenses this file
-//     to you under the Apache License, Version 2.0 (the
-//     "License"); you may not use this file except in compliance
-//     with the License.  You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-
-//     Unless required by applicable law or agreed to in writing,
-//     software distributed under the License is distributed on an
-//     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-//     KIND, either express or implied.  See the License for the
-//     specific language governing permissions and limitations
-//     under the License.
-// */
-
-/* jshint sub:true */
-
-var install = require('../src/plugman/install'),
-    actions = require('../src/plugman/util/action-stack'),
-    PlatformJson = require('../src/plugman/util/PlatformJson'),
-    events  = require('../src/events'),
-    plugman = require('../src/plugman/plugman'),
-    platforms = require('../src/plugman/platforms/common'),
-    common  = require('./common'),
-    fs      = require('fs'),
-    os      = require('os'),
-    path    = require('path'),
-    shell   = require('shelljs'),
-    child_process = require('child_process'),
-    semver  = require('semver'),
-    Q = require('q'),
-    spec    = __dirname,
-    done    = false,
-    srcProject = path.join(spec, 'projects', 'android_install'),
-    temp_dir = path.join(os.tmpdir(), 'plugman-test'),
-    project = path.join(temp_dir, 'android_install'),
-    plugins_dir = path.join(spec, 'plugins'),
-    plugins_install_dir = path.join(project, 'cordova', 'plugins'),
-    plugins = {
-        'org.test.plugins.dummyplugin' : path.join(plugins_dir, 'org.test.plugins.dummyplugin'),
-        'com.cordova.engine' : path.join(plugins_dir, 'com.cordova.engine'),
-        'com.cordova.engine-android' : path.join(plugins_dir, 'com.cordova.engine-android'),
-        'org.test.plugins.childbrowser' : path.join(plugins_dir, 'org.test.plugins.childbrowser'),
-        'com.adobe.vars' : path.join(plugins_dir, 'com.adobe.vars'),
-        'org.test.defaultvariables' : path.join(plugins_dir, 'org.test.defaultvariables'),
-        'A' : path.join(plugins_dir, 'dependencies', 'A'),
-        'B' : path.join(plugins_dir, 'dependencies', 'B'),
-        'C' : path.join(plugins_dir, 'dependencies', 'C'),
-        'F' : path.join(plugins_dir, 'dependencies', 'F'),
-        'G' : path.join(plugins_dir, 'dependencies', 'G')
-    },
-    promise,
-    results = {},
-    dummy_id = 'org.test.plugins.dummyplugin',
-    superspawn = require('../src/cordova/superspawn');
-
-
-// Pre-crete the temp dir, without it the test fails.
-shell.mkdir('-p', temp_dir);
-
-function installPromise(f) {
-  f.then(function(res) { done = true; }, function(err) { done = err; });
-}
-
-var existsSync = fs.existsSync;
-
-// Mocked functions for tests
-var fake = {
-    'existsSync' : {
-        'noPlugins' : function(path){
-            // fake installed plugin directories as 'not found'
-            if( path.slice(-5) !== '.json' && path.indexOf(plugins_install_dir) >= 0) {
-                return false;
-            }
-
-            return existsSync(path);
-        }
-    },
-    'fetch' : {
-        'dependencies' : function(id, dir) {
-            if(id == plugins['A'])
-                return Q(id); // full path to plugin
-
-            return Q( path.join(plugins_dir, 'dependencies', id) );
-        }
-    }
-};
-
-describe('start', function() {
-    var prepare, prepareBrowserify, config_queue_add, proc, actions_push, ca, emit;
-
-    beforeEach(function() {
-        prepare = spyOn(plugman, 'prepare');
-        prepareBrowserify = spyOn(plugman, 'prepareBrowserify');
-        config_queue_add = spyOn(PlatformJson.prototype, 'addInstalledPluginToPrepareQueue');
-        proc = spyOn(actions.prototype, 'process').andReturn( Q(true) );
-        actions_push = spyOn(actions.prototype, 'push');
-        ca = spyOn(actions.prototype, 'createAction');
-    });
-    it('start', function() {
-        shell.rm('-rf', project);
-        shell.cp('-R', path.join(srcProject, '*'), project);
-
-        done = false;
-        promise = Q()
-         .then(
-            function(){ return install('android', project, plugins['org.test.plugins.dummyplugin'], plugins_install_dir, { browserify: true }); }
-        ).then(
-            function(){
-                results['actions_callCount'] = actions_push.callCount;
-                results['actions_create'] = ca.argsForCall[0];
-                results['config_add'] = config_queue_add.argsForCall[0];
-
-                return Q();
-            }
-        ).then(
-            function(){
-                return install('android', project, plugins['com.cordova.engine'], plugins_install_dir, { browserify: true }); }
-        ).then(
-            function(){
-                emit = spyOn(events, 'emit');
-                return install('android', project, plugins['org.test.plugins.childbrowser'], plugins_install_dir, { browserify: true });
-            }
-        ).then(
-            function(){
-                return install('android', project, plugins['com.adobe.vars'], plugins_install_dir, { browserify: true, cli_variables:{API_KEY:'batman'} });
-            }
-        ).then(
-            function(){
-                done = true;
-                results['prepareCount'] = prepareBrowserify.callCount;
-                results['emit_results'] = [];
-
-                for(var i in emit.calls) {
-                    if(emit.calls[i].args[0] === 'results')
-                        results['emit_results'].push(emit.calls[i].args[1]);
-                }
-
-                events.emit('verbose', '***** DONE START *****');
-            }
-        ).fail(
-            function(error) {
-                expect(error).toEqual({});
-            }
-        );
-        waitsFor(function() { return done; }, 'promise never resolved', 2000);
-    });
-});
-
-describe('install', function() {
-    var chmod, exec, add_to_queue, prepare, cp, rm, fetchSpy;
-    var spawnSpy;
-
-    beforeEach(function() {
-        prepare = spyOn(plugman, 'prepare').andReturn( Q(true) );
-        spyOn(plugman, 'prepareBrowserify');
-        exec = spyOn(child_process, 'exec').andCallFake(function(cmd, cb) {
-            cb(false, '', '');
-        });
-        spawnSpy = spyOn(superspawn, 'spawn').andReturn(Q('3.1.0'));
-        spyOn(fs, 'mkdirSync').andReturn(true);
-        spyOn(shell, 'mkdir').andReturn(true);
-        spyOn(platforms, 'copyFile').andReturn(true);
-
-        fetchSpy = spyOn(plugman.raw, 'fetch').andReturn( Q( plugins['com.cordova.engine'] ) );
-        chmod = spyOn(fs, 'chmodSync').andReturn(true);
-        spyOn(fs, 'writeFileSync').andReturn(true);
-        cp = spyOn(shell, 'cp').andReturn(true);
-        rm = spyOn(shell, 'rm').andReturn(true);
-        add_to_queue = spyOn(PlatformJson.prototype, 'addInstalledPluginToPrepareQueue');
-        done = false;
-    });
-
-    describe('success', function() {
-        it('should call prepare after a successful install', function() {
-           expect(results['prepareCount']).toBe(4);
-        });
-
-        it('should emit a results event with platform-agnostic <info>', function() {
-            // org.test.plugins.childbrowser
-            expect(results['emit_results'][0]).toBe('No matter what platform you are installing to, this notice is very important.');
-        });
-        it('should emit a results event with platform-specific <info>', function() {
-            // org.test.plugins.childbrowser
-            expect(results['emit_results'][1]).toBe('Please make sure you read this because it is very important to complete the installation of your plugin.');
-        });
-        it('should interpolate variables into <info> tags', function() {
-            // VariableBrowser
-            expect(results['emit_results'][2]).toBe('Remember that your api key is batman!');
-        });
-
-        it('should call fetch if provided plugin cannot be resolved locally', function() {
-            fetchSpy.andReturn( Q( plugins['org.test.plugins.dummyplugin'] ) );
-            spyOn(fs, 'existsSync').andCallFake( fake['existsSync']['noPlugins'] );
-
-            runs(function() {
-                installPromise(install('android', project, 'CLEANYOURSHORTS', plugins_dir, { browserify: true } ));
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(done).toBe(true);
-                expect(fetchSpy).toHaveBeenCalled();
-            });
-        });
-
-        it('should call the config-changes module\'s add_installed_plugin_to_prepare_queue method after processing an install', function() {
-           expect(results['config_add']).toEqual([dummy_id, {}, true]);
-        });
-        it('should queue up actions as appropriate for that plugin and call process on the action stack',
-           function() {
-                expect(results['actions_callCount']).toEqual(6);
-                expect(results['actions_create']).toEqual([jasmine.any(Function), [jasmine.any(Object), path.join(plugins_install_dir, dummy_id), dummy_id, jasmine.any(Object)], jasmine.any(Function), [jasmine.any(Object), dummy_id, jasmine.any(Object)]]);
-        });
-
-        it('should check version if plugin has engine tag', function(){
-            var satisfies = spyOn(semver, 'satisfies').andReturn(true);
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '2.5.0\n');
-            });
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(satisfies).toHaveBeenCalledWith('2.5.0','>=2.3.0');
-            });
-        });
-        it('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() {
-            var satisfies = spyOn(semver, 'satisfies').andReturn(true);
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '3.0.0rc1\n');
-            });
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(satisfies).toHaveBeenCalledWith('3.0.0-rc1','>=2.3.0');
-            });
-        });
-        it('should check specific platform version over cordova version if specified', function() {
-            var spy = spyOn(semver, 'satisfies').andReturn(true);
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '3.1.0\n');
-            });
-            fetchSpy.andReturn( Q( plugins['com.cordova.engine-android'] ) );
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine-android'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(spy).toHaveBeenCalledWith('3.1.0','>=3.1.0');
-            });
-        });
-        it('should check platform sdk version if specified', function() {
-            var spy = spyOn(semver, 'satisfies').andReturn(true);
-            fetchSpy.andReturn( Q( plugins['com.cordova.engine-android'] ) );
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '18\n');
-            });
-
-            runs(function() {
-                installPromise( install('android', project, 'com.cordova.engine-android', plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                // <engine name="cordova" VERSION=">=3.0.0"/>
-                // <engine name="cordova-android" VERSION=">=3.1.0"/>
-                // <engine name="android-sdk" VERSION=">=18"/>
-
-                expect(spy.calls.length).toBe(3);
-                expect(spy.calls[0].args).toEqual([ '18.0.0', '>=3.0.0' ]);
-                expect(spy.calls[1].args).toEqual([ '18.0.0', '>=3.1.0' ]);
-                expect(spy.calls[2].args).toEqual([ '18.0.0','>=18' ]);
-            });
-        });
-        it('should check engine versions', function() {
-            var spy = spyOn(semver, 'satisfies').andReturn(true);
-            fetchSpy.andReturn( Q( plugins['com.cordova.engine'] ) );
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                // <engine name="cordova" version=">=2.3.0"/>
-                // <engine name="cordova-plugman" version=">=0.10.0" />
-                // <engine name="mega-fun-plugin" version=">=1.0.0" scriptSrc="megaFunVersion" platform="*" />
-                // <engine name="mega-boring-plugin" version=">=3.0.0" scriptSrc="megaBoringVersion" platform="ios|android" />
-
-                var plugmanVersion = require('../package.json').version;
-                plugmanVersion = plugmanVersion.replace(/-dev$/, '');
-
-                expect(spy.calls.length).toBe(4);
-                expect(spy.calls[0].args).toEqual([ null, '>=2.3.0' ]);
-                expect(spy.calls[1].args).toEqual([ plugmanVersion, '>=0.10.0' ]);
-                expect(spy.calls[2].args).toEqual([ null, '>=1.0.0' ]);
-                expect(spy.calls[3].args).toEqual([ null, '>=3.0.0' ]);
-            });
-        });
-        it('should not check custom engine version that is not supported for platform', function() {
-            var spy = spyOn(semver, 'satisfies').andReturn(true);
-            runs(function() {
-                installPromise( install('blackberry10', project, plugins['com.cordova.engine'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(spy).not.toHaveBeenCalledWith('','>=3.0.0');
-            });
-        });
-
-        describe('with dependencies', function() {
-            var emit;
-            beforeEach(function() {
-                spyOn(fs, 'existsSync').andCallFake( fake['existsSync']['noPlugins'] );
-                fetchSpy.andCallFake( fake['fetch']['dependencies'] );
-                emit = spyOn(events, 'emit');
-                exec.andCallFake(function(cmd, cb) {
-                    cb(null, '9.0.0\n');
-                });
-            });
-
-            it('should install any dependent plugins if missing', function() {
-                runs(function() {
-                    installPromise( install('android', project, plugins['A'], plugins_install_dir, { browserify: true }) );
-                });
-                waitsFor(function() { return done; }, 'install promise never resolved', 200);
-                runs(function() {
-                    // Look for 'Installing plugin ...' in events
-                    var install = common.spy.getInstall(emit);
-
-                    expect(install).toEqual([
-                        'Install start for "C" on android.',
-                        'Install start for "D" on android.',
-                        'Install start for "A" on android.'
-                    ]);
-                });
-            });
-
-            it('should install any dependent plugins from registry when url is not defined', function() {
-                // Plugin A depends on C & D
-                runs(function() {
-                    installPromise( install('android', project, plugins['A'], plugins_install_dir, { browserify: true }) );
-                });
-                waitsFor(function() { return done; }, 'promise never resolved', 200);
-                runs(function() {
-                    // TODO: this is same test as above? Need test other dependency with url=?
-                    var install = common.spy.getInstall(emit);
-
-                    expect(install).toEqual([
-                        'Install start for "C" on android.',
-                        'Install start for "D" on android.',
-                        'Install start for "A" on android.'
-                    ]);
-                });
-            });
-
-            it('should process all dependent plugins with alternate routes to the same plugin', function() {
-                // Plugin F depends on A, C, D and E
-                runs(function () {
-                    installPromise(install('android', project, plugins['F'], plugins_install_dir, { browserify: true }));
-                });
-                waitsFor(function () { return done; }, 'install promise never resolved', 200);
-                runs(function () {
-                    var install = common.spy.getInstall(emit);
-
-                    expect(install).toEqual([
-                        'Install start for "C" on android.',
-                        'Install start for "D" on android.',
-                        'Install start for "A" on android.',
-                        'Install start for "D" on android.',
-                        'Install start for "F" on android.'
-                    ]);
-                });
-            });
-
-            it('should throw if there is a cyclic dependency', function() {
-                runs(function () {
-                    installPromise( install('android', project, plugins['G'], plugins_install_dir, { browserify: true }) );
-                });
-                waitsFor(function () { return done; }, 'install promise never resolved', 200);
-                runs(function () {
-                    common.spy.getInstall(emit);
-
-                    expect(done.message).toEqual('Cyclic dependency from G to H');
-                });
-            });
-
-            it('install subdir relative to top level plugin if no fetch meta', function() {
-                runs(function () {
-                    installPromise(install('android', project, plugins['B'], plugins_install_dir, { browserify: true }));
-                });
-                waitsFor(function () { return done; }, 'install promise never resolved', 200);
-                runs(function () {
-                    var install = common.spy.getInstall(emit);
-
-                    expect(install).toEqual([
-                        'Install start for "D" on android.',
-                        'Install start for "E" on android.',
-                        'Install start for "B" on android.'
-                    ]);
-                });
-            });
-
-            it('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').andCallFake(function(){
-                    return {
-                        source: {type: 'dir', url: path.join(plugins['B'], '..', 'meta')}
-                    };
-                });
-
-                runs(function () {
-                    installPromise(install('android', project, plugins['B'], plugins_install_dir, { browserify: true }));
-                });
-                waitsFor(function () { return done; }, 'install promise never resolved', 200);
-                runs(function () {
-                    var install = common.spy.getInstall(emit);
-
-                    expect(install).toEqual([
-                        'Install start for "D" on android.',
-                        'Install start for "E" on android.',
-                        'Install start for "B" on android.'
-                    ]);
-
-                    var copy = common.spy.startsWith(emit, 'Copying from');
-                    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);
-                });
-            });
-        });
-
-    });
-
-    describe('failure', function() {
-        it('should throw if platform is unrecognized', function() {
-            runs(function() {
-                installPromise( install('atari', project, 'SomePlugin', plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toContain('atari not supported.');
-            });
-        });
-        it('should throw if variables are missing', function() {
-            runs(function() {
-                installPromise( install('android', project, plugins['com.adobe.vars'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function(){ return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toContain('Variable(s) missing: API_KEY');
-            });
-        });
-         it('should not throw exception on default variables', function() {
-            runs(function() {
-                installPromise( install('android', project, plugins['org.test.defaultvariables'], plugins_install_dir, { browserify: true , cli_variables:{API_KEY:'del7a' }}) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toEqual('true');
-            });
-        });
-        it('should throw if git is not found on the path and a remote url is requested', function() {
-            spyOn(fs, 'existsSync').andCallFake( fake['existsSync']['noPlugins'] );
-            fetchSpy.andCallThrough();
-            spyOn(shell, 'which').andReturn(null);
-            runs(function() {
-                installPromise( install('android', project, 'https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git', plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function(){ return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toContain('"git" command line tool is not installed: make sure it is accessible on your PATH.');
-            });
-        });
-        it('should not fail if plugin version is less than the minimum requirement. Instead skip.', function(){
-            spyOn(semver, 'satisfies').andReturn(false);
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '0.0.1\n');
-            });
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function(){ return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toMatch(true);
-            });
-        });
-    });
-
-});
-
-// When run using 'npm test', the removal of temp_dir is causing
-// tests in 'install.spec.js' to fail.
-
-// describe('end', function() {
-
-//     it('end', function() {
-//         done = false;
-
-//         promise.fin(function(err){
-//             if(err)
-//                 events.emit('error', err);
-
-//             shell.rm('-rf', temp_dir);
-//             done = true;
-//         });
-
-//         waitsFor(function() { return done; }, 'promise never resolved', 500);
-//     });
-// });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/install.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/install.spec.js b/cordova-lib/spec-plugman/install.spec.js
index c50e907..6da5767 100644
--- a/cordova-lib/spec-plugman/install.spec.js
+++ b/cordova-lib/spec-plugman/install.spec.js
@@ -21,6 +21,8 @@
 
 var install = require('../src/plugman/install'),
     actions = require('../src/plugman/util/action-stack'),
+    xmlHelpers = require('../src/util/xml-helpers'),
+    et      = require('elementtree'),
     PlatformJson = require('../src/plugman/util/PlatformJson'),
     events  = require('../src/events'),
     plugman = require('../src/plugman/plugman'),
@@ -55,7 +57,6 @@ var install = require('../src/plugman/install'),
     },
     promise,
     results = {},
-    dummy_id = 'org.test.plugins.dummyplugin',
     superspawn = require('../src/cordova/superspawn');
 
 
@@ -90,15 +91,38 @@ var fake = {
     }
 };
 
+var TEST_XML = '<?xml version="1.0" encoding="UTF-8"?>\n' +
+    '<widget xmlns     = "http://www.w3.org/ns/widgets"\n' +
+    '        xmlns:cdv = "http://cordova.apache.org/ns/1.0"\n' +
+    '        id        = "io.cordova.hellocordova"\n' +
+    '        version   = "0.0.1">\n' +
+    '    <name>Hello Cordova</name>\n' +
+    '    <description>\n' +
+    '        A sample Apache Cordova application that responds to the deviceready event.\n' +
+    '    </description>\n' +
+    '    <author href="http://cordova.io" email="dev@cordova.apache.org">\n' +
+    '        Apache Cordova Team\n' +
+    '    </author>\n' +
+    '    <content src="index.html" />\n' +
+    '    <access origin="*" />\n' +
+    '    <preference name="fullscreen" value="true" />\n' +
+    '    <preference name="webviewbounce" value="true" />\n' +
+    '</widget>\n';
+
 describe('start', function() {
-    var prepare, config_queue_add, proc, actions_push, ca, emit;
+    var config_queue_add, proc, actions_push, ca, emit;
 
     beforeEach(function() {
-        prepare = spyOn(plugman, 'prepare');
         config_queue_add = spyOn(PlatformJson.prototype, 'addInstalledPluginToPrepareQueue');
         proc = spyOn(actions.prototype, 'process').andReturn( Q(true) );
         actions_push = spyOn(actions.prototype, 'push');
         ca = spyOn(actions.prototype, 'createAction');
+
+        var origParseElementtreeSync = xmlHelpers.parseElementtreeSync.bind(xmlHelpers);
+        spyOn(xmlHelpers, 'parseElementtreeSync').andCallFake(function(path) {
+            if (/config.xml$/.test(path)) return new et.ElementTree(et.XML(TEST_XML));
+            return origParseElementtreeSync(path);
+        });
     });
     it('start', function() {
         shell.rm('-rf', project);
@@ -107,7 +131,9 @@ describe('start', function() {
         done = false;
         promise = Q()
          .then(
-            function(){ return install('android', project, plugins['org.test.plugins.dummyplugin']); }
+            function(){
+                return install('android', project, plugins['org.test.plugins.dummyplugin']);
+            }
         ).then(
             function(){
                 results['actions_callCount'] = actions_push.callCount;
@@ -134,7 +160,6 @@ describe('start', function() {
         ).then(
             function(){
                 done = true;
-                results['prepareCount'] = prepare.callCount;
                 results['emit_results'] = [];
 
                 for(var i in emit.calls) {
@@ -154,11 +179,10 @@ describe('start', function() {
 });
 
 describe('install', function() {
-    var chmod, exec, add_to_queue, prepare, cp, rm, fetchSpy;
+    var chmod, exec, add_to_queue, cp, rm, fetchSpy;
     var spawnSpy;
 
     beforeEach(function() {
-        prepare = spyOn(plugman, 'prepare').andReturn( Q(true) );
 
         exec = spyOn(child_process, 'exec').andCallFake(function(cmd, cb) {
             cb(false, '', '');
@@ -178,10 +202,6 @@ describe('install', function() {
     });
 
     describe('success', function() {
-        it('should call prepare after a successful install', function() {
-           expect(results['prepareCount']).toBe(5);
-        });
-
         it('should emit a results event with platform-agnostic <info>', function() {
             // org.test.plugins.childbrowser
             expect(results['emit_results'][0]).toBe('No matter what platform you are installing to, this notice is very important.');
@@ -194,7 +214,6 @@ describe('install', function() {
             // VariableBrowser
             expect(results['emit_results'][2]).toBe('Remember that your api key is batman!');
         });
-
         it('should call fetch if provided plugin cannot be resolved locally', function() {
             fetchSpy.andReturn( Q( plugins['org.test.plugins.dummyplugin'] ) );
             spyOn(fs, 'existsSync').andCallFake( fake['existsSync']['noPlugins'] );
@@ -209,102 +228,80 @@ describe('install', function() {
             });
         });
 
-        it('should call the config-changes module\'s add_installed_plugin_to_prepare_queue method after processing an install', function() {
-           expect(results['config_add']).toEqual([dummy_id, {}, true]);
-        });
-        it('should queue up actions as appropriate for that plugin and call process on the action stack',
-           function() {
-                expect(results['actions_callCount']).toEqual(6);
-                expect(results['actions_create']).toEqual([jasmine.any(Function), [jasmine.any(Object), path.join(plugins_install_dir, dummy_id), dummy_id, jasmine.any(Object)], jasmine.any(Function), [jasmine.any(Object), dummy_id, jasmine.any(Object)]]);
-        });
-
-        it('should check version if plugin has engine tag', function(){
-            var satisfies = spyOn(semver, 'satisfies').andReturn(true);
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '2.5.0\n');
-            });
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine']) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(satisfies).toHaveBeenCalledWith('2.5.0','>=2.3.0');
-            });
-        });
-        it('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() {
-            var satisfies = spyOn(semver, 'satisfies').andReturn(true);
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '3.0.0rc1\n');
-            });
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine']) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(satisfies).toHaveBeenCalledWith('3.0.0-rc1','>=2.3.0');
-            });
-        });
-        it('should check specific platform version over cordova version if specified', function() {
-            var spy = spyOn(semver, 'satisfies').andReturn(true);
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '3.1.0\n');
-            });
-            fetchSpy.andReturn( Q( plugins['com.cordova.engine-android'] ) );
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine-android']) );
-            });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(spy).toHaveBeenCalledWith('3.1.0','>=3.1.0');
+        describe('engine versions', function () {
+            var fail, satisfies;
+            beforeEach(function () {
+                fail = jasmine.createSpy('fail');
+                satisfies = spyOn(semver, 'satisfies').andReturn(true);
+                spyOn(PlatformJson.prototype, 'isPluginInstalled').andReturn(false);
+            });
+
+            it('should check version if plugin has engine tag', function(done){
+                exec.andCallFake(function(cmd, cb) { cb(null, '2.5.0\n'); });
+                install('android', project, plugins['com.cordova.engine'])
+                .fail(fail)
+                .fin(function () {
+                    expect(satisfies).toHaveBeenCalledWith('2.5.0','>=2.3.0');
+                    done();
+                });
             });
-        });
-        it('should check platform sdk version if specified', function() {
-            var spy = spyOn(semver, 'satisfies').andReturn(true);
-            fetchSpy.andReturn( Q( plugins['com.cordova.engine-android'] ) );
-            exec.andCallFake(function(cmd, cb) {
-                cb(null, '18\n');
+            it('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) {
+                exec.andCallFake(function(cmd, cb) { cb(null, '3.0.0rc1\n'); });
+                install('android', project, plugins['com.cordova.engine'])
+                .fail(fail)
+                .fin(function () {
+                    expect(satisfies).toHaveBeenCalledWith('3.0.0-rc1','>=2.3.0');
+                    done();
+                });
             });
-
-            runs(function() {
-                installPromise( install('android', project, 'com.cordova.engine-android') );
+            it('should check specific platform version over cordova version if specified', function(done) {
+                exec.andCallFake(function(cmd, cb) { cb(null, '3.1.0\n'); });
+                install('android', project, plugins['com.cordova.engine-android'])
+                .fail(fail)
+                .fin(function() {
+                    expect(satisfies).toHaveBeenCalledWith('3.1.0','>=3.1.0');
+                    done();
+                });
             });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                // <engine name="cordova" VERSION=">=3.0.0"/>
-                // <engine name="cordova-android" VERSION=">=3.1.0"/>
-                // <engine name="android-sdk" VERSION=">=18"/>
-
-                expect(spy.calls.length).toBe(3);
-                expect(spy.calls[0].args).toEqual([ '18.0.0', '>=3.0.0' ]);
-                expect(spy.calls[1].args).toEqual([ '18.0.0', '>=3.1.0' ]);
-                expect(spy.calls[2].args).toEqual([ '18.0.0','>=18' ]);
+            it('should check platform sdk version if specified', function(done) {
+                exec.andCallFake(function(cmd, cb) { cb(null, '18\n'); });
+                install('android', project, plugins['com.cordova.engine-android'])
+                .fail(fail)
+                .fin(function() {
+                    expect(satisfies.calls.length).toBe(3);
+                    // <engine name="cordova" VERSION=">=3.0.0"/>
+                    expect(satisfies.calls[0].args).toEqual([ '18.0.0', '>=3.0.0' ]);
+                    // <engine name="cordova-android" VERSION=">=3.1.0"/>
+                    expect(satisfies.calls[1].args).toEqual([ '18.0.0', '>=3.1.0' ]);
+                    // <engine name="android-sdk" VERSION=">=18"/>
+                    expect(satisfies.calls[2].args).toEqual([ '18.0.0','>=18' ]);
+                    done();
+                });
             });
-        });
-        it('should check engine versions', function() {
-            var spy = spyOn(semver, 'satisfies').andReturn(true);
-            fetchSpy.andReturn( Q( plugins['com.cordova.engine'] ) );
-
-            runs(function() {
-                installPromise( install('android', project, plugins['com.cordova.engine']) );
+            it('should check engine versions', function(done) {
+                install('android', project, plugins['com.cordova.engine'])
+                .fail(fail)
+                .fin(function() {
+                    var plugmanVersion = require('../package.json').version.replace('-dev', '');
+                    expect(satisfies.calls.length).toBe(4);
+                    // <engine name="cordova" version=">=2.3.0"/>
+                    expect(satisfies.calls[0].args).toEqual([ null, '>=2.3.0' ]);
+                    // <engine name="cordova-plugman" version=">=0.10.0" />
+                    expect(satisfies.calls[1].args).toEqual([ plugmanVersion, '>=0.10.0' ]);
+                    // <engine name="mega-fun-plugin" version=">=1.0.0" scriptSrc="megaFunVersion" platform="*" />
+                    expect(satisfies.calls[2].args).toEqual([ null, '>=1.0.0' ]);
+                    // <engine name="mega-boring-plugin" version=">=3.0.0" scriptSrc="megaBoringVersion" platform="ios|android" />
+                    expect(satisfies.calls[3].args).toEqual([ null, '>=3.0.0' ]);
+                    done();
+                });
             });
-            waitsFor(function() { return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                // <engine name="cordova" version=">=2.3.0"/>
-                // <engine name="cordova-plugman" version=">=0.10.0" />
-                // <engine name="mega-fun-plugin" version=">=1.0.0" scriptSrc="megaFunVersion" platform="*" />
-                // <engine name="mega-boring-plugin" version=">=3.0.0" scriptSrc="megaBoringVersion" platform="ios|android" />
-
-                var plugmanVersion = require('../package.json').version;
-                plugmanVersion = plugmanVersion.replace(/-dev$/, '');
-
-                expect(spy.calls.length).toBe(4);
-                expect(spy.calls[0].args).toEqual([ null, '>=2.3.0' ]);
-                expect(spy.calls[1].args).toEqual([ plugmanVersion, '>=0.10.0' ]);
-                expect(spy.calls[2].args).toEqual([ null, '>=1.0.0' ]);
-                expect(spy.calls[3].args).toEqual([ null, '>=3.0.0' ]);
+            it('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 () {
+                    expect(satisfies).not.toHaveBeenCalledWith('','>=3.0.0');
+                })
+                .fin(done);
             });
         });
         it('should not check custom engine version that is not supported for platform', function() {
@@ -440,7 +437,6 @@ describe('install', function() {
                 });
             });
         });
-
     });
 
     describe('failure', function() {
@@ -453,13 +449,17 @@ describe('install', function() {
                 expect(''+done).toContain('atari not supported.');
             });
         });
-        it('should throw if variables are missing', function() {
-            runs(function() {
-                installPromise( install('android', project, plugins['com.adobe.vars']) );
-            });
-            waitsFor(function(){ return done; }, 'install promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toContain('Variable(s) missing: API_KEY');
+        it('should throw if variables are missing', function(done) {
+            var success = jasmine.createSpy('success');
+            spyOn(PlatformJson.prototype, 'isPluginInstalled').andReturn(false);
+            install('android', project, plugins['com.adobe.vars'])
+            .then(success)
+            .fail(function (err) {
+                expect(err).toContain('Variable(s) missing: API_KEY');
+            })
+            .fin(function () {
+                expect(success).not.toHaveBeenCalled();
+                done();
             });
         });
         it('should throw if git is not found on the path and a remote url is requested', function() {
@@ -488,10 +488,8 @@ describe('install', function() {
             });
         });
     });
-
 });
 
-
 describe('end', function() {
 
     it('end', function() {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/prepare.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/prepare.spec.js b/cordova-lib/spec-plugman/prepare.spec.js
deleted file mode 100644
index c3ff707..0000000
--- a/cordova-lib/spec-plugman/prepare.spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-*/
-var prepare = require('../src/plugman/prepare'),
-    common  = require('../src/plugman/platforms/common'),
-    fs      = require('fs'),
-    path    = require('path'),
-    shell   = require('shelljs'),
-    config_changes = require('../src/plugman/util/config-changes'),
-    PlatformJson = require('../src/plugman/util/PlatformJson'),
-    temp    = __dirname,
-    plugins_dir = path.join(temp, 'plugins');
-
-describe('prepare', function() {
-    var proc, platform_json, write, mkdir, rm;
-    beforeEach(function() {
-        rm = spyOn(shell, 'rm');
-        mkdir = spyOn(shell, 'mkdir');
-        proc = spyOn(config_changes, 'process');
-        platform_json = spyOn(PlatformJson, 'load').andReturn(new PlatformJson(null, null, {installed_plugins:{},dependent_plugins:{},prepare_queue:{uninstalled:[]}}));
-        write = spyOn(fs, 'writeFileSync');
-    });
-    it('should create cordova_plugins.js file in a custom www directory', function() {
-        var custom_www = path.join(temp, 'assets', 'custom_www'),
-            js = path.join(temp, 'assets', 'custom_www', 'cordova_plugins.js');
-        prepare(temp, 'android', plugins_dir, custom_www);
-        expect(write).toHaveBeenCalledWith(js, jasmine.any(String), 'utf-8');
-    });
-    describe('handling of js-modules', function() {
-        var copySpy;
-        beforeEach(function() {
-            copySpy = spyOn(common, 'copyFile');
-            platform_json.andReturn(new PlatformJson(null, null, {
-                installed_plugins: {plugin_one: '', plugin_two: ''},
-                dependent_plugins: {}, prepare_queue: {uninstalled:[]}
-            }));
-        });
-        describe('uninstallation/removal', function() {
-            var existsSync;
-            beforeEach(function() {
-                existsSync = spyOn(fs, 'existsSync').andReturn(true);
-                platform_json.andReturn(new PlatformJson(null, null, {installed_plugins:{},dependent_plugins:{},prepare_queue:{uninstalled:[{
-                    plugin:'nickelback',
-                    id:'nickelback',
-                    topLevel:true
-                }]}}));
-            });
-            it('should remove any www/plugins directories related to plugins being queued for removal', function() {
-                prepare(temp, 'android', plugins_dir);
-                expect(rm).toHaveBeenCalledWith('-rf', path.join(temp, 'assets', 'www', 'plugins', 'nickelback'));
-            });
-        });
-    });
-    it('should call into config-changes\' process method to do config processing', function() {
-        prepare(temp, 'android', plugins_dir);
-        expect(proc).toHaveBeenCalledWith(plugins_dir, temp, 'android', jasmine.any(Object), jasmine.any(Object));
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/projects/wp8/config.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/wp8/config.xml b/cordova-lib/spec-plugman/projects/wp8/config.xml
new file mode 100644
index 0000000..c08b522
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/wp8/config.xml
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="io.cordova.cordovaapp" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>CordovaApp</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/uninstall-browserify.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/uninstall-browserify.spec.js b/cordova-lib/spec-plugman/uninstall-browserify.spec.js
deleted file mode 100644
index d68b0a6..0000000
--- a/cordova-lib/spec-plugman/uninstall-browserify.spec.js
+++ /dev/null
@@ -1,315 +0,0 @@
-/**
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-*/
-
-/* jshint sub:true */
-
-var uninstall = require('../src/plugman/uninstall'),
-    install = require('../src/plugman/install'),
-    actions = require('../src/plugman/util/action-stack'),
-    PlatformJson = require('../src/plugman/util/PlatformJson'),
-    events  = require('../src/events'),
-    plugman = require('../src/plugman/plugman'),
-    common  = require('./common'),
-    fs      = require('fs'),
-    path    = require('path'),
-    shell   = require('shelljs'),
-    Q       = require('q'),
-    spec    = __dirname,
-    done    = false,
-    srcProject = path.join(spec, 'projects', 'android_uninstall'),
-    project = path.join(spec, 'projects', 'android_uninstall.test'),
-    project2 = path.join(spec, 'projects', 'android_uninstall.test2'),
-
-    plugins_dir = path.join(spec, 'plugins'),
-    plugins_install_dir = path.join(project, 'cordova', 'plugins'),
-    plugins_install_dir2 = path.join(project2, 'cordova', 'plugins'),
-
-    plugins = {
-        'org.test.plugins.dummyplugin' : path.join(plugins_dir, 'org.test.plugins.dummyplugin'),
-        'A' : path.join(plugins_dir, 'dependencies', 'A'),
-        'C' : path.join(plugins_dir, 'dependencies', 'C')
-    },
-    promise,
-    dummy_id = 'org.test.plugins.dummyplugin';
-
-function uninstallPromise(f) {
-    return f.then(function() { done = true; }, function(err) { done = err; });
-}
-
-describe('start', function() {
-
-    it('start', function() {
-        shell.rm('-rf', project);
-        shell.rm('-rf', project2);
-        shell.cp('-R', path.join(srcProject, '*'), project);
-        shell.cp('-R', path.join(srcProject, '*'), project2);
-
-        done = false;
-        promise = Q()
-        .then(
-            function(){ return install('android', project, plugins['org.test.plugins.dummyplugin'], plugins_install_dir, { browserify: true }); }
-        ).then(
-            function(){ return install('android', project, plugins['A'], plugins_install_dir, { browserify: true }); }
-        ).then(
-            function(){ return install('android', project2, plugins['C'], plugins_install_dir2, { browserify: true }); }
-        ).then(
-            function(){ return install('android', project2, plugins['A'], plugins_install_dir2, { browserify: true }); }
-        ).then(
-            function(){ done = true; }
-        ).fail(function(err) {
-            done = err.stack;
-        });
-        waitsFor(function() { return done; }, 'promise never resolved', 5000);
-        runs(function() {
-            expect(done).toBe(true);
-        });
-    });
-});
-
-describe('uninstallPlatform', function() {
-    var proc, prepare, prepareBrowserify, actions_push, add_to_queue, c_a, rm;
-    var fsWrite;
-
-    beforeEach(function() {
-        proc = spyOn(actions.prototype, 'process').andReturn(Q());
-        actions_push = spyOn(actions.prototype, 'push');
-        c_a = spyOn(actions.prototype, 'createAction');
-        prepare = spyOn(plugman, 'prepare');
-        prepareBrowserify = spyOn(plugman, 'prepareBrowserify');
-        fsWrite = spyOn(fs, 'writeFileSync').andReturn(true);
-        rm = spyOn(shell, 'rm').andReturn(true);
-        spyOn(shell, 'cp').andReturn(true);
-        add_to_queue = spyOn(PlatformJson.prototype, 'addUninstalledPluginToPrepareQueue');
-        done = false;
-    });
-    describe('success', function() {
-        it('should call prepare after a successful uninstall', function() {
-            runs(function() {
-                uninstallPromise(uninstall.uninstallPlatform('android', project, dummy_id, plugins_install_dir, { browserify: true }));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(prepareBrowserify).toHaveBeenCalled();
-            });
-        });
-        it('should call the config-changes module\'s add_uninstalled_plugin_to_prepare_queue method after processing an install', function() {
-            runs(function() {
-                uninstallPromise(uninstall.uninstallPlatform('android', project, dummy_id, plugins_install_dir, { browserify: true }));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(add_to_queue).toHaveBeenCalledWith(dummy_id, true);
-            });
-        });
-        it('should queue up actions as appropriate for that plugin and call process on the action stack', function() {
-            runs(function() {
-                uninstallPromise(uninstall.uninstallPlatform('android', project, dummy_id, plugins_install_dir, { browserify: true }));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(actions_push.calls.length).toEqual(6);
-                expect(proc).toHaveBeenCalled();
-            });
-        });
-
-        describe('with dependencies', function() {
-            var emit;
-            beforeEach(function() {
-                emit = spyOn(events, 'emit');
-            });
-            it('should uninstall "dangling" dependencies', function() {
-                runs(function() {
-                    uninstallPromise(uninstall.uninstallPlatform('android', project, 'A', plugins_install_dir, { browserify: true }));
-                });
-                waitsFor(function() { return done; }, 'promise never resolved', 200);
-                runs(function() {
-                    expect(emit).toHaveBeenCalledWith('log', 'Uninstalling 2 dependent plugins.');
-                });
-            });
-        });
-    });
-
-    describe('failure', function() {
-        it('should throw if platform is unrecognized', function() {
-            runs(function() {
-                uninstallPromise( uninstall.uninstallPlatform('atari', project, 'SomePlugin', plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toContain('atari not supported.');
-            });
-        });
-        it('should throw if plugin is missing', function() {
-            runs(function() {
-                uninstallPromise( uninstall.uninstallPlatform('android', project, 'SomePluginThatDoesntExist', plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(''+done).toContain('Plugin "SomePluginThatDoesntExist" not found. Already uninstalled?');
-            });
-        });
-    });
-});
-
-describe('uninstallPlugin', function() {
-    var rm, fsWrite, rmstack = [], emit;
-
-    beforeEach(function() {
-        fsWrite = spyOn(fs, 'writeFileSync').andReturn(true);
-        rm = spyOn(shell, 'rm').andCallFake(function(f,p) { rmstack.push(p); return true; });
-        rmstack = [];
-        emit = spyOn(events, 'emit');
-        done = false;
-    });
-    describe('with dependencies', function() {
-
-        it('should delete all dependent plugins', function() {
-            runs(function() {
-                uninstallPromise( uninstall.uninstallPlugin('A', plugins_install_dir, {browserify: true}) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                var del = common.spy.getDeleted(emit);
-
-                expect(del).toEqual([
-                    'Deleted "C"',
-                    'Deleted "D"',
-                    'Deleted "A"'
-                ]);
-            });
-        });
-
-        it('should fail if plugin is a required dependency', function() {
-            runs(function() {
-                uninstallPromise( uninstall.uninstallPlugin('C', plugins_install_dir, {browserify: true}) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(done.message).toBe('"C" is required by (A) and cannot be removed (hint: use -f or --force)');
-            });
-        });
-
-        it('allow forcefully removing a plugin', function() {
-            runs(function() {
-                uninstallPromise( uninstall.uninstallPlugin('C', plugins_install_dir, {browserify: true, force: true}) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(done).toBe(true);
-                var del = common.spy.getDeleted(emit);
-                expect(del).toEqual(['Deleted "C"']);
-            });
-        });
-
-        it('never remove top level plugins if they are a dependency', function() {
-            runs(function() {
-                uninstallPromise( uninstall.uninstallPlugin('A', plugins_install_dir2, {browserify: true}) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                var del = common.spy.getDeleted(emit);
-
-                expect(del).toEqual([
-                    'Deleted "D"',
-                    'Deleted "A"'
-                ]);
-            });
-        });
-    });
-});
-
-describe('uninstall', function() {
-    var fsWrite, rm, add_to_queue;
-
-    beforeEach(function() {
-        fsWrite = spyOn(fs, 'writeFileSync').andReturn(true);
-        rm = spyOn(shell, 'rm').andReturn(true);
-        add_to_queue = spyOn(PlatformJson.prototype, 'addUninstalledPluginToPrepareQueue');
-        done = false;
-    });
-    describe('success', function() {
-        it('should call the config-changes module\'s add_uninstalled_plugin_to_prepare_queue method after processing an install', function() {
-            runs(function() {
-                uninstallPromise( uninstall('android', project, plugins['org.test.plugins.dummyplugin'], plugins_install_dir, { browserify: true }) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 500);
-            runs(function() {
-                expect(add_to_queue).toHaveBeenCalledWith(dummy_id, true);
-            });
-        });
-    });
-
-    describe('failure', function() {
-        it('should throw if platform is unrecognized', function() {
-            runs(function() {
-                uninstallPromise(uninstall('atari', project, 'SomePlugin', plugins_install_dir, { browserify: true }));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 500);
-            runs(function() {
-                expect(''+done).toContain('atari not supported.');
-            });
-        });
-        it('should throw if plugin is missing', function() {
-            runs(function() {
-                uninstallPromise(uninstall('android', project, 'SomePluginThatDoesntExist', plugins_install_dir, { browserify: true }));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 500);
-            runs(function() {
-                expect(''+done).toContain('Plugin "SomePluginThatDoesntExist" not found. Already uninstalled?');
-            });
-        });
-    });
-});
-
-describe('end', function() {
-
-    it('end', function() {
-        done = false;
-
-        promise.then(
-            function(){
-                return uninstall('android', project, plugins['org.test.plugins.dummyplugin'], plugins_install_dir, { browserify: true });
-            }
-        ).then(
-            function(){
-                // Fails... A depends on
-                return uninstall('android', project, plugins['C'], plugins_install_dir, { browserify: true });
-            }
-        ).fail(
-            function(err) {
-                expect(err.message).toBe('The plugin \'C\' is required by (A), skipping uninstallation.');
-            }
-        ).then(
-            function(){
-                // dependencies on C,D ... should this only work with --recursive? prompt user..?
-                return uninstall('android', project, plugins['A'], plugins_install_dir, { browserify: true });
-            }
-        ).fin(function(err){
-            if(err)
-                plugman.emit('error', err);
-
-            shell.rm('-rf', project);
-            shell.rm('-rf', project2);
-            done = true;
-        });
-
-        waitsFor(function() { return done; }, 'promise never resolved', 1500);
-    });
-});
-

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/uninstall.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/uninstall.spec.js b/cordova-lib/spec-plugman/uninstall.spec.js
index 264d8b9..63f1ff2 100644
--- a/cordova-lib/spec-plugman/uninstall.spec.js
+++ b/cordova-lib/spec-plugman/uninstall.spec.js
@@ -22,10 +22,12 @@
 var uninstall = require('../src/plugman/uninstall'),
     install = require('../src/plugman/install'),
     actions = require('../src/plugman/util/action-stack'),
-    PlatformJson = require('../src/plugman/util/PlatformJson'),
     events  = require('../src/events'),
     plugman = require('../src/plugman/plugman'),
     common  = require('./common'),
+    platforms = require('../src/platforms/platforms'),
+    xmlHelpers = require('../src/util/xml-helpers'),
+    et      = require('elementtree'),
     fs      = require('fs'),
     path    = require('path'),
     shell   = require('shelljs'),
@@ -50,11 +52,34 @@ var uninstall = require('../src/plugman/uninstall'),
     promise,
     dummy_id = 'org.test.plugins.dummyplugin';
 
+var TEST_XML = '<?xml version="1.0" encoding="UTF-8"?>\n' +
+    '<widget xmlns     = "http://www.w3.org/ns/widgets"\n' +
+    '        xmlns:cdv = "http://cordova.apache.org/ns/1.0"\n' +
+    '        id        = "io.cordova.hellocordova"\n' +
+    '        version   = "0.0.1">\n' +
+    '    <name>Hello Cordova</name>\n' +
+    '    <description>\n' +
+    '        A sample Apache Cordova application that responds to the deviceready event.\n' +
+    '    </description>\n' +
+    '    <author href="http://cordova.io" email="dev@cordova.apache.org">\n' +
+    '        Apache Cordova Team\n' +
+    '    </author>\n' +
+    '    <content src="index.html" />\n' +
+    '    <access origin="*" />\n' +
+    '</widget>\n';
+
 function uninstallPromise(f) {
     return f.then(function() { done = true; }, function(err) { done = err; });
 }
 
 describe('start', function() {
+    beforeEach(function () {
+        var origParseElementtreeSync = xmlHelpers.parseElementtreeSync.bind(xmlHelpers);
+        spyOn(xmlHelpers, 'parseElementtreeSync').andCallFake(function(path) {
+            if (/config.xml$/.test(path)) return new et.ElementTree(et.XML(TEST_XML));
+            return origParseElementtreeSync(path);
+        });
+    });
 
     it('start', function() {
         shell.rm('-rf', project, project2, project3);
@@ -89,48 +114,29 @@ describe('start', function() {
 });
 
 describe('uninstallPlatform', function() {
-    var proc, prepare, actions_push, add_to_queue, c_a, rm;
+    var proc, rm;
     var fsWrite;
 
     beforeEach(function() {
         proc = spyOn(actions.prototype, 'process').andReturn(Q());
-        actions_push = spyOn(actions.prototype, 'push');
-        c_a = spyOn(actions.prototype, 'createAction');
-        prepare = spyOn(plugman, 'prepare');
         fsWrite = spyOn(fs, 'writeFileSync').andReturn(true);
         rm = spyOn(shell, 'rm').andReturn(true);
         spyOn(shell, 'cp').andReturn(true);
-        add_to_queue = spyOn(PlatformJson.prototype, 'addUninstalledPluginToPrepareQueue');
         done = false;
     });
     describe('success', function() {
-        it('should call prepare after a successful uninstall', function() {
-            runs(function() {
-                uninstallPromise(uninstall.uninstallPlatform('android', project, dummy_id));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(prepare).toHaveBeenCalled();
-            });
-        });
-        it('should call the config-changes module\'s add_uninstalled_plugin_to_prepare_queue method after processing an install', function() {
-            runs(function() {
-                uninstallPromise(uninstall.uninstallPlatform('android', project, dummy_id));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(add_to_queue).toHaveBeenCalledWith(dummy_id, true);
-            });
-        });
-        it('should queue up actions as appropriate for that plugin and call process on the action stack', function() {
-            runs(function() {
-                uninstallPromise(uninstall.uninstallPlatform('android', project, dummy_id));
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(actions_push.calls.length).toEqual(6);
-                expect(proc).toHaveBeenCalled();
-            });
+
+        it('should get PlatformApi instance for platform and invoke its\' removePlugin method', function(done) {
+            var platformApi = { removePlugin: jasmine.createSpy('removePlugin').andReturn(Q()) };
+            var getPlatformApi = spyOn(platforms, 'getPlatformApi').andReturn(platformApi);
+
+            uninstall.uninstallPlatform('android', project, dummy_id)
+            .then(function() {
+                expect(getPlatformApi).toHaveBeenCalledWith('android', project);
+                expect(platformApi.removePlugin).toHaveBeenCalled();
+            }, function(err) {
+                expect(err).toBeUndefined();
+            }).fin(done);
         });
 
         describe('with dependencies', function() {
@@ -255,25 +261,13 @@ describe('uninstallPlugin', function() {
 });
 
 describe('uninstall', function() {
-    var fsWrite, rm, add_to_queue;
+    var fsWrite, rm;
 
     beforeEach(function() {
         fsWrite = spyOn(fs, 'writeFileSync').andReturn(true);
         rm = spyOn(shell, 'rm').andReturn(true);
-        add_to_queue = spyOn(PlatformJson.prototype, 'addUninstalledPluginToPrepareQueue');
         done = false;
     });
-    describe('success', function() {
-        it('should call the config-changes module\'s add_uninstalled_plugin_to_prepare_queue method after processing an install', function() {
-            runs(function() {
-                uninstallPromise( uninstall('android', project, plugins['org.test.plugins.dummyplugin']) );
-            });
-            waitsFor(function() { return done; }, 'promise never resolved', 200);
-            runs(function() {
-                expect(add_to_queue).toHaveBeenCalledWith(dummy_id, true);
-            });
-        });
-    });
 
     describe('failure', function() {
         it('should throw if platform is unrecognized', function() {
@@ -298,29 +292,20 @@ describe('uninstall', function() {
 });
 
 describe('end', function() {
-
     it('end', function() {
         done = false;
 
-        promise.then(
-            function(){
-                return uninstall('android', project, plugins['org.test.plugins.dummyplugin']);
-            }
-        ).then(
-            function(){
-                // Fails... A depends on
-                return uninstall('android', project, plugins['C']);
-            }
-        ).fail(
-            function(err) {
-                expect(err.stack).toMatch(/The plugin 'C' is required by \(A\), skipping uninstallation./);
-            }
-        ).then(
-            function(){
-                // dependencies on C,D ... should this only work with --recursive? prompt user..?
-                return uninstall('android', project, plugins['A']);
-            }
-        ).fin(function(err){
+        promise.then(function(){
+            return uninstall('android', project, plugins['org.test.plugins.dummyplugin']);
+        }).then(function(){
+            // Fails... A depends on
+            return uninstall('android', project, plugins['C']);
+        }).fail(function(err) {
+            expect(err.stack).toMatch(/The plugin 'C' is required by \(A\), skipping uninstallation./);
+        }).then(function(){
+            // dependencies on C,D ... should this only work with --recursive? prompt user..?
+            return uninstall('android', project, plugins['A']);
+        }).fin(function(err){
             if(err)
                 plugman.emit('error', err);
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/07271a5c/cordova-lib/spec-plugman/util/action-stack.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/util/action-stack.spec.js b/cordova-lib/spec-plugman/util/action-stack.spec.js
index 5eb4847..c0677ea 100644
--- a/cordova-lib/spec-plugman/util/action-stack.spec.js
+++ b/cordova-lib/spec-plugman/util/action-stack.spec.js
@@ -37,9 +37,9 @@ describe('action-stack', function() {
             stack.push(stack.createAction(second_spy, second_args, function(){}, []));
             stack.push(stack.createAction(third_spy, third_args, function(){}, []));
             stack.process('android', android_one_project);
-            expect(first_spy).toHaveBeenCalledWith(first_args[0], jasmine.any(Object));
-            expect(second_spy).toHaveBeenCalledWith(second_args[0], jasmine.any(Object));
-            expect(third_spy).toHaveBeenCalledWith(third_args[0], jasmine.any(Object));
+            expect(first_spy).toHaveBeenCalledWith(first_args[0]);
+            expect(second_spy).toHaveBeenCalledWith(second_args[0]);
+            expect(third_spy).toHaveBeenCalledWith(third_args[0]);
         });
         it('should revert processed actions if an exception occurs', function() {
             spyOn(console, 'log');
@@ -66,11 +66,11 @@ describe('action-stack', function() {
             runs(function() {
                 expect(error).toEqual(process_err);
                 // first two actions should have been called, but not the third
-                expect(first_spy).toHaveBeenCalledWith(first_args[0], jasmine.any(Object));
-                expect(second_spy).toHaveBeenCalledWith(second_args[0], jasmine.any(Object));
-                expect(third_spy).not.toHaveBeenCalledWith(third_args[0], jasmine.any(Object));
+                expect(first_spy).toHaveBeenCalledWith(first_args[0]);
+                expect(second_spy).toHaveBeenCalledWith(second_args[0]);
+                expect(third_spy).not.toHaveBeenCalledWith(third_args[0]);
                 // first reverter should have been called after second action exploded
-                expect(first_reverter).toHaveBeenCalledWith(first_reverter_args[0], jasmine.any(Object));
+                expect(first_reverter).toHaveBeenCalledWith(first_reverter_args[0]);
             });
         });
     });


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