UNPKG

lfr-amd-loader

Version:

AMD Loader with support for combo URL and conditional loading

553 lines (426 loc) 17.7 kB
'use strict'; require('./fixture/common.js'); require('./fixture/script.js'); var assert = require('chai').assert; var sinon = require('sinon'); describe('Loader', function() { beforeEach(function() { Object.keys(require.cache).forEach(function(cache) { delete require.cache[cache]; }); global.__CONFIG__ = { url: __dirname + '/fixture', basePath: '/modules', maps: { 'liferay': 'liferay@1.0.0', 'liferay2': 'liferay@2.0.0' }, modules: { module1: { dependencies: ['module2', 'module3'] }, module2: { dependencies: [] }, module3: { dependencies: [] }, module5: { dependencies: ['module6', 'module7', 'exports'] }, module6: { dependencies: ['module7', 'exports'] }, module7: { dependencies: ['exports'] }, moduleMissing: { dependencies: [] }, moduleCyclic1: { dependencies: ['moduleCyclic2'] }, moduleCyclic2: { dependencies: ['moduleCyclic1'] }, 'liferay@1.0.0/relative1': { dependencies: ['exports', 'module', './relative2'], path: 'relative1.js' }, 'liferay@1.0.0/relative2': { dependencies: ['exports', 'module', './sub-relative/sub-relative1'], path: 'relative2.js' }, 'liferay@1.0.0/relative3': { dependencies: ['exports', 'module'], path: 'relative3.js' }, 'liferay@1.0.0/sub-relative/sub-relative1': { dependencies: ['exports', 'module', '../relative3'], 'path': 'sub-relative/sub-relative1.js' }, 'liferay@1.0.0': { dependencies: ['exports'], path: 'liferay.js' }, 'liferay@2.0.0': { dependencies: ['exports', 'liferay'], path: 'liferay2.js' }, 'exports-dep': { dependencies: ['exports'], path: 'exports-dep.js' }, 'module-dep': { dependencies: ['exports', 'module'], path: 'module-dep.js' }, 'liferay@1.0.0/empty': { dependencies: [], path: 'empty.js' }, 'liferay@1.0.0/mappeddeps': { dependencies: ['liferay', 'liferay2'], path: 'mappeddeps.js' } } }; global.__CONFIG__.waitTimeout = 0; global.__CONFIG__.paths = {}; require('../umd/config-parser.js'); require('../umd/event-emitter.js'); require('../umd/script-loader.js'); }); it('should add module to the configuration', function() { var moduleName = '_' + Math.random().toString(); var modules = Loader.getModules(); assert.notProperty(modules, moduleName); var module = Loader.addModule({ name: moduleName, dependencies: [] }); assert.property(modules, moduleName); assert.isObject(module); assert.propertyVal(module, 'name', moduleName); }); it('should define a module without dependencies (except exports)', function (done) { var impl = sinon.spy(function (exports) { exports.pejJung = {}; }); Loader.define('pej-jung', ['exports'], impl); setTimeout(function() { assert(impl.notCalled); var modules = Loader.getModules(); var module = modules['pej-jung']; assert.ok(module); assert.strictEqual('pej-jung', module.name); assert.strictEqual(module.pendingImplementation, impl); assert.strictEqual(module.requested, undefined); done(); }, 50); }); it('should discover missing dependencies of already defined modules', function() { var module1 = Math.random().toString(); var dep1 = Math.random().toString(); var module2 = Math.random().toString(); var dep2 = Math.random().toString(); Loader.define(module1, [dep1], function() {return 1;}); Loader.define(module2, [dep2], function() {return 1;}); var missingDeps = Loader._getMissingDepenencies([module1, module2]); assert.isArray(missingDeps); assert.strictEqual(2, missingDeps.length); assert.sameMembers([dep1, dep2], missingDeps); }); it('should resolve relative dependencies path in define', function() { var module = 'test/sub1/' + Math.random().toString(); var depName = Math.random().toString(); var dep = '../' + depName; Loader.define(module, [dep], function() {}); var modules = Loader.getModules(); assert.property(modules, module); assert.isArray(modules[module].dependencies); assert.strictEqual('test/' + depName, modules[module].dependencies[0]); }); it('should not accept define with only one parameter', function() { assert.isUndefined(Loader.define(function() {})); }); it('should not accept define with two parameters', function() { assert.isUndefined(Loader.define(['exports'], function() {})); }); it('should define a module with name and without dependencies', function() { var module = Math.random().toString(); var impl = function() {}; Loader.define(module, impl); var modules = Loader.getModules(); assert.property(modules, module); assert.isArray(modules[module].dependencies); assert.strictEqual(modules[module].pendingImplementation, impl); assert.sameMembers(['exports', 'module'], modules[module].dependencies); }); it('should define itself as AMD compatibe loader', function() { assert.property(global.define, 'amd'); assert.isObject(global.define.amd); }); it('should register unregistered modules in require', function() { var module = Math.random().toString(); Loader.require(module); var modules = Loader.getModules(); assert.property(modules, module); assert.isObject(modules[module]); assert.property(modules[module], 'dependencies'); assert.isArray(modules[module].dependencies); }); it('should map modules in require', function() { var module = Math.random().toString(); var alias = Math.random().toString(); global.__CONFIG__.maps[module] = alias; Loader.require(module, [], function() {return 1;}); var modules = Loader.getModules(); assert.property(modules, alias); }); it('should load already defined (manually) modules', function (done) { var failure = sinon.stub(); var success = sinon.stub(); Loader.require(['aui-123', 'pej-jung'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled); assert.isTrue(success.calledOnce); done(); }, 50); }); it('should load unregistered modules', function (done) { var one; var failure = sinon.stub(); var success = sinon.spy(function(_one) { one = _one; }); global.__CONFIG__.paths['one'] = '/modules2/one'; global.__CONFIG__.paths['two'] = '/modules2/two'; global.__CONFIG__.paths['three'] = '/modules2/three'; Loader.require(['one'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled); assert.isTrue(success.calledOnce); assert.isFunction(one); done(); }, 50); }); it('should load previously registered modules', function (done) { var failure = sinon.stub(); var success = sinon.stub(); Loader.require('module1', success, failure); setTimeout(function() { assert.isTrue(failure.notCalled); assert.isTrue(success.calledOnce); done(); }, 50); }); it('should load module which implementation is an object', function(done) { var moduleName = Math.random().toString(); Loader.addModule({ name: 'impl_as_object', dependencies: ['exports'], path: '/modules2/impl_as_object.js' }); var failure = sinon.stub(); var implementation; var success = sinon.spy(function(impl) { implementation = impl; }); Loader.require(['impl_as_object'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should not be called'); assert.isTrue(success.calledOnce, 'Success should be called'); assert.isObject(implementation, 'The implementation should be an object'); assert.property(implementation, 'pesho'); done(); }, 50); }); it('should fail on registered but not existing file', function (done) { var failure = sinon.stub(); var success = sinon.stub(); Loader.require('moduleMissing', success, failure); setTimeout(function() { assert.isTrue(failure.calledOnce); assert.isTrue(success.notCalled); done(); }, 50); }); it('should fail if there are cyclic dependencies', function (done) { var failure = sinon.stub(); var success = sinon.stub(); Loader.require('moduleCyclic1', 'moduleCyclic2', success, failure); setTimeout(function() { assert.isTrue(failure.calledOnce); assert.isTrue(success.notCalled); done(); }, 50); }); it('should succeed when requiring modules multiple times', function (done) { var failure = sinon.stub(); var success = sinon.stub(); Loader.require(['module5'], success, failure); Loader.require(['module6'], success, failure); Loader.require(['module7'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled); assert.isTrue(success.calledThrice); done(); }, 50); }); it('should ignore success and callback if not functions', function() { Loader.require(['module1'], null, null); }); it('should return conditional modules', function() { var conditionalModules = Loader.getConditionalModules(); assert.deepEqual({}, conditionalModules); }); it('should load aliased modules', function(done) { var failure = sinon.stub(); var success = sinon.stub(); Loader.require(['liferay'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled); assert.isTrue(success.calledOnce); done(); }, 50); }); it('should load aliased modules with aliased dependencies', function(done) { var failure = sinon.stub(); var success = sinon.stub(); Loader.require(['liferay2'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should be not called'); assert.isTrue(success.calledOnce, 'Success should be called'); done(); }, 50); }); it('should load module with "exports" dependency', function(done) { var failure = sinon.stub(); var successValue; var success = sinon.spy(function(val) { successValue = val; }); Loader.require(['exports-dep'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should be not called'); assert.isTrue(success.calledOnce, 'Success should be called'); assert.isObject(successValue); assert.property(successValue, 'default'); assert.isFunction(successValue.default); assert.strictEqual('alabala', successValue.default.name); done(); }, 50); }); it('should load module with "module" dependency', function(done) { var failure = sinon.stub(); var successValue; var success = sinon.spy(function(val) { successValue = val; }); Loader.require(['module-dep'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should be not called'); assert.isTrue(success.calledOnce, 'Success should be called'); assert.isFunction(successValue); assert.strictEqual('alabala', successValue.name); done(); }, 50); }); it('should load module with relative path', function(done) { var failure = sinon.stub(); var successValue; var success = sinon.spy(function(val) { successValue = val; }); Loader.require(['liferay/relative1'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should be not called'); assert.isTrue(success.calledOnce, 'Success should be called'); assert.isObject(successValue); done(); }, 50); }); it('should resolve the missing dependencies without multiple require calls', function(done) { Loader.require = sinon.spy(Loader.require); var failure = sinon.stub(); var success = sinon.stub(); Loader.require.call(Loader, ['liferay@1.0.0/relative1'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should be not called'); assert.isTrue(success.calledOnce, 'Success should be called'); assert.isTrue(Loader.require.calledOnce, 'Require should be called once'); done(); }, 50); }); it('should load module with mapped dependencies without multiple require calls', function(done) { Loader.require = sinon.spy(Loader.require); var failure = sinon.stub(); var success = sinon.stub(); Loader.require.call(Loader, ['liferay/mappeddeps'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should be not called'); assert.isTrue(success.calledOnce, 'Success should be called'); assert.isTrue(Loader.require.calledOnce, 'Require should be called once'); done(); }, 50); }); it('should cancel a require in case of failure because of an empty module', function(done) { global.__CONFIG__.waitTimeout = 20; var failureError; var failure = sinon.spy(function(error) { failureError = error; }); var success = sinon.stub(); Loader.require(['liferay@1.0.0/empty'], success, failure); setTimeout(function() { assert.isTrue(failure.calledOnce, 'Failure should be called once'); assert.isTrue(success.notCalled, 'Success should not be called'); assert.instanceOf(failureError, Error); assert.property(failureError, 'dependecies'); assert.property(failureError, 'mappedModules'); assert.property(failureError, 'missingDependencies'); assert.property(failureError, 'modules'); done(); }, 50); }); it('should failure after require timeout, but a valid module should still load', function(done) { global.__CONFIG__.waitTimeout = 1; global.__CONFIG__.paths['delay'] = '/modules2/delay'; var failureError; var failure = sinon.spy(function(error) { failureError = error; }); var success = sinon.stub(); Loader.require(['delay'], success, failure); setTimeout(function() { assert.isTrue(failure.calledOnce, 'Failure should be called'); assert.property(failureError, 'modules'); assert.isTrue(success.notCalled, 'Success should be not called'); // Delay module adds "delay" property to global assert.strictEqual(1, global.delay); done(); }, 50); }); it('should load modules which do not expose a define function', function(done) { Loader.addModule({ dependencies: [], exports: '_', name: 'underscore', path: '/modules2/underscore.js' }); var failure = sinon.spy(function(error) { console.error(error); }); var success = sinon.stub(); Loader.require(['underscore'], success, failure); setTimeout(function() { assert.isTrue(failure.notCalled, 'Failure should not be called'); assert.isTrue(success.calledOnce, 'Success should be called'); assert.property(global, '_'); var modules = Loader.getModules(); assert.property(modules['underscore'], 'implementation'); done(); }, 50); }); });