SIGN IN SIGN UP
angular / angular.js UNCLAIMED

AngularJS - HTML enhanced for web apps!

58864 0 0 JavaScript
2012-01-06 18:10:47 -08:00
'use strict';
describe('module loader', function() {
var window;
beforeEach(function() {
2012-01-06 18:10:47 -08:00
window = {};
setupModuleLoader(window);
});
it('should set up namespace', function() {
expect(window.angular).toBeDefined();
expect(window.angular.module).toBeDefined();
});
it('should not override existing namespace', function() {
var angular = window.angular;
var module = angular.module;
setupModuleLoader(window);
expect(window.angular).toBe(angular);
expect(window.angular.module).toBe(module);
});
it('should record calls', function() {
var otherModule = window.angular.module('other', []);
2012-01-13 14:19:10 -08:00
otherModule.config('otherInit');
2012-01-06 18:10:47 -08:00
2012-01-13 14:19:10 -08:00
var myModule = window.angular.module('my', ['other'], 'config');
2012-01-06 18:10:47 -08:00
2012-01-13 14:19:10 -08:00
expect(myModule.
decorator('dk', 'dv').
provider('sk', 'sv').
2012-01-06 18:10:47 -08:00
factory('fk', 'fv').
service('a', 'aa').
2012-01-06 18:10:47 -08:00
value('k', 'v').
filter('f', 'ff').
directive('d', 'dd').
component('c', 'cc').
controller('ctrl', 'ccc').
2012-01-13 14:19:10 -08:00
config('init2').
2012-02-22 13:28:42 -08:00
constant('abc', 123).
2012-01-13 14:19:10 -08:00
run('runBlock')).toBe(myModule);
2012-01-06 18:10:47 -08:00
expect(myModule.requires).toEqual(['other']);
2012-01-13 14:19:10 -08:00
expect(myModule._invokeQueue).toEqual([
['$provide', 'constant', jasmine.objectContaining(['abc', 123])],
['$provide', 'provider', jasmine.objectContaining(['sk', 'sv'])],
['$provide', 'factory', jasmine.objectContaining(['fk', 'fv'])],
['$provide', 'service', jasmine.objectContaining(['a', 'aa'])],
['$provide', 'value', jasmine.objectContaining(['k', 'v'])],
['$filterProvider', 'register', jasmine.objectContaining(['f', 'ff'])],
['$compileProvider', 'directive', jasmine.objectContaining(['d', 'dd'])],
['$compileProvider', 'component', jasmine.objectContaining(['c', 'cc'])],
['$controllerProvider', 'register', jasmine.objectContaining(['ctrl', 'ccc'])]
]);
expect(myModule._configBlocks).toEqual([
['$injector', 'invoke', jasmine.objectContaining(['config'])],
fix(loader): module.decorator order of operations is now irrelevant `module.decorator` is now processed via the configBlocks order of operations and: 1. no longer throws error if declared before the provider being decorated. 2. guarantees the correct provider will be decorated when multiple, same-name providers are defined. (1) Prior to this fix, declaring `module.decorator` before the provider that it decorates results in throwing an error: ```js angular .module('theApp', []) .decorator('theFactory', moduleDecoratorFn) .factory('theFactory', theFactoryFn); // Error: [$injector:modulerr] Failed to instantiate module theApp due to: // Error: [$injector:unpr] Unknown provider: theFactoryProvider ``` The result of this fix now allows for the declaration order above. (2) Prior to this fix, declaring `module.decorator` before the final, same-named provider results in that provider **not** being decorated as expected: **NOTE:** Angular does not use provider name spacing, so the final declared provider is selected if multiple, same-named providers are declared. ```js angular .module('theApp', []) .factory('theFactory', theFactoryFn) .decorator('theFactory', moduleDecoratorFn) .factory('theFactory', theOtherFactoryFn); ``` `theOtherFactoryFn` is selected as 'theFactory' provider, but prior to this fix it is **not** decorated via `moduleDecoratorFn`. This fix ensures that `theOtherFactoryFn` will be decorated as expected when using the declaration order above. Closes #12382 Closes #14348 BREAKING CHANGE: `module.decorator` declarations are now processed as part of the `module.config` queue and may result in providers being decorated in a different order if `module.config` blocks are also used to decorate providers via `$provide.decorator`. For example, consider the following declaration order in which 'theFactory' is decorated by both a `module.decorator` and a `$provide.decorator`: ```js angular .module('theApp', []) .factory('theFactory', theFactoryFn) .config(function($provide) { $provide.decorator('theFactory', provideDecoratorFn); }) .decorator('theFactory', moduleDecoratorFn); ``` Prior to this fix, 'theFactory' provider would be decorated in the following order: 1. moduleDecoratorFn 2. provideDecoratorFn The result of this fix changes the order in which 'theFactory' is decorated because now `module.decorator` declarations are processed in the same order as `module.config` declarations: 1. provideDecoratorFn 2. moduleDecoratorFn
2016-03-30 17:30:42 -04:00
['$provide', 'decorator', jasmine.objectContaining(['dk', 'dv'])],
['$injector', 'invoke', jasmine.objectContaining(['init2'])]
2012-01-06 18:10:47 -08:00
]);
2012-01-13 14:19:10 -08:00
expect(myModule._runBlocks).toEqual(['runBlock']);
2012-01-06 18:10:47 -08:00
});
it('should not throw error when `module.decorator` is declared before provider that it decorates', function() {
fix(loader): module.decorator order of operations is now irrelevant `module.decorator` is now processed via the configBlocks order of operations and: 1. no longer throws error if declared before the provider being decorated. 2. guarantees the correct provider will be decorated when multiple, same-name providers are defined. (1) Prior to this fix, declaring `module.decorator` before the provider that it decorates results in throwing an error: ```js angular .module('theApp', []) .decorator('theFactory', moduleDecoratorFn) .factory('theFactory', theFactoryFn); // Error: [$injector:modulerr] Failed to instantiate module theApp due to: // Error: [$injector:unpr] Unknown provider: theFactoryProvider ``` The result of this fix now allows for the declaration order above. (2) Prior to this fix, declaring `module.decorator` before the final, same-named provider results in that provider **not** being decorated as expected: **NOTE:** Angular does not use provider name spacing, so the final declared provider is selected if multiple, same-named providers are declared. ```js angular .module('theApp', []) .factory('theFactory', theFactoryFn) .decorator('theFactory', moduleDecoratorFn) .factory('theFactory', theOtherFactoryFn); ``` `theOtherFactoryFn` is selected as 'theFactory' provider, but prior to this fix it is **not** decorated via `moduleDecoratorFn`. This fix ensures that `theOtherFactoryFn` will be decorated as expected when using the declaration order above. Closes #12382 Closes #14348 BREAKING CHANGE: `module.decorator` declarations are now processed as part of the `module.config` queue and may result in providers being decorated in a different order if `module.config` blocks are also used to decorate providers via `$provide.decorator`. For example, consider the following declaration order in which 'theFactory' is decorated by both a `module.decorator` and a `$provide.decorator`: ```js angular .module('theApp', []) .factory('theFactory', theFactoryFn) .config(function($provide) { $provide.decorator('theFactory', provideDecoratorFn); }) .decorator('theFactory', moduleDecoratorFn); ``` Prior to this fix, 'theFactory' provider would be decorated in the following order: 1. moduleDecoratorFn 2. provideDecoratorFn The result of this fix changes the order in which 'theFactory' is decorated because now `module.decorator` declarations are processed in the same order as `module.config` declarations: 1. provideDecoratorFn 2. moduleDecoratorFn
2016-03-30 17:30:42 -04:00
angular.module('theModule', []).
decorator('theProvider', function($delegate) { return $delegate; }).
factory('theProvider', function() { return {}; });
expect(function() {
createInjector(['theModule']);
}).not.toThrow();
});
it('should run decorators in order of declaration, even when mixed with provider.decorator', function() {
var log = '';
angular.module('theModule', [])
.factory('theProvider', function() {
return {api: 'provider'};
})
.decorator('theProvider', function($delegate) {
$delegate.api = $delegate.api + '-first';
return $delegate;
})
.config(function($provide) {
$provide.decorator('theProvider', function($delegate) {
$delegate.api = $delegate.api + '-second';
return $delegate;
});
})
.decorator('theProvider', function($delegate) {
$delegate.api = $delegate.api + '-third';
return $delegate;
})
.run(function(theProvider) {
log = theProvider.api;
2016-05-24 18:12:12 +02:00
});
createInjector(['theModule']);
expect(log).toBe('provider-first-second-third');
});
it('should decorate the last declared provider if multiple have been declared', function() {
var log = '';
angular.module('theModule', []).
factory('theProvider', function() {
return {
api: 'firstProvider'
};
}).
decorator('theProvider', function($delegate) {
$delegate.api = $delegate.api + '-decorator';
return $delegate;
}).
factory('theProvider', function() {
return {
api: 'secondProvider'
};
}).
run(function(theProvider) {
log = theProvider.api;
});
createInjector(['theModule']);
2016-05-24 18:12:12 +02:00
expect(log).toBe('secondProvider-decorator');
});
2012-01-06 18:10:47 -08:00
it('should allow module redefinition', function() {
expect(window.angular.module('a', [])).not.toBe(window.angular.module('a', []));
});
it('should complain of no module', function() {
expect(function() {
window.angular.module('dontExist');
}).toThrowMinErr('$injector', 'nomod', 'Module \'dontExist\' is not available! You either misspelled the module name ' +
'or forgot to load it. If registering a module ensure that you specify the dependencies as the second ' +
'argument.');
2012-01-06 18:10:47 -08:00
});
it('should complain if a module is called "hasOwnProperty', function() {
expect(function() {
window.angular.module('hasOwnProperty', []);
}).toThrowMinErr('ng','badname', 'hasOwnProperty is not a valid module name');
});
it('should expose `$$minErr` on the `angular` object', function() {
expect(window.angular.$$minErr).toEqual(jasmine.any(Function));
});
describe('Module', function() {
describe('info()', function() {
var theModule;
beforeEach(function() {
theModule = angular.module('theModule', []);
});
it('should default to an empty object', function() {
expect(theModule.info()).toEqual({});
});
it('should store the object passed as a param', function() {
theModule.info({ version: '1.2' });
expect(theModule.info()).toEqual({ version: '1.2' });
});
it('should throw if the parameter is not an object', function() {
expect(function() {
theModule.info('some text');
}).toThrowMinErr('ng', 'aobj');
});
it('should completely replace the previous info object', function() {
theModule.info({ value: 'X' });
theModule.info({ newValue: 'Y' });
expect(theModule.info()).toEqual({ newValue: 'Y' });
});
});
});
2012-01-06 18:10:47 -08:00
});