diff --git a/spec/plugman/install.spec.js b/spec/plugman/install.spec.js index 7d9ca8880..cd5703449 100644 --- a/spec/plugman/install.spec.js +++ b/spec/plugman/install.spec.js @@ -27,6 +27,7 @@ var events = require('cordova-common').events; var plugman = require('../../src/plugman/plugman'); var platforms = require('../../src/plugman/platforms/common'); var knownPlatforms = require('../../src/platforms/platforms'); +var cordovaUtil = require('../../src/cordova/util'); var common = require('../common'); var fs = require('fs'); var os = require('os'); @@ -287,15 +288,12 @@ describe('install', function () { .fin(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); + // var megaFun = require('../../package.json').version.replace(/-dev|-nightly.*$/, ''); + expect(satisfies.calls.count()).toBe(2); // expect(satisfies.calls.argsFor(0)).toEqual([ cordovaVersion, '>=2.3.0', true ]); // expect(satisfies.calls.argsFor(1)).toEqual([ plugmanVersion, '>=0.10.0', true ]); - // - expect(satisfies.calls.argsFor(2)).toEqual([ null, '>=1.0.0', true ]); - // - expect(satisfies.calls.argsFor(3)).toEqual([ null, '>=3.0.0', true ]); done(); }); }, TIMEOUT); @@ -543,3 +541,67 @@ describe('end', function () { shell.rm('-rf', temp_dir); }, TIMEOUT); }); + +describe('unit tests for checkEngines', function () { + var fail; + var engine = [ { platform: 'android', + minVersion: '>=3.6.0', + currentVersion: '6.2.3' } ]; + beforeEach(function () { + spyOn(semver, 'satisfies'); + }); + + it('checkEngines should return true', function () { + spyOn(fs, 'existsSync').and.returnValue(false); + semver.satisfies.and.returnValue(true); + install.checkEngines(engine, 'pluginDir') + .then(function (res) { + expect(res).toBe(true); + }).fail(function err (errMsg) { + fail('fail handler unexpectedly invoked'); + console.error(errMsg); + }); + }); + + it('checkEngines should check cordovaDependencies', function () { + var pkgJson = { engines: { cordovaDependencies: { '9.0.0': [Object], '2.0.0': [Object] } } }; + spyOn(fs, 'existsSync').and.returnValue(true); + spyOn(cordovaUtil, 'requireNoCache').and.returnValue(pkgJson); + semver.satisfies.and.callThrough(); + install.checkEngines(engine, 'pluginDir') + .then(function (res) { + expect(res).toBe(true); + expect(semver.satisfies).toHaveBeenCalledWith('6.2.3', '>=3.6.0', true); + }).fail(function err (errMsg) { + fail('fail handler unexpectedly invoked'); + console.error(errMsg); + }); + }); + + it('checkEngines should check if plugin version is supported', function () { + spyOn(fs, 'existsSync').and.returnValue(true); + spyOn(cordovaUtil, 'requireNoCache').and.returnValue(true); + semver.satisfies.and.callThrough(); + install.checkEngines(engine, 'pluginDir') + .then(function (res) { + expect(res).toBe(true); + expect(semver.satisfies).toHaveBeenCalledWith('6.2.3', '>=3.6.0', true); + }).fail(function err (errMsg) { + fail('fail handler unexpectedly invoked'); + console.error(errMsg); + }); + }); + + it('checkEngines should warn if plugin is not supported', function () { + spyOn(events, 'emit'); + spyOn(Q, 'reject').and.callThrough(); + semver.satisfies.and.returnValue(false); + install.checkEngines(engine, 'pluginDir') + .then(function (res) { + fail('success handler unexpectedly invoked'); + }).fail(function err (errMsg) { + expect(errMsg).toBe('skip'); + expect(events.emit).toHaveBeenCalledWith('warn', jasmine.stringMatching(/failed version requirement/)); + }); + }); +}); diff --git a/src/plugman/install.js b/src/plugman/install.js index 51c6baf74..c54c0d331 100644 --- a/src/plugman/install.js +++ b/src/plugman/install.js @@ -100,33 +100,54 @@ function possiblyFetch (id, plugins_dir, options) { return require('./plugman').fetch(id, plugins_dir, opts); } -function checkEngines (engines) { +function checkEngines (engines, plugin_dir) { + var plugin_pkgJson_path = path.join(plugin_dir, 'package.json'); + var plugin_pkgJson; + + if (fs.existsSync(plugin_pkgJson_path)) { + plugin_pkgJson = cordovaUtil.requireNoCache(plugin_pkgJson_path); + } for (var i = 0; i < engines.length; i++) { var engine = engines[i]; - - // This is a hack to allow plugins with tag to be installed with - // engine with '-dev' or '-nightly' suffixes. It is required due to new semver range logic, - // introduced in semver@3.x. For more details see https://github.com/npm/node-semver#prerelease-tags. - // - // This may lead to false-positive checks, when engine version with dropped - // suffix is equal to one of range bounds, for example: 5.1.0-dev >= 5.1.0. - // However this shouldn't be a problem, because this only should happen in dev workflow. - engine.currentVersion = engine.currentVersion && engine.currentVersion.replace(/-dev|-nightly.*$/, ''); - if (semver.satisfies(engine.currentVersion, engine.minVersion, /* loose= */true) || engine.currentVersion === null) { - continue; // engine ok! - } else { - var msg = 'Plugin doesn\'t support this project\'s ' + engine.name + ' version. ' + - engine.name + ': ' + engine.currentVersion + - ', failed version requirement: ' + engine.minVersion; - events.emit('warn', msg); - return Q.reject('skip'); + if (engine && engine.currentVersion) { + if (plugin_pkgJson && plugin_pkgJson.engines && plugin_pkgJson.engines.cordovaDependencies) { + for (var key in plugin_pkgJson.engines.cordovaDependencies) { + if (plugin_pkgJson.engines.cordovaDependencies.hasOwnProperty(key)) { + if (((key < engine.currentVersion) || (key === engine.currentVersion)) && (plugin_pkgJson.engines.cordovaDependencies[key])) { + var plugin_pkgJson_min = plugin_pkgJson.engines.cordovaDependencies[key]; + if (plugin_pkgJson_min[engine.name]) { + engine.minVersion = plugin_pkgJson_min[engine.name]; + } + } + } + } + // This is a hack to allow plugins with tag to be installed with + // engine with '-dev' or '-nightly' suffixes. It is required due to new semver range logic, + // introduced in semver@3.x. For more details see https://github.com/npm/node-semver#prerelease-tags. + // + // This may lead to false-positive checks, when engine version with dropped + // suffix is equal to one of range bounds, for example: 5.1.0-dev >= 5.1.0. + // However this shouldn't be a problem, because this only should happen in dev workflow. + } + engine.currentVersion = engine.currentVersion && engine.currentVersion.replace(/-dev|-nightly.*$/, ''); + if (semver.satisfies(engine.currentVersion, engine.minVersion, /* loose= */true) || engine.currentVersion === null) { + continue; // engine ok! + } else { + var msg = 'Plugin doesn\'t support this project\'s ' + engine.name + ' version. ' + + engine.name + ': ' + engine.currentVersion + + ', failed version requirement: ' + engine.minVersion; + events.emit('warn', msg); + return Q.reject('skip'); + } } } return Q(true); } +module.exports.checkEngines = checkEngines; + function cleanVersionOutput (version, name) { var out = version.trim(); var rc_index = out.indexOf('rc'); @@ -310,7 +331,7 @@ function runInstall (actions, platform, project_dir, plugin_dir, plugins_dir, op options.platformVersion = platformVersion; return callEngineScripts(theEngines, path.resolve(plugins_dir, '..')); }).then(function (engines) { - return checkEngines(engines); + return module.exports.checkEngines(engines, plugin_dir); }).then(function () { filtered_variables = variableMerge.mergeVariables(plugin_dir, platform, options); install.filtered_variables = filtered_variables;