UNPKG

sku-pg

Version:

Skulpt is a Javascript implementation of Python 2.x. Python that runs in your browser!

1,171 lines (1,035 loc) 37.5 kB
<!DOCTYPE html> <html> <!-- Copyright 2008 The Closure Library Authors. All Rights Reserved. Use of this source code is governed by an Apache 2.0 License. See the COPYING file for details. --> <!-- Author: pupius@google.com (Daniel Pupius) Author: jananir@google.com (Janani Ravi) (Modified for Closure) --> <head> <title>Closure Unit Tests - goog.module.ModuleManager</title> <script src="../base.js"></script> <script src="../../../third_party/closure/goog/deps.js"></script> <script> goog.require('goog.functions'); goog.require('goog.module.BaseModule'); goog.require('goog.module.ModuleManager'); goog.require('goog.testing.MockClock'); goog.require('goog.testing.jsunit'); goog.require('goog.testing.recordFunction'); </script> </head> <body> <script> var clock; function setUpPage() { clock = new goog.testing.MockClock(true); } function tearDownPage() { clock.dispose(); } function getModuleManager(infoMap) { var mm = new goog.module.ModuleManager(); mm.setAllModuleInfo(infoMap); mm.isModuleLoaded = function(id) { return this.getModuleInfo(id).isLoaded(); } return mm; } function createSuccessfulBatchLoader(moduleMgr) { return { loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn, opt_timeoutFn) { setTimeout(goog.bind(this.onLoad, this, ids.concat(), 0), 5); }, onLoad: function(ids, idxLoaded) { moduleMgr.beforeLoadModuleCode(ids[0]); moduleMgr.setLoaded(ids[idxLoaded]); moduleMgr.afterLoadModuleCode(ids[idxLoaded]); var idx = idxLoaded + 1; if (idx < ids.length) { moduleMgr.beforeLoadModuleCode(ids[idx]); setTimeout(goog.bind(this.onLoad, this, ids, idx), 2); } }}; } function createSuccessfulNonBatchLoader(moduleMgr) { return { loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn, opt_timeoutFn) { setTimeout(function() { moduleMgr.beforeLoadModuleCode(ids[0]); moduleMgr.setLoaded(ids[0]); moduleMgr.afterLoadModuleCode(ids[0]); if (opt_successFn) { opt_successFn(); } }, 5); }}; } function createUnsuccessfulLoader(moduleMgr, status) { return { loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn, opt_timeoutFn) { moduleMgr.beforeLoadModuleCode(ids[0]); setTimeout(function() { opt_errFn(status); }, 5); }}; } function createTimeoutLoader(moduleMgr, status) { return { loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn, opt_timeoutFn) { setTimeout(function() { opt_timeoutFn(status); }, 5); }}; } /** * Tests loading a module under different conditions i.e. unloaded * module, already loaded module, module loaded through user initiated * actions, synchronous callback for a module that has been already * loaded. Test both batch and non-batch loaders. */ function testExecOnLoad() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); execOnLoad_(mm); mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulBatchLoader(mm)); mm.setBatchModeEnabled(true); execOnLoad_(mm); } /** * Tests execOnLoad with the specified module manager. * @param {goog.module.ModuleManager} mm The module manager. */ function execOnLoad_(mm) { // When module is unloaded, execOnLoad is async. var execCalled1 = false; mm.execOnLoad('a', function() { execCalled1 = true; }); assertFalse('module "a" should not be loaded', mm.isModuleLoaded('a')); assertTrue('module "a" should be loading', mm.isModuleLoading('a')); assertFalse('execCalled1 should not be set yet', execCalled1); assertTrue('ModuleManager should be active', mm.isActive()); assertFalse( 'ModuleManager should not be user active', mm.isUserActive()); clock.tick(5); assertTrue('module "a" should be loaded', mm.isModuleLoaded('a')); assertFalse( 'module "a" should not be loading', mm.isModuleLoading('a')); assertTrue('execCalled1 should be set', execCalled1); assertFalse('ModuleManager should not be active', mm.isActive()); assertFalse( 'ModuleManager should not be user active', mm.isUserActive()); // When module is already loaded, execOnLoad is still async unless // specified otherwise. var execCalled2 = false; mm.execOnLoad('a', function() { execCalled2 = true; }); assertTrue('module "a" should be loaded', mm.isModuleLoaded('a')); assertFalse( 'module "a" should not be loading', mm.isModuleLoading('a')); assertFalse('execCalled2 should not be set yet', execCalled2); clock.tick(5); assertTrue('execCalled2 should be set', execCalled2); // When module is unloaded, execOnLoad is async (user active). var execCalled5 = false; mm.execOnLoad('c', function() { execCalled5 = true; }, null, null, true); assertFalse('module "c" should not be loaded', mm.isModuleLoaded('c')); assertTrue('module "c" should be loading', mm.isModuleLoading('c')); assertFalse('execCalled1 should not be set yet', execCalled5); assertTrue('ModuleManager should be active', mm.isActive()); assertTrue('ModuleManager should be user active', mm.isUserActive()); clock.tick(5); assertTrue('module "c" should be loaded', mm.isModuleLoaded('c')); assertFalse( 'module "c" should not be loading', mm.isModuleLoading('c')); assertTrue('execCalled1 should be set', execCalled5); assertFalse('ModuleManager should not be active', mm.isActive()); assertFalse( 'ModuleManager should not be user active', mm.isUserActive()); // When module is already loaded, execOnLoad is still synchronous when // so specified var execCalled6 = false; mm.execOnLoad('c', function() { execCalled6 = true; }, undefined, undefined, undefined, true); assertTrue('module "c" should be loaded', mm.isModuleLoaded('c')); assertFalse( 'module "c" should not be loading', mm.isModuleLoading('c')); assertTrue('execCalled6 should be set', execCalled6); clock.tick(5); assertTrue('execCalled6 should still be set', execCalled6); } /** * Test aborting the callback called on module load. */ function testExecOnLoadAbort() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); // When module is unloaded and abort is called, module still gets // loaded, but callback is cancelled. var execCalled1 = false; var callback1 = mm.execOnLoad('b', function() { execCalled1 = true; }); callback1.abort(); clock.tick(5); assertTrue('module "b" should be loaded', mm.isModuleLoaded('b')); assertFalse('execCalled3 should not be set', execCalled1); // When module is already loaded, execOnLoad is still async, so calling // abort should still cancel the callback. var execCalled2 = false; var callback2 = mm.execOnLoad('a', function() { execCalled2 = true; }); callback2.abort(); clock.tick(5); assertFalse('execCalled2 should not be set', execCalled2); } /** * Test preloading modules and ensure that the before load, after load * and set load called are called only once per module. */ function testExecOnLoadWhilePreloadingAndViceVersa() { var mm = getModuleManager({'c': [], 'd': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); execOnLoadWhilePreloadingAndViceVersa_(mm); mm = getModuleManager({'c': [], 'd': []}); mm.setLoader(createSuccessfulBatchLoader(mm)); mm.setBatchModeEnabled(true); execOnLoadWhilePreloadingAndViceVersa_(mm); } /** * Perform tests with the specified module manager. * @param {goog.module.ModuleManager} mm The module manager. */ function execOnLoadWhilePreloadingAndViceVersa_(mm) { var mm = getModuleManager({'c': [], 'd': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var origSetLoaded = mm.setLoaded; var calls = [0, 0, 0]; mm.beforeLoadModuleCode = function(id) { calls[0]++; }; mm.setLoaded = function(id) { calls[1]++; origSetLoaded.call(mm, id); }; mm.afterLoadModuleCode = function(id) { calls[2]++; }; mm.preloadModule('c', 2); assertFalse( 'module "c" should not be loading yet', mm.isModuleLoading('c')); clock.tick(2); assertTrue( 'module "c" should now be loading', mm.isModuleLoading('c')); mm.execOnLoad('c', function() {}); assertTrue( 'module "c" should still be loading', mm.isModuleLoading('c')); clock.tick(5); assertFalse( 'module "c" should be done loading', mm.isModuleLoading('c')); assertEquals( 'beforeLoad should only be called once for "c"', 1, calls[0]); assertEquals( 'setLoaded should only be called once for "c"', 1, calls[1]); assertEquals( 'afterLoad should only be called once for "c"', 1, calls[2]); mm.execOnLoad('d', function() {}); assertTrue( 'module "d" should now be loading', mm.isModuleLoading('d')); mm.preloadModule('d', 2); clock.tick(5); assertFalse( 'module "d" should be done loading', mm.isModuleLoading('d')); assertTrue( 'module "d" should now be loaded', mm.isModuleLoaded('d')); assertEquals( 'beforeLoad should only be called once for "d"', 2, calls[0]); assertEquals( 'setLoaded should only be called once for "d"', 2, calls[1]); assertEquals( 'afterLoad should only be called once for "d"', 2, calls[2]); } /** * Tests loading a module by requesting a Deferred object. */ function testLoad() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var calledBack = false; var error = null; var d = mm.load('a'); d.addCallback(function(ctx) { calledBack = true; }); d.addErrback(function(err) { error = err; }); assertFalse(calledBack); assertNull(error); assertFalse(mm.isUserActive()); clock.tick(5); assertTrue(calledBack); assertNull(error); } /** * Tests loading a module by user action by requesting a Deferred object. */ function testLoadForUser() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var calledBack = false; var error = null; var d = mm.load('a', true); d.addCallback(function(ctx) { calledBack = true; }); d.addErrback(function(err) { error = err; }); assertFalse(calledBack); assertNull(error); assertTrue(mm.isUserActive()); clock.tick(5); assertTrue(calledBack); assertNull(error); } /** * Tests that preloading a module calls back the deferred object. */ function testPreloadDeferredWhenNotLoaded() { var mm = getModuleManager({'a': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var calledBack = false; var d = mm.preloadModule('a');; d.addCallback(function(ctx) { calledBack = true; }); // First load should take five ticks. assertFalse('module "a" should not be loaded yet', calledBack); clock.tick(5); assertTrue('module "a" should be loaded', calledBack); } /** * Tests preloading an already loaded module. */ function testPreloadDeferredWhenLoaded() { var mm = getModuleManager({'a': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var calledBack = false; mm.preloadModule('a'); clock.tick(5); var d = mm.preloadModule('a');; d.addCallback(function(ctx) { calledBack = true; }); // Module is already loaded, should be called back after the setTimeout // in preloadModule. assertFalse('deferred for module "a" should not be called yet', calledBack); clock.tick(1); assertTrue('module "a" should be loaded', calledBack); } /** * Tests preloading a module that is currently loading. */ function testPreloadDeferredWhenLoading() { var mm = getModuleManager({'a': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); mm.preloadModule('a'); clock.tick(1); // 'b' is in the middle of loading, should get called back when it's done. var calledBack = false; var d = mm.preloadModule('a');; d.addCallback(function(ctx) { calledBack = true; }); assertFalse('module "a" should not be loaded yet', calledBack); clock.tick(4); assertTrue('module "a" should be loaded', calledBack); } /** * Tests that load doesn't trigger another load if a module is already * preloading. */ function testLoadWhenPreloading() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var origSetLoaded = mm.setLoaded; var calls = [0, 0, 0]; mm.beforeLoadModuleCode = function(id) { calls[0]++; }; mm.setLoaded = function(id) { calls[1]++; origSetLoaded.call(mm, id); }; mm.afterLoadModuleCode = function(id) { calls[2]++; }; var calledBack = false; var error = null; mm.preloadModule('c', 2); assertFalse( 'module "c" should not be loading yet', mm.isModuleLoading('c')); clock.tick(2); assertTrue( 'module "c" should now be loading', mm.isModuleLoading('c')); var d = mm.load('c'); d.addCallback(function(ctx) { calledBack = true; }); d.addErrback(function(err) { error = err; }); assertTrue( 'module "c" should still be loading', mm.isModuleLoading('c')); clock.tick(5); assertFalse( 'module "c" should be done loading', mm.isModuleLoading('c')); assertEquals( 'beforeLoad should only be called once for "c"', 1, calls[0]); assertEquals( 'setLoaded should only be called once for "c"', 1, calls[1]); assertEquals( 'afterLoad should only be called once for "c"', 1, calls[2]); assertTrue(calledBack); assertNull(error); } /** * Tests loading a module via load when the module is already * loaded. The deferred's callback should be called immediately. */ function testLoadWhenLoaded() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var calledBack = false; var error = null; mm.preloadModule('b', 2); clock.tick(10); assertFalse( 'module "b" should be done loading', mm.isModuleLoading('b')); var d = mm.load('b'); d.addCallback(function(ctx) { calledBack = true; }); d.addErrback(function(err) { error = err; }); assertTrue(calledBack); assertNull(error); } /** * Tests that the deferred's errbacks are called if the module fails to load. */ function testLoadWithFailingModule() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createUnsuccessfulLoader(mm, 401)); mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR, function(callbackType, id, cause) { assertEquals('Failure cause was not as expected', goog.module.ModuleManager.FailureType.UNAUTHORIZED, cause); firedLoadFailed = true; }); var calledBack = false; var error = null; var d = mm.load('a'); d.addCallback(function(ctx) { calledBack = true; }); d.addErrback(function(err) { error = err; }); assertFalse(calledBack); assertNull(error); clock.tick(500); assertFalse(calledBack); // NOTE: Deferred always calls errbacks with an Error object. For now the // module manager just passes the FailureType which gets set as the Error // object's message. assertEquals('Failure cause was not as expected', goog.module.ModuleManager.FailureType.UNAUTHORIZED, Number(error.message)); } /** * Test loading dependencies transitively. */ function testLoadingDepsInNonBatchMode1() { var mm = getModuleManager({ 'i': [], 'j': [], 'k': ['j'], 'l': ['i','j','k']}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); mm.preloadModule('j'); clock.tick(5); assertTrue('module "j" should be loaded', mm.isModuleLoaded('j')); assertFalse( 'module "i" should not be loaded (1)', mm.isModuleLoaded('i')); assertFalse( 'module "k" should not be loaded (1)', mm.isModuleLoaded('k')); assertFalse( 'module "l" should not be loaded (1)', mm.isModuleLoaded('l')); // When loading a module in non-batch mode, its dependencies should be // requested independently, and in dependency order. mm.preloadModule('l'); clock.tick(5); assertTrue('module "i" should be loaded', mm.isModuleLoaded('i')); assertFalse( 'module "k" should not be loaded (2)', mm.isModuleLoaded('k')); assertFalse( 'module "l" should not be loaded (2)', mm.isModuleLoaded('l')); clock.tick(5); assertTrue('module "k" should be loaded', mm.isModuleLoaded('k')); assertFalse( 'module "l" should not be loaded (3)', mm.isModuleLoaded('l')); clock.tick(5); assertTrue( 'module "l" should be loaded', mm.isModuleLoaded('l')); } /** * Test loading dependencies transitively and in dependency order. */ function testLoadingDepsInNonBatchMode2() { var mm = getModuleManager({ 'h': [], 'i': ['h'], 'j': ['i'], 'k': ['j'], 'l': ['i','j','k'], 'm': ['l']}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); // When loading a module in non-batch mode, its dependencies should be // requested independently, and in dependency order. The order in this // case should be h,i,j,k,l,m. mm.preloadModule('m'); clock.tick(5); assertTrue('module "h" should be loaded', mm.isModuleLoaded('h')); assertFalse( 'module "i" should not be loaded (1)', mm.isModuleLoaded('i')); assertFalse( 'module "j" should not be loaded (1)', mm.isModuleLoaded('j')); assertFalse( 'module "k" should not be loaded (1)', mm.isModuleLoaded('k')); assertFalse( 'module "l" should not be loaded (1)', mm.isModuleLoaded('l')); assertFalse( 'module "m" should not be loaded (1)', mm.isModuleLoaded('m')); clock.tick(5); assertTrue('module "i" should be loaded', mm.isModuleLoaded('i')); assertFalse( 'module "j" should not be loaded (2)', mm.isModuleLoaded('j')); assertFalse( 'module "k" should not be loaded (2)', mm.isModuleLoaded('k')); assertFalse( 'module "l" should not be loaded (2)', mm.isModuleLoaded('l')); assertFalse( 'module "m" should not be loaded (2)', mm.isModuleLoaded('m')); clock.tick(5); assertTrue('module "j" should be loaded', mm.isModuleLoaded('j')); assertFalse( 'module "k" should not be loaded (3)', mm.isModuleLoaded('k')); assertFalse( 'module "l" should not be loaded (3)', mm.isModuleLoaded('l')); assertFalse( 'module "m" should not be loaded (3)', mm.isModuleLoaded('m')); clock.tick(5); assertTrue('module "k" should be loaded', mm.isModuleLoaded('k')); assertFalse( 'module "l" should not be loaded (4)', mm.isModuleLoaded('l')); assertFalse( 'module "m" should not be loaded (4)', mm.isModuleLoaded('m')); clock.tick(5); assertTrue('module "l" should be loaded', mm.isModuleLoaded('l')); assertFalse( 'module "m" should not be loaded (5)', mm.isModuleLoaded('m')); clock.tick(5); assertTrue('module "m" should be loaded', mm.isModuleLoaded('m')); } function testLoadingDepsInBatchMode() { var mm = getModuleManager({ 'e': [], 'f': [], 'g': ['f'], 'h': ['e','f','g']}); mm.setLoader(createSuccessfulBatchLoader(mm)); mm.setBatchModeEnabled(true); mm.preloadModule('f'); clock.tick(5); assertTrue('module "f" should be loaded', mm.isModuleLoaded('f')); assertFalse( 'module "e" should not be loaded (1)', mm.isModuleLoaded('e')); assertFalse( 'module "g" should not be loaded (1)', mm.isModuleLoaded('g')); assertFalse( 'module "h" should not be loaded (1)', mm.isModuleLoaded('h')); // When loading a module in batch mode, its not-yet-loaded dependencies // should be requested at the same time, and in dependency order. mm.preloadModule('h'); clock.tick(5); assertTrue('module "e" should be loaded', mm.isModuleLoaded('e')); assertFalse( 'module "g" should not be loaded (2)', mm.isModuleLoaded('g')); assertFalse( 'module "h" should not be loaded (2)', mm.isModuleLoaded('h')); clock.tick(2); assertTrue( 'module "g" should be loaded', mm.isModuleLoaded('g')); assertFalse( 'module "h" should not be loaded (3)', mm.isModuleLoaded('h')); clock.tick(2); assertTrue( 'module "h" should be loaded', mm.isModuleLoaded('h')); } /** * Test unauthorized errors while loading modules. */ function testUnauthorizedLoading() { var mm = getModuleManager({ 'm': [], 'n': [], 'o': ['n']}); mm.setLoader(createUnsuccessfulLoader(mm, 401)); // Callback checks for an unauthorized error var firedLoadFailed = false; mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR, function(callbackType, id, cause) { assertEquals('Failure cause was not as expected', goog.module.ModuleManager.FailureType.UNAUTHORIZED, cause); firedLoadFailed = true; }); mm.execOnLoad('o', function() {}); assertTrue('module "o" should be loading', mm.isModuleLoading('o')); assertTrue('module "n" should be loading', mm.isModuleLoading('n')); clock.tick(5); assertTrue( 'should have called unauthorized module callback', firedLoadFailed); assertFalse( 'module "o" should not be loaded', mm.isModuleLoaded('o')); assertFalse( 'module "o" should not be loading', mm.isModuleLoading('o')); assertFalse( 'module "n" should not be loaded', mm.isModuleLoaded('n')); assertFalse( 'module "n" should not be loading', mm.isModuleLoading('n')); } /** * Test error loading modules which are retried. */ function testErrorLoadingModule() { var mm = getModuleManager({ 'p': ['q'], 'q': [], 'r': ['q','p']}); mm.setLoader(createUnsuccessfulLoader(mm, 500)); mm.preloadModule('r'); clock.tick(4); // A module request is now underway using the unsuccessful loader. // We substitute a successful loader for future module load requests. mm.setLoader(createSuccessfulNonBatchLoader(mm)); clock.tick(1); assertFalse( 'module "q" should not be loaded (1)', mm.isModuleLoaded('q')); assertFalse( 'module "p" should not be loaded (1)', mm.isModuleLoaded('p')); assertFalse( 'module "r" should not be loaded (1)', mm.isModuleLoaded('r')); // Failed loads are automatically retried. clock.tick(5); assertTrue('module "q" should be loaded', mm.isModuleLoaded('q')); assertFalse( 'module "p" should not be loaded (2)', mm.isModuleLoaded('p')); assertFalse( 'module "r" should not be loaded (2)', mm.isModuleLoaded('r')); clock.tick(5); assertTrue('module "p" should be loaded', mm.isModuleLoaded('p')); assertFalse( 'module "r" should not be loaded (3)', mm.isModuleLoaded('r')); clock.tick(5); assertTrue( 'module "r" should be loaded', mm.isModuleLoaded('r')); } /** * Test consecutive errors in loading modules. */ function testConsecutiveErrors() { var mm = getModuleManager({'s': []}); mm.setLoader(createUnsuccessfulLoader(mm, 500)); // Register an error callback for consecutive failures. var firedLoadFailed = false; mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR, function(callbackType, id, cause) { assertEquals('Failure cause was not as expected', goog.module.ModuleManager.FailureType.CONSECUTIVE_FAILURES, cause); firedLoadFailed = true; }); mm.preloadModule('s'); assertFalse( 'module "s" should not be loaded (0)', mm.isModuleLoaded('s')); // Fail twice. for (var i = 0; i < 2; i++) { clock.tick(5); assertFalse( 'module "s" should not be loaded (1)', mm.isModuleLoaded('s')); assertFalse( 'should not fire failed callback (1)', firedLoadFailed); } // Fail a third time and check that the callback is fired. clock.tick(5); assertFalse( 'module "s" should not be loaded (2)', mm.isModuleLoaded('s')); assertTrue( 'should have fired failed callback', firedLoadFailed); // Check that it doesn't attempt to load the module anymore after it has // failed. var triedLoad = false; mm.setLoader({ loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn) { triedLoad = true; }}); // Also reset the failed callback flag and make sure it isn't called // again. firedLoadFailed = false; clock.tick(10); assertFalse( 'module "s" should not be loaded (3)', mm.isModuleLoaded('s')); assertFalse('No more loads should have been tried', triedLoad); assertFalse('The load failed callback should be fired only once', firedLoadFailed); } /** * Test loading errors due to old code. */ function testOldCodeGoneError() { var mm = getModuleManager({'s': []}); mm.setLoader(createUnsuccessfulLoader(mm, 410)); // Callback checks for an old code failure var firedLoadFailed = false; mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR, function(callbackType, id, cause) { assertEquals('Failure cause was not as expected', goog.module.ModuleManager.FailureType.OLD_CODE_GONE, cause); firedLoadFailed = true; }); mm.preloadModule('s', 0); assertFalse( 'module "s" should not be loaded (0)', mm.isModuleLoaded('s')); clock.tick(5); assertFalse( 'module "s" should not be loaded (1)', mm.isModuleLoaded('s')); assertTrue( 'should have called old code gone callback', firedLoadFailed); } /** * Test timeout. */ function testTimeout() { var mm = getModuleManager({'s': []}); mm.setLoader(createTimeoutLoader(mm)); // Callback checks for timeout var firedTimeout = false; mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR, function(callbackType, id, cause) { assertEquals('Failure cause was not as expected', goog.module.ModuleManager.FailureType.TIMEOUT, cause); firedTimeout = true; }); mm.preloadModule('s', 0); assertFalse( 'module "s" should not be loaded (0)', mm.isModuleLoaded('s')); clock.tick(5); assertFalse( 'module "s" should not be loaded (1)', mm.isModuleLoaded('s')); assertTrue( 'should have called timeout callback', firedTimeout); } /** * Make sure ModuleInfo objects in moduleInfoMap_ get disposed. */ function testDispose() { var mm = getModuleManager({'a': [], 'b': [], 'c': []}); var moduleInfoA = mm.getModuleInfo('a'); assertNotNull(moduleInfoA); var moduleInfoB = mm.getModuleInfo('b'); assertNotNull(moduleInfoB); var moduleInfoC = mm.getModuleInfo('c'); assertNotNull(moduleInfoC); mm.dispose(); assertTrue(moduleInfoA.isDisposed()); assertTrue(moduleInfoB.isDisposed()); assertTrue(moduleInfoC.isDisposed()); } function testDependencyOrderingWithSimpleDeps() { var mm = getModuleManager({ 'a': ['b', 'c'], 'b': ['d'], 'c': ['e', 'f'], 'd': [], 'e': [], 'f': [] }); var ids = mm.getNotYetLoadedTransitiveDepIds_('a'); assertDependencyOrder(ids, mm); assertArrayEquals(['d', 'e', 'f', 'b', 'c', 'a'], ids); } function testDependencyOrderingWithCommonDepsInDeps() { // Tests to make sure that if dependencies of the root are loaded before // their common dependencies. var mm = getModuleManager({ 'a': ['b', 'c'], 'b': ['d'], 'c': ['d'], 'd': [] }); var ids = mm.getNotYetLoadedTransitiveDepIds_('a'); assertDependencyOrder(ids, mm); assertArrayEquals(['d', 'b', 'c', 'a'], ids); } function testDependencyOrderingWithCommonDepsInRoot1() { // Tests the case where a dependency of the root depends on another // dependency of the root. Irregardless of ordering in the root's // deps. var mm = getModuleManager({ 'a': ['b', 'c'], 'b': ['c'], 'c': [] }); var ids = mm.getNotYetLoadedTransitiveDepIds_('a'); assertDependencyOrder(ids, mm); assertArrayEquals(['c', 'b', 'a'], ids); } function testDependencyOrderingWithCommonDepsInRoot2() { // Tests the case where a dependency of the root depends on another // dependency of the root. Irregardless of ordering in the root's // deps. var mm = getModuleManager({ 'a': ['b', 'c'], 'b': [], 'c': ['b'] }); var ids = mm.getNotYetLoadedTransitiveDepIds_('a'); assertDependencyOrder(ids, mm); assertArrayEquals(['b', 'c', 'a'], ids); } function testDependencyOrderingWithGmailExample() { // Real dependency graph taken from gmail. var mm = getModuleManager({ 's': ['dp', 'ml', 'md'], 'dp': ['a'], 'ml': ['ld', 'm'], 'ld': ['a'], 'm': ['ad', 'mh', 'n'], 'md': ['mh', 'ld'], 'a': [], 'mh': [], 'ad': [], 'n': [] }); mm.setLoaded('a'); mm.setLoaded('m'); mm.setLoaded('n'); mm.setLoaded('ad'); mm.setLoaded('mh'); var ids = mm.getNotYetLoadedTransitiveDepIds_('s'); assertDependencyOrder(ids, mm); assertArrayEquals(['ld', 'dp', 'ml', 'md', 's'], ids); } function assertDependencyOrder(list, mm) { var seen = {}; for (var i = 0; i < list.length; i++) { var id = list[i]; seen[id] = true; var deps = mm.getModuleInfo(id).getDependencies(); for (var j = 0; j < deps.length; j++) { var dep = deps[j]; assertTrue('Unresolved dependency [' + dep + '] for [' + id + '].', seen[dep] || mm.getModuleInfo(dep).isLoaded()); } } } function testRegisterInitializationCallback() { var initCalled = 0; var mm = getModuleManager({'a': [], 'b': [], 'c': []}); mm.setLoader(createSuccessfulNonBatchLoaderWithRegisterInitCallback(mm, function() { ++initCalled; })); execOnLoad_(mm); // execOnLoad_ loads modules a and c assertTrue(initCalled == 2); } function createSuccessfulNonBatchLoaderWithRegisterInitCallback( moduleMgr, fn) { return { loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn, opt_timeoutFn) { moduleMgr.beforeLoadModuleCode(ids[0]); moduleMgr.registerInitializationCallback(fn); setTimeout(function() { moduleMgr.setLoaded(ids[0]); moduleMgr.afterLoadModuleCode(ids[0]); if (opt_successFn) { opt_successFn(); } }, 5); }}; } function testSetModuleConstructor() { var initCalled = 0; var mm = getModuleManager({'a': [], 'b': [], 'c': []}); var info = { 'a': { ctor: AModule, count: 0 }, 'b': { ctor: BModule, count: 0 }, 'c': { ctor: CModule, count: 0 } }; function AModule() { ++info['a'].count; goog.module.BaseModule.call(this); } goog.inherits(AModule, goog.module.BaseModule); function BModule() { ++info['b'].count; goog.module.BaseModule.call(this); } goog.inherits(BModule, goog.module.BaseModule); function CModule() { ++info['c'].count; goog.module.BaseModule.call(this); } goog.inherits(CModule, goog.module.BaseModule); mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor(mm, info)); execOnLoad_(mm); assertTrue(info['a'].count == 1); assertTrue(info['b'].count == 0); assertTrue(info['c'].count == 1); assertTrue(mm.getModuleInfo('a').getModule() instanceof AModule); assertTrue(mm.getModuleInfo('c').getModule() instanceof CModule); } /** * Tests that a call to load the loading module during module initialization * doesn't trigger a second load. */ function testLoadWhenInitializing() { var mm = getModuleManager({'a': []}); mm.setLoader(createSuccessfulNonBatchLoader(mm)); var info = { 'a': { ctor: AModule, count: 0 } }; function AModule() { ++info['a'].count; goog.module.BaseModule.call(this); } goog.inherits(AModule, goog.module.BaseModule); AModule.prototype.initialize = function() { mm.load('a'); }; mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor(mm, info)); mm.preloadModule('a'); clock.tick(5); assertEquals(info['a'].count, 1); } function testErrorInEarlyCallback() { var errback = goog.testing.recordFunction(); var callback = goog.testing.recordFunction(); var mm = getModuleManager({'a': [], 'b': ['a']}); mm.getModuleInfo('a').registerEarlyCallback(goog.functions.error('error')); mm.getModuleInfo('a').registerCallback(callback); mm.getModuleInfo('a').registerErrback(errback); mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor( mm, createModulesFor('a', 'b'))); mm.preloadModule('b'); clock.tick(5); assertEquals(1, callback.getCallCount()); assertEquals(1, errback.getCallCount()); assertEquals(goog.module.ModuleManager.FailureType.INIT_ERROR, errback.getLastCall().getArguments()[0]); assertTrue(mm.getModuleInfo('a').isLoaded()); assertFalse(mm.getModuleInfo('b').isLoaded()); clock.tick(5); assertTrue(mm.getModuleInfo('b').isLoaded()); } function testErrorInNormalCallback() { var earlyCallback = goog.testing.recordFunction(); var errback = goog.testing.recordFunction(); var mm = getModuleManager({'a': [], 'b': ['a']}); mm.getModuleInfo('a').registerEarlyCallback(earlyCallback); mm.getModuleInfo('a').registerEarlyCallback(goog.functions.error('error')); mm.getModuleInfo('a').registerErrback(errback); mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor( mm, createModulesFor('a', 'b'))); mm.preloadModule('b'); clock.tick(10); assertEquals(1, errback.getCallCount()); assertEquals(goog.module.ModuleManager.FailureType.INIT_ERROR, errback.getLastCall().getArguments()[0]); assertTrue(mm.getModuleInfo('a').isLoaded()); assertTrue(mm.getModuleInfo('b').isLoaded()); } function testErrorInErrback() { var mm = getModuleManager({'a': [], 'b': ['a']}); mm.getModuleInfo('a').registerCallback(goog.functions.error('error1')); mm.getModuleInfo('a').registerErrback(goog.functions.error('error2')); mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor( mm, createModulesFor('a', 'b'))); mm.preloadModule('a'); try { clock.tick(10); } catch (e) { assertContains('Module errback failure', e.message); if (!goog.userAgent.IE) { assertContains('error2', e.message); } } assertTrue(mm.getModuleInfo('a').isLoaded()); } function createModulesFor(var_args) { var result = {}; for (var i = 0; i < arguments.length; i++) { var key = arguments[i]; result[key] = {ctor: goog.module.BaseModule}; } return result; } function createSuccessfulNonBatchLoaderWithConstructor(moduleMgr, info) { return { loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn, opt_timeoutFn) { setTimeout(function() { moduleMgr.beforeLoadModuleCode(ids[0]); moduleMgr.setModuleConstructor(info[ids[0]].ctor); moduleMgr.setLoaded(ids[0]); moduleMgr.afterLoadModuleCode(ids[0]); if (opt_successFn) { opt_successFn(); } }, 5); }}; } function testInitCallbackInBaseModule() { var mm = new goog.module.ModuleManager(); var called = false; var context; mm.registerInitializationCallback(function(mcontext) { called = true; context = mcontext; }); mm.setAllModuleInfo({'a': [], 'b': ['a']}); assertTrue('Base initialization not called', called); assertNull('Context should still be null', context); var mm = new goog.module.ModuleManager(); called = false; mm.registerInitializationCallback(function(mcontext) { called = true; context = mcontext; }); var appContext = {}; mm.setModuleContext(appContext); assertTrue('Base initialization not called after setModuleContext', called); assertEquals('Did not receive module context', appContext, context); } </script> </body> </html>