[BlackBerry10] Implement plugin client script loading via script tag appended to document head.
Reviewed by Rose Tse <r...@blackberry.com> Project: http://git-wip-us.apache.org/repos/asf/cordova-js/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-js/commit/d2f52662 Tree: http://git-wip-us.apache.org/repos/asf/cordova-js/tree/d2f52662 Diff: http://git-wip-us.apache.org/repos/asf/cordova-js/diff/d2f52662 Branch: refs/heads/master Commit: d2f526623bdab447af897b9bc7fc3776d1245a53 Parents: 28084c5 Author: Bryan Higgins <bhigg...@rim.com> Authored: Tue Mar 5 11:46:53 2013 -0500 Committer: Bryan Higgins <bhigg...@blackberry.com> Committed: Fri May 3 09:49:22 2013 -0400 ---------------------------------------------------------------------- lib/blackberry10/plugin/blackberry10/builder.js | 74 ---- .../plugin/blackberry10/pluginUtils.js | 69 ++++ lib/scripts/bootstrap-blackberry10.js | 220 ++++-------- lib/scripts/require.js | 289 +++------------ test/blackberry10/test.builder.js | 121 ------ test/blackberry10/test.pluginUtils.js | 137 +++++++ test/runner.js | 2 +- 7 files changed, 342 insertions(+), 570 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-js/blob/d2f52662/lib/blackberry10/plugin/blackberry10/builder.js ---------------------------------------------------------------------- diff --git a/lib/blackberry10/plugin/blackberry10/builder.js b/lib/blackberry10/plugin/blackberry10/builder.js deleted file mode 100644 index 9271c58..0000000 --- a/lib/blackberry10/plugin/blackberry10/builder.js +++ /dev/null @@ -1,74 +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 utils = require("cordova/plugin/blackberry10/utils"); - -function buildNamespace(currentNamespace, namespaceParts, featureProperties) { - var featureId, - nextPart; - - if (namespaceParts.length === 1) { - //base case, feature properties go here - featureId = namespaceParts[0]; - if (currentNamespace[featureId] === undefined) { - currentNamespace[featureId] = {}; - } - - currentNamespace = utils.mixin(featureProperties, currentNamespace[featureId]); - return currentNamespace; - } - else { - nextPart = namespaceParts.shift(); - if (currentNamespace[nextPart] === undefined) { - currentNamespace[nextPart] = {}; - } - - return buildNamespace(currentNamespace[nextPart], namespaceParts, featureProperties); - } -} - -function include(parent, featureIdList) { - var featureId, - featureProperties, - localUrl, - i; - - for (i = 0; i < featureIdList.length; i++) { - featureId = featureIdList[i]; - - localUrl = "local://ext/" + featureId + "/client.js"; - featureProperties = utils.loadModule(localUrl); - - buildNamespace(parent, featureId.split("."), featureProperties); - } -} - -var _self = { - build: function (featureIdList) { - return { - into: function (target) { - include(target, featureIdList); - } - }; - } -}; - -module.exports = _self; http://git-wip-us.apache.org/repos/asf/cordova-js/blob/d2f52662/lib/blackberry10/plugin/blackberry10/pluginUtils.js ---------------------------------------------------------------------- diff --git a/lib/blackberry10/plugin/blackberry10/pluginUtils.js b/lib/blackberry10/plugin/blackberry10/pluginUtils.js new file mode 100644 index 0000000..9a52a25 --- /dev/null +++ b/lib/blackberry10/plugin/blackberry10/pluginUtils.js @@ -0,0 +1,69 @@ +/* + * + * 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. + * + */ + +module.exports = { + + loadClientJs: function (plugins, callback) { + var plugin, + script, + i, + count = 0; + for (plugin in plugins) { + if (plugins.hasOwnProperty(plugin) && plugins[plugin].modules) { + for (i = 0; i < plugins[plugin].modules.length; i++) { + script = document.createElement('script'); + script.src = 'plugins/' + plugin + '/' + plugins[plugin].modules[i]; + script.onload = function () { + if (--count === 0 && typeof callback === 'function') { + callback(); + } + }; + count++; + document.head.appendChild(script); + } + } + } + }, + + getPlugins: function (success, error) { + var request, + response; + request = new XMLHttpRequest(); + request.open('GET', 'plugins/plugins.json', true); + request.onreadystatechange = function () { + if (request.readyState === 4) { + if (request.status === 200) { + try { + response = JSON.parse(decodeURIComponent(request.responseText)); + success(response); + } + catch (e) { + error(e); + } + } + else { + error(request.status); + } + } + }; + request.send(null); + } +} http://git-wip-us.apache.org/repos/asf/cordova-js/blob/d2f52662/lib/scripts/bootstrap-blackberry10.js ---------------------------------------------------------------------- diff --git a/lib/scripts/bootstrap-blackberry10.js b/lib/scripts/bootstrap-blackberry10.js index 1a33845..8c97e46 100644 --- a/lib/scripts/bootstrap-blackberry10.js +++ b/lib/scripts/bootstrap-blackberry10.js @@ -20,17 +20,19 @@ */ (function () { - var _d = document.addEventListener, - _webworksReady = false, - _alreadyFired = false, - _listenerRegistered = false; + var pluginUtils = require('cordova/plugin/blackberry10/pluginUtils'), + docAddEventListener = document.addEventListener, + webworksReady = false, + alreadyFired = false, + listenerRegistered = false; //Only fire the webworks event when both webworks is ready and a listener is registered function fireWebworksReadyEvent() { - if (_listenerRegistered && _webworksReady && !_alreadyFired) { - _alreadyFired = true; - var evt = document.createEvent("Events"); - evt.initEvent("webworksready", true, true); + var evt; + if (listenerRegistered && webworksReady && !alreadyFired) { + alreadyFired = true; + evt = document.createEvent('Events'); + evt.initEvent('webworksready', true, true); document.dispatchEvent(evt); } } @@ -38,113 +40,78 @@ //Trapping when users add listeners to the webworks ready event //This way we can make sure not to fire the event before there is a listener document.addEventListener = function (event, callback, capture) { - _d.call(document, event, callback, capture); - if (event.toLowerCase() === "webworksready") { - _listenerRegistered = true; + docAddEventListener.call(document, event, callback, capture); + if (event.toLowerCase() === 'webworksready') { + listenerRegistered = true; fireWebworksReadyEvent(); } }; - function createWebworksReady() { - function RemoteFunctionCall(functionUri) { - var params = {}; - - function composeUri() { - return require("cordova/plugin/blackberry10/utils").getURIPrefix() + functionUri; - } - - function createXhrRequest(uri, isAsync) { - var request = new XMLHttpRequest(); - - request.open("POST", uri, isAsync); - request.setRequestHeader("Content-Type", "application/json"); - - return request; - } - - this.addParam = function (name, value) { - params[name] = encodeURIComponent(JSON.stringify(value)); - }; - - this.makeSyncCall = function (success, error) { - var requestUri = composeUri(), - request = createXhrRequest(requestUri, false), - response, - errored, - cb, - data; - - request.send(JSON.stringify(params)); - - response = JSON.parse(decodeURIComponent(request.responseText) || "null"); - errored = response.code < 0; - cb = errored ? error : success; - data = errored ? response.msg : response.data; - - if (cb) { - cb(data, response); - } - else if (errored) { - throw data; - } - - return data; - }; - - this.makeAsyncCall = function (success, error) { - var requestUri = composeUri(), - request = createXhrRequest(requestUri, true); + //Fire webworks ready once plugin javascript has been loaded + pluginUtils.getPlugins( + function (plugins) { + pluginUtils.loadClientJs(plugins, function () { + webworksReady = true; + fireWebworksReadyEvent(); + }); + }, + function (e) { + console.log(e); + } + ); - request.onreadystatechange = function () { - if (request.readyState === 4 && request.status === 200) { - var response = JSON.parse(decodeURIComponent(request.responseText) || "null"), - cb = response.code < 0 ? error : success, - data = response.code < 0 ? response.msg : response.data; + /** + * webworks.exec + * + * This will all be moved into lib/blackberry10/exec once cordova.exec can be replaced + */ - return cb && cb(data, response); - } - }; + function RemoteFunctionCall(functionUri) { + var params = {}; - request.send(JSON.stringify(params)); - }; + function composeUri() { + return require("cordova/plugin/blackberry10/utils").getURIPrefix() + functionUri; } - var builder, - request, - resp, - execFunc; - - //For users who wish to have a single source project across BB7 -> PB -> BB10 they will need to use webworks.js - //To aid in this, we will fire the webworksready event on these platforms as well - //If blackberry object already exists then we are in an older version of webworks - if (window.blackberry) { - _webworksReady = true; - fireWebworksReadyEvent(); - return; + function createXhrRequest(uri, isAsync) { + var request = new XMLHttpRequest(); + request.open("POST", uri, isAsync); + request.setRequestHeader("Content-Type", "application/json"); + return request; } - // Build out the blackberry namespace based on the APIs desired in the config.xml - builder = require('cordova/plugin/blackberry10/builder'); + this.addParam = function (name, value) { + params[name] = encodeURIComponent(JSON.stringify(value)); + }; + + this.makeSyncCall = function (success, error) { + var requestUri = composeUri(), + request = createXhrRequest(requestUri, false), + response, + errored, + cb, + data; - request = new XMLHttpRequest(); - request.open("GET", "http://localhost:8472/extensions/get", true); + request.send(JSON.stringify(params)); - request.onreadystatechange = function () { - if (request.readyState === 4) { - resp = JSON.parse(decodeURIComponent(request.responseText)); + response = JSON.parse(decodeURIComponent(request.responseText) || "null"); + errored = response.code < 0; + cb = errored ? error : success; + data = errored ? response.msg : response.data; - if (request.status === 200) { - builder.build(resp.data).into(window); - //At this point all of the APIs should be built into the window object - //Fire the webworks ready event - _webworksReady = true; - fireWebworksReadyEvent(); - } + if (cb) { + cb(data, response); } + else if (errored) { + throw data; + } + + return data; }; - request.send(null); + } - execFunc = function (success, fail, service, action, args, sync) { + window.webworks = { + exec: function (success, fail, service, action, args) { var uri = service + "/" + action, request = new RemoteFunctionCall(uri), name; @@ -155,53 +122,16 @@ } } - request[sync ? "makeSyncCall" : "makeAsyncCall"](success, fail); - }; - - window.webworks = { - exec: execFunc, - execSync: function (service, action, args) { - var result; - - execFunc(function (data, response) { - result = data; - }, function (data, response) { - throw data; - }, service, action, args, true); - - return result; - }, - execAsync: function (service, action, args) { - var result; - - execFunc(function (data, response) { - result = data; - }, function (data, response) { - throw data; - }, service, action, args, false); - - return result; - }, - successCallback: function (id, args) { - //HACK: this will live later - throw "not implemented"; - }, - errorCallback: function (id, args) { - //HACK: this will live later - throw "not implemented"; - }, - defineReadOnlyField: function (obj, field, value) { - Object.defineProperty(obj, field, { - "value": value, - "writable": false - }); - }, - event: require("cordova/plugin/blackberry10/event") - }; - } - - // Let's create the webworks namespace - createWebworksReady(); + return request.makeSyncCall(success, fail); + }, + defineReadOnlyField: function (obj, field, value) { + Object.defineProperty(obj, field, { + "value": value, + "writable": false + }); + }, + event: require("cordova/plugin/blackberry10/event") + }; }()); document.addEventListener("DOMContentLoaded", function () { http://git-wip-us.apache.org/repos/asf/cordova-js/blob/d2f52662/lib/scripts/require.js ---------------------------------------------------------------------- diff --git a/lib/scripts/require.js b/lib/scripts/require.js index 35f160e..5dbc905 100644 --- a/lib/scripts/require.js +++ b/lib/scripts/require.js @@ -1,251 +1,82 @@ /* - * Copyright 2012 Research In Motion Limited. * - * Licensed 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 + * 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 + * 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. - */ + * 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 define, - require; +var require, + define; (function () { - var unpreparedModules = {}, - readyModules = {}, - ACCEPTABLE_EXTENSIONS = [".js", ".json"], - DEFAULT_EXTENSION = ".js"; - - function hasValidExtension(moduleName) { - return ACCEPTABLE_EXTENSIONS.some(function (element, index, array) { - return moduleName.match("\\" + element + "$"); - }); - } - - - function normalizeName(originalName, baseName) { - var nameParts, - name = originalName.slice(0); - //remove ^local:// (if it exists) and .js$ - //This will not work for local:// without a trailing js - name = name.replace(/(?:^local:\/\/)/, ""); - if (name.charAt(0) === '.' && baseName) { - //Split the baseName and remove the final part (the module name) - nameParts = baseName.split('/'); - nameParts.pop(); - nameParts = nameParts.concat(name.split('/')); - - name = nameParts.reduce(function (previous, current, index, array) { - var returnValue, - slashIndex; - - //If previous is a dot, ignore it - //If previous is ever just .. we're screwed anyway - if (previous !== '.') { - returnValue = previous; - } - - //If we have a .. then remove a chunk of previous - if (current === "..") { - slashIndex = previous.lastIndexOf('/'); - //If there's no slash we're either screwed or we remove the final token - if (slashIndex !== -1) { - returnValue = previous.slice(0, previous.lastIndexOf('/')); - } else { - returnValue = ""; - } - } else if (current !== '.') { - //Otherwise simply append anything not a . - //Only append a slash if we're not empty - if (returnValue.length) { - returnValue += "/"; - } - returnValue += current; - } - - return returnValue; - }); - - } - - //If there is no acceptable extension tack on a .js - if (!hasValidExtension(name)) { - name = name + DEFAULT_EXTENSION; - } - - return name; - } - - function buildModule(name, dependencies, factory) { - var module = {exports: {}}, - localRequire = function (moduleName) { - return require(moduleName, name); - }, - args = []; - localRequire.toUrl = function (moduleName, baseName) { - return require.toUrl(moduleName, baseName || name); - }; - dependencies.forEach(function (dependency) { - if (dependency === 'require') { - args.push(localRequire); - } else if (dependency === 'exports') { - args.push(module.exports); - } else if (dependency === 'module') { - args.push(module); - } else { - //This is because jshint cannot handle out of order functions - /*global loadModule:false */ - args.push(loadModule(dependency)); - /*global loadModule:true */ - } - }); - - //No need to process dependencies, webworks only has require, exports, module - factory.apply(this, args); - - //For full AMD we would need logic to also check the return value + var modules = {}; + // Stack of moduleIds currently being built. + var requireStack = []; + // Map of module ID -> index into requireStack of modules currently being built. + var inProgressModules = {}; + + function build(module) { + var factory = module.factory; + module.exports = {}; + delete module.factory; + factory(require, module.exports, module); return module.exports; - } - function getDefineString(moduleName, body) { - var evalString = 'define("' + moduleName + '", function (require, exports, module) {', - isJson = /\.json$/.test(moduleName); - - evalString += isJson ? ' module.exports = ' : ''; - evalString += body.replace(/^\s+|\s+$/g, ''); - evalString += isJson ? ' ;' : ''; - evalString += '});'; - - return evalString; - } - - function loadModule(name, baseName) { - var normalizedName = normalizeName(name, baseName), - url, - xhr, - loadResult; - //Always check undefined first, this allows the user to redefine modules - //(Not used in WebWorks, although it is used in our unit tests) - if (unpreparedModules[normalizedName]) { - readyModules[normalizedName] = buildModule(normalizedName, unpreparedModules[normalizedName].dependencies, unpreparedModules[normalizedName].factory); - delete unpreparedModules[normalizedName]; + require = function (id) { + if (!modules[id]) { + throw "module " + id + " not found"; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw "Cycle in require graph: " + cycle; } - - //If the module does not exist, load the module from external source - //Webworks currently only loads APIs from across bridge - if (!readyModules[normalizedName]) { - //If the module to be loaded ends in .js then we will define it - //Also if baseName exists than we have a local require situation - if (hasValidExtension(name) || baseName) { - xhr = new XMLHttpRequest(); - url = name; - //If the module to be loaded starts with local:// go over the bridge - //Else If the module to be loaded is a relative load it may not have .js extension which is needed - if (/^local:\/\//.test(name)) { - url = "http://localhost:8472/extensions/load/" + normalizedName.replace(/(?:^ext\/)(.+)(?:\/client.js$)/, "$1"); - - xhr.open("GET", url, false); - xhr.send(null); - try { - loadResult = JSON.parse(xhr.responseText); - - loadResult.dependencies.forEach(function (dep) { - /*jshint evil:true */ - eval(getDefineString(dep.moduleName, dep.body)); - /*jshint evil:false */ - }); - - //Trimming responseText to remove EOF chars - /*jshint evil:true */ - eval(getDefineString(normalizedName, loadResult.client)); - /*jshint evil:false */ - } catch (err1) { - err1.message += ' in ' + url; - throw err1; - } - } else { - if (baseName) { - url = normalizedName; - } - - xhr.open("GET", url, false); - xhr.send(null); - try { - //Trimming responseText to remove EOF chars - /*jshint evil:true */ - eval(getDefineString(normalizedName, xhr.responseText)); - /*jshint evil:false */ - } catch (err) { - err.message += ' in ' + url; - throw err; - } - } - - if (unpreparedModules[normalizedName]) { - readyModules[normalizedName] = buildModule(normalizedName, unpreparedModules[normalizedName].dependencies, unpreparedModules[normalizedName].factory); - delete unpreparedModules[normalizedName]; - } - } else { - throw "module " + name + " cannot be found"; + if (modules[id].factory) { + try { + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); } - - } - - return readyModules[normalizedName]; - - } - - //Use the AMD signature incase we ever want to change. - //For now we will only be using (name, baseName) - require = function (dependencies, callback) { - if (typeof dependencies === "string") { - //dependencies is the module name and callback is the relName - //relName is not part of the AMDJS spec, but we use it from localRequire - return loadModule(dependencies, callback); - } else if (Array.isArray(dependencies) && typeof callback === 'function') { - //Call it Asynchronously - setTimeout(function () { - buildModule(undefined, dependencies, callback); - }, 0); } - }; - - require.toUrl = function (originalName, baseName) { - return normalizeName(originalName, baseName); + return modules[id].exports; }; - //Use the AMD signature incase we ever want to change. - //For now webworks will only be using (name, factory) signature. - define = function (name, dependencies, factory) { - if (typeof name === "string" && typeof dependencies === 'function') { - factory = dependencies; - dependencies = ['require', 'exports', 'module']; + define = function (id, factory) { + if (modules[id]) { + throw "module " + id + " already defined"; } - //According to the AMDJS spec we should parse out the require statments - //from factory.toString and add those to the list of dependencies - - //Normalize the name. Remove local:// and .js - name = normalizeName(name); - unpreparedModules[name] = { - dependencies: dependencies, + modules[id] = { + id: id, factory: factory - }; + }; }; -}()); -//Export for use in node for unit tests -if (typeof module === "object" && typeof require === "function") { - module.exports = { - require: require, - define: define + define.remove = function (id) { + delete modules[id]; }; + + define.moduleMap = modules; +})(); + +//Export for use in node +if (typeof module === "object" && typeof require === "function") { + module.exports.require = require; + module.exports.define = define; } http://git-wip-us.apache.org/repos/asf/cordova-js/blob/d2f52662/test/blackberry10/test.builder.js ---------------------------------------------------------------------- diff --git a/test/blackberry10/test.builder.js b/test/blackberry10/test.builder.js deleted file mode 100644 index 86e5487..0000000 --- a/test/blackberry10/test.builder.js +++ /dev/null @@ -1,121 +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 app, - io, - filetransfer, - system, - builder, - utils; - -describe("blackberry10 builder", function () { - - beforeEach(function () { - //Set up mocking, no need to "spyOn" since spies are included in mock - window.webworks = { - webworks: { - execSync: jasmine.createSpy(), - defineReadOnlyField: jasmine.createSpy() - } - }; - - app = { - "name": "abc", - "version": "1.2.3" - }; - io = { - "sandbox": false - }; - filetransfer = { - "upload": function () {}, - "download": function () {} - }; - system = { - "getCurrentTimezone": function () {} - }; - - utils = require("cordova/plugin/blackberry10/utils"); - spyOn(utils, "loadModule").andCallFake(function (module) { - if (module.indexOf("app") !== -1) { - return app; - } else if (module.indexOf("filetransfer") !== -1) { - return filetransfer; - } else if (module.indexOf("io") !== -1) { - return io; - } else if (module.indexOf("system") !== -1) { - return system; - } - }); - - builder = require("cordova/plugin/blackberry10/builder"); - }); - - afterEach(function () { - delete window.webworks; - builder = null; - }); - - it("can build an object with a single member", function () { - var featureIds = ['blackberry.app'], - target = {}; - - builder.build(featureIds).into(target); - - expect(target.blackberry.app).toEqual(app); - expect(Object.hasOwnProperty.call(target.blackberry.app, "name")).toBeTruthy(); - expect(Object.hasOwnProperty.call(target.blackberry.app, "version")).toBeTruthy(); - }); - - it("can build an object with a nested member", function () { - var featureIds = ['blackberry.io', 'blackberry.io.filetransfer'], - target = {}; - - builder.build(featureIds).into(target); - expect(target.blackberry.io.filetransfer).toEqual(filetransfer); - expect(target.blackberry.io.sandbox).toEqual(io.sandbox); - }); - - it("can build with feature IDs provided in any order", function () { - var featureIds = ['blackberry.io.filetransfer', 'blackberry.io'], - target = {}; - - builder.build(featureIds).into(target); - expect(target.blackberry.io.filetransfer).toEqual(filetransfer); - expect(target.blackberry.io.sandbox).toEqual(io.sandbox); - }); - - it("can build an object with only the nested member", function () { - var featureIds = ['blackberry.io.filetransfer'], - target = {}; - - builder.build(featureIds).into(target); - expect(target.blackberry.io.filetransfer).toEqual(filetransfer); - }); - - it("can build an object with multiple members", function () { - var featureIds = ['blackberry.app', 'blackberry.system'], - target = {}; - - builder.build(featureIds).into(target); - expect(target.blackberry.app).toEqual(app); - expect(target.blackberry.system).toEqual(system); - }); -}); http://git-wip-us.apache.org/repos/asf/cordova-js/blob/d2f52662/test/blackberry10/test.pluginUtils.js ---------------------------------------------------------------------- diff --git a/test/blackberry10/test.pluginUtils.js b/test/blackberry10/test.pluginUtils.js new file mode 100644 index 0000000..37f0e9c --- /dev/null +++ b/test/blackberry10/test.pluginUtils.js @@ -0,0 +1,137 @@ +/* + * + * 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. + * +*/ + +describe('blackberry10 pluginUtils', function () { + + var pluginUtils = require('cordova/plugin/blackberry10/pluginUtils'); + + describe('loadClientJs', function () { + + var callback, + script; + + beforeEach(function () { + script = {}; + spyOn(document, "createElement").andCallFake(function () { + return script; + }); + spyOn(document.head, "appendChild"); + callback = jasmine.createSpy(); + }); + + it('does nothing for 0 plugins', function () { + var plugins = {}; + pluginUtils.loadClientJs(plugins, callback); + expect(document.createElement).not.toHaveBeenCalled(); + expect(document.head.appendChild).not.toHaveBeenCalled(); + expect(callback).not.toHaveBeenCalled(); + }); + + it('adds a script tag for 1 plugin', function () { + var plugins = { foo : { client: ['bar.js'] } }; + pluginUtils.loadClientJs(plugins, callback); + expect(document.createElement).toHaveBeenCalled(); + expect(script.src).toEqual('plugins/foo/bar.js'); + expect(document.head.appendChild).toHaveBeenCalled(); + script.onload(); + expect(callback).toHaveBeenCalled(); + }); + + it('adds multiple script tags for 1 plugin', function () { + var plugins = { foo: { client: ['bar.js', '2.js'] } }; + pluginUtils.loadClientJs(plugins, callback); + expect(document.createElement.callCount).toBe(2); + expect(document.head.appendChild.callCount).toBe(2); + script.onload(); + script.onload(); + expect(callback.callCount).toBe(1); + }); + + it('adds script tags for multiple plugins', function () { + var plugins = { foo: { client: ['1.js'] }, bar: { client: ['1.js', '2.js' ] } }; + pluginUtils.loadClientJs(plugins, callback); + expect(document.createElement.callCount).toBe(3); + expect(document.head.appendChild.callCount).toBe(3); + script.onload(); + script.onload(); + script.onload(); + expect(callback.callCount).toBe(1); + }); + + }); + + describe('getPlugins', function () { + + var success, + error, + xhr; + + beforeEach(function () { + GLOBAL.XMLHttpRequest = function () { + this.open = jasmine.createSpy(); + this.send = jasmine.createSpy(); + xhr = this; + }; + success = jasmine.createSpy(); + error = jasmine.createSpy(); + }); + + afterEach(function () { + delete GLOBAL.XMLHttpRequest; + }); + + it('sends XHR for plugins.json', function () { + pluginUtils.getPlugins(success, error); + expect(xhr.open).toHaveBeenCalledWith('GET', 'plugins/plugins.json', true); + expect(xhr.send).toHaveBeenCalled(); + }); + + it('calls success with JSON response', function () { + pluginUtils.getPlugins(success, error); + xhr.readyState = 4; + xhr.status = 200; + xhr.responseText = '{ "hello" : "World" }'; + xhr.onreadystatechange(); + expect(success).toHaveBeenCalledWith({ hello: "World"}); + expect(error).not.toHaveBeenCalled(); + }); + + it('calls error with status', function () { + pluginUtils.getPlugins(success, error); + xhr.readyState = 4; + xhr.status = 500; + xhr.onreadystatechange(); + expect(error).toHaveBeenCalledWith(500); + expect(success).not.toHaveBeenCalled(); + }); + + it('calls error with parse exception', function () { + pluginUtils.getPlugins(success, error); + xhr.readyState = 4; + xhr.status = 200; + xhr.responseText = 'INVALID'; + xhr.onreadystatechange(); + expect(error).toHaveBeenCalled(); + expect(success).not.toHaveBeenCalled(); + }); + + }); +}); http://git-wip-us.apache.org/repos/asf/cordova-js/blob/d2f52662/test/runner.js ---------------------------------------------------------------------- diff --git a/test/runner.js b/test/runner.js index e25afbb..c908cf3 100644 --- a/test/runner.js +++ b/test/runner.js @@ -49,7 +49,7 @@ module.exports = { try { jsdom = require("jsdom").jsdom; - document = jsdom("<html>"); + document = jsdom("<html><head></head></html>"); window = document.createWindow(); } catch (e) { //no jsDom (some people don't have compilers)